For this task you will build a classifier for Rock-Paper-Scissors
based on the rps dataset.
IMPORTANT: Your final layer should be as shown, do not change the
provided code, or the tests may fail
IMPORTANT: Images will be tested as 150x150 with 3 bytes of color depth
So ensure that your input layer is designed accordingly, or the tests
may fail.
NOTE THAT THIS IS UNLABELLED DATA.
You can use the ImageDataGenerator to automatically label it
and we have provided some starter code.
์ด ์์ ์์๋ Rock-Paper-Scissors์ ๋ํ ๋ถ๋ฅ๊ธฐ๋ฅผ ์์ฑํฉ๋๋ค.
rps ๋ฐ์ดํฐ ์ ์ ๊ธฐ๋ฐ์ผ๋กํฉ๋๋ค.
์ค์ : ์ต์ข ๋ ์ด์ด๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์์ผํฉ๋๋ค.
์ค์ : ์ด๋ฏธ์ง๋ 3 ๋ฐ์ดํธ 150x150์ ์ปฌ๋ฌ์ฌ์ง์ผ๋ก ํ ์คํธ๋ฉ๋๋ค.
๋ฐ๋ผ์ ์ ๋ ฅ ๋ ์ด์ด๊ฐ ๊ทธ์ ๋ฐ๋ผ ์ค๊ณ๋์๊ฑฐ๋ ํ ์คํธ๋์๋์ง ํ์ธํ์ญ์์ค.
ImageDataGenerator๋ฅผ ์ฌ์ฉํ์ฌ ์๋์ผ๋ก ๋ ์ด๋ธ์ ์ง์ ํ ์ ์์ต๋๋ค.
ํ์ํ ๋ชจ๋์ import ํฉ๋๋ค.
import urllib.request
import zipfile
import numpy as np
from IPython.display import Image
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dropout, Dense
from tensorflow.keras.models import Sequential
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import ModelCheckpoint
tensorflow-datasets๋ฅผ ํ์ฉํฉ๋๋ค.
๊ฐ์๋ฐ์๋ณด์ ๋ํ ์์ ์ฌ์ง์ ๊ฐ์ง๊ณ ๊ฐ์
์ธ์ง, ๋ฐ์
์ธ์ง, ๋ณด์๊ธฐ
์ธ์ง ๋ถ๋ฅํ๋ classification
๋ฌธ์ ์
๋๋ค.
url = 'https://storage.googleapis.com/download.tensorflow.org/data/rps.zip'
urllib.request.urlretrieve(url, 'rps.zip')
local_zip = 'rps.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('tmp/')
zip_ref.close()
๋ฐ์ดํฐ์ ์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํด ์ฃผ์ธ์ (root ํด๋์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ์ฌ์ผ ํฉ๋๋ค.)
# training dir
TRAINING_DIR = "tmp/rps/"
rescale
: ์ด๋ฏธ์ง์ ํฝ์
๊ฐ์ ์กฐ์ rotation_range
: ์ด๋ฏธ์ง ํ์ width_shift_range
: ๊ฐ๋ก ๋ฐฉํฅ์ผ๋ก ์ด๋height_shift_range
: ์ธ๋ก ๋ฐฉํฅ์ผ๋ก ์ด๋shear_range
: ์ด๋ฏธ์ง ๊ตด์ zoom_range
: ์ด๋ฏธ์ง ํ๋horizontal_flip
: ํก ๋ฐฉํฅ์ผ๋ก ์ด๋ฏธ์ง ๋ฐ์ fill_mode
: ์ด๋ฏธ์ง๋ฅผ ์ด๋์ด๋ ๊ตด์ ์์ผฐ์ ๋ ๋น ํฝ์
๊ฐ์ ๋ํ์ฌ ๊ฐ์ ์ฑ์ฐ๋ ๋ฐฉ์validation_split
: validation set์ ๊ตฌ์ฑ ๋น์จtraining_datagen = ImageDataGenerator(
rescale=1. / 255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest',
validation_split=0.2
)
ImageDataGenerator๋ฅผ ์ ๋ง๋ค์ด ์ฃผ์๋ค๋ฉด, flow_from_directory
๋ก ์ด๋ฏธ์ง๋ฅผ ์ด๋ป๊ฒ ๊ณต๊ธํด ์ค ๊ฒ์ธ๊ฐ๋ฅผ ์ง์ ํด ์ฃผ์ด์ผํฉ๋๋ค.
batch_size
๋ฅผ ์ ์ํฉ๋๋ค. (32)target_size
๋ฅผ ์ ์ํฉ๋๋ค. (150 x 150). ์ด๋ฏธ์ง๋ฅผ ์์์ ํ๊ฒ ์ฌ์ด์ฆ ๋งํผ ์๋ผ๋ด์ด ๊ณต๊ธํฉ๋๋ค.class_mode
๋ ์ถ๋ ฅ์ธต์ activation์ด softmax
์ธ ๊ฒฝ์ฐ 'categorical', sigmoid
์ธ ๊ฒฝ์ฐ 'binary'๋ฅผ ์ง์ ํฉ๋๋ค.subset
์ ์ง์ ํฉ๋๋ค. (training / validation)training_generator์ ๋ํ from_from_directory
๋ฅผ ์ ์ํฉ๋๋ค.
training_generator = training_datagen.flow_from_directory(TRAINING_DIR,
batch_size=32,
target_size=(150, 150),
class_mode='categorical',
subset='training',
)
validation_generator์ ๋ํ from_from_directory
๋ฅผ ์ ์ํฉ๋๋ค.
validation_generator = training_datagen.flow_from_directory(TRAINING_DIR,
batch_size=32,
target_size=(150, 150),
class_mode='categorical',
subset='validation',
)
504 ๊ฐ์ ์ด๋ฏธ์ง๊ฐ ์ถ๋ ฅ๋์ด์ผ ํฉ๋๋ค.
import matplotlib.pyplot as plt
class_map = {
0: 'Paper',
1: 'Rock',
2: 'Scissors'
}
print('์ค๋ฆฌ์ง๋ ์ฌ์ง ํ์ผ')
original_datagen = ImageDataGenerator(rescale=1./255)
original_generator = original_datagen.flow_from_directory(TRAINING_DIR,
batch_size=128,
target_size=(150, 150),
class_mode='categorical'
)
for x, y in original_generator:
print(x.shape, y.shape)
print(y[0])
fig, axes = plt.subplots(2, 5)
fig.set_size_inches(15, 6)
for i in range(10):
axes[i//5, i%5].imshow(x[i])
axes[i//5, i%5].set_title(class_map[y[i].argmax()], fontsize=15)
axes[i//5, i%5].axis('off')
plt.show()
break
print('Augmentation ์ ์ฉํ ์ฌ์ง ํ์ผ')
for x, y in training_generator:
print(x.shape, y.shape)
print(y[0])
fig, axes = plt.subplots(2, 5)
fig.set_size_inches(15, 6)
for i in range(10):
axes[i//5, i%5].imshow(x[i])
axes[i//5, i%5].set_title(class_map[y[i].argmax()], fontsize=15)
axes[i//5, i%5].axis('off')
plt.show()
break
CNN - activation - Pooling ๊ณผ์ ์ ํตํด ์ด๋ฏธ์ง ๋ถ๋ถ ๋ถ๋ถ์ ์ฃผ์ํ Feature ๋ค์ ์ถ์ถํด ๋ ๋๋ค.
CNN์ ํตํด ์ฐ๋ฆฌ๋ ๋ค์ํ 1๊ฐ์ ์ด๋ฏธ์ง๋ฅผ filter
๋ฅผ ๊ฑฐ์น ๋ค์์ ์ด๋ฏธ์ง๋ก ์ถ๋ ฅํฉ๋๋ค.
filter
์ ์ฌ์ด์ฆ๋ 3 X 3 ํํฐ๋ฅผ ์์ฃผ ์ฌ์ฉํฉ๋๋ค
๋ํ, 3 X 3 ํํฐ๋ฅผ ๊ฑฐ์น ์ด๋ฏธ์ง์ ์ฌ์ด์ฆ๋ 2px ๋งํผ ์ฌ์ด์ฆ๊ฐ ์ค์ด๋ญ๋๋ค.
์ด์ Modeling์ ํ ์ฐจ๋ก์ ๋๋ค.
model = Sequential([
# Conv2D, MaxPooling2D ์กฐํฉ์ผ๋ก ์ธต์ ์์ต๋๋ค. ์ฒซ๋ฒ์งธ ์
๋ ฅ์ธต์ input_shape์ (150, 150, 3)์ผ๋ก ์ง์ ํฉ๋๋ค.
Conv2D(64, (3, 3), activation='relu', input_shape=(150, 150, 3)),
MaxPooling2D(2, 2),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
Conv2D(128, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
Conv2D(128, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
# 2D -> 1D๋ก ๋ณํ์ ์ํ์ฌ Flatten ํฉ๋๋ค.
Flatten(),
# ๊ณผ์ ํฉ ๋ฐฉ์ง๋ฅผ ์ํ์ฌ Dropout์ ์ ์ฉํฉ๋๋ค.
Dropout(0.5),
Dense(512, activation='relu'),
# Classification์ ์ํ Softmax
# ์ถ๋ ฅ์ธต์ ๊ฐฏ์๋ ํด๋์ค์ ๊ฐฏ์์ ๋์ผํ๊ฒ ๋ง์ถฐ์ค๋๋ค (3๊ฐ), activation๋ ์์ง๋ง์ธ์!
Dense(3, activation='softmax'),
])
model.summary()
optimizer
๋ ๊ฐ์ฅ ์ต์ ํ๊ฐ ์๋๋ ์๊ณ ๋ฆฌ์ฆ์ธ 'adam'์ ์ฌ์ฉํฉ๋๋ค.loss
์ค์ sigmoid
์ธ ๊ฒฝ์ฐ: binary_crossentropy
softmax
์ธ ๊ฒฝ์ฐ: categorical_crossentropy
sparse_categorical_crossentropy
)ImageDataGenerator
๋ ์๋์ผ๋ก Label์ ์ํซ์ธ์ฝ๋ฉ(one-hot encoding) ํด์ค๋๋ค.metrics
๋ฅผ 'acc' ํน์ 'accuracy'๋ก ์ง์ ํ๋ฉด, ํ์ต์ ์ ํ๋๋ฅผ ๋ชจ๋ํฐ๋ง ํ ์ ์์ต๋๋ค.model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
val_loss
๊ธฐ์ค์ผ๋ก epoch ๋ง๋ค ์ต์ ์ ๋ชจ๋ธ์ ์ ์ฅํ๊ธฐ ์ํ์ฌ, ModelCheckpoint๋ฅผ ๋ง๋ญ๋๋ค.
checkpoint_path
๋ ๋ชจ๋ธ์ด ์ ์ฅ๋ ํ์ผ ๋ช
์ ์ค์ ํฉ๋๋ค.ModelCheckpoint
์ ์ ์ธํ๊ณ , ์ ์ ํ ์ต์
๊ฐ์ ์ง์ ํฉ๋๋ค.checkpoint_path = "tmp_checkpoint.ckpt"
checkpoint = ModelCheckpoint(filepath=checkpoint_path,
save_weights_only=True,
save_best_only=True,
monitor='val_loss',
verbose=1)
epochs=25
history = model.fit(train_data,
validation_data=(valid_data),
epochs=20,
callbacks=[checkpoint],
)
ํ์ต์ด ์๋ฃ๋ ํ์๋ ๋ฐ๋์ load_weights
๋ฅผ ํด์ฃผ์ด์ผ ํฉ๋๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด, ์ด์ฌํ ModelCheckpoint๋ฅผ ๋ง๋ ์๋ฏธ๊ฐ ์์ต๋๋ค.
# checkpoint ๋ฅผ ์ ์ฅํ ํ์ผ๋ช
์ ์
๋ ฅํฉ๋๋ค.
model.load_weights(checkpoint_path)
plt.figure(figsize=(12, 9))
plt.plot(np.arange(1, epochs+1), history.history['acc'])
plt.plot(np.arange(1, epochs+1), history.history['loss'])
plt.title('Acc / Loss', fontsize=20)
plt.xlabel('Epochs')
plt.ylabel('Acc / Loss')
plt.legend(['acc', 'loss'], fontsize=15)
plt.show()
model.evaluate(x_valid, y_valid)