8-1에서 배운 내용을 토대로 패션 MNIST 구현해보자.
from tensorflow import keras
from sklearn.model_selection import train_test_split
(train_input, train_target), (test_input, test_target) =\
keras.datasets.fashion_mnist.load_data()
train_scaled = train_input.reshape(-1, 28, 28, 1) / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(
train_scaled, train_target, test_size=0.2, random_state=42 )
reshape.(-1,28,28,1) -> 4차원 배열로
이제 합성곱 신경망을 만들어보자..!
합성곱 신경망 만들기
model = keras.Sequential()
model.add(keras.layers.Conv2D(32, kernel_size=3, activation='relu',
padding = 'same', input_shape=(28,28,1)))
매개변수 설명 : 필터 32개를 사용
커널의 크기는 3x3
활성화 함수 : 렐루 함수
세임패딩 사용
입력의 차원 28,28,1
풀링 층 추가 ( 차원 축소시키는것 )
model.add(keras.MaxPooling2D(2))
최대 풀링 = MaxPooling
평균 풀링 = AveragePooling
위 코드에서는 최대값 풀링을 사용했고, (2,2)로 설정했다. ---> 가로세로가 같으면 숫자 하나만 써도 가능
패션 MNIST 이미지 => 28x28크기에 세임 패딩 -> 출력된 특성 맵 또한 28x28 -> 2,2 풀링했으므로 특성맵 크기 절반으로 됨. 특성 맵의 깊이 32가 됨, 따라서 최대 풀링을 통과한 특성 맵의 크기는 (14,14,32)가 될 것.
첫 번째 CNN풀링층 다음에 두 번째 CNN 풀링 층을 추가해보자.
model.add(keras.layers.Conv2D(64, kernel_size=3, activation = 'relu',
padding = 'same'))
model.add(keras.layers.MaxPooling2D(2))
처음과 동일 (필터개수 64개 만 바뀌었다.)
최종 출력되는 특성 맵은 (7,7,64)가 될 것이다.
이제 이 특성맵을 일렬로 펼쳐보자.
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(100, activation = 'relu'))
model.add(keras.layers.Dropout(0.4))
model.add(keras.layers.Dense(10, activation = 'softmax'))
은닉층과 출력층 사이에 드롭아웃을 넣었다.
이제 summary() 해보자.
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 28, 28, 32) 320
max_pooling2d (MaxPooling2D (None, 14, 14, 32) 0
)
conv2d_1 (Conv2D) (None, 14, 14, 64) 18496
max_pooling2d_1 (MaxPooling (None, 7, 7, 64) 0
2D)
flatten (Flatten) (None, 3136) 0
dense (Dense) (None, 100) 313700
dropout (Dropout) (None, 100) 0
dense_1 (Dense) (None, 10) 1010
=================================================================
Total params: 333,526
Trainable params: 333,526
Non-trainable params: 0
_________________________________________________________________
출력된 것을 보고 각 층을 통과하면서 특성맵의 깊이가 32, 64로 각각 변하는것을 볼 수 있다.
모델 컴파일과 훈련
model checkpont 콜백, early stopping 콜백을 같이 사용
model.compile(optimizer = 'adam', loss='sparse_categorical_crossentropy',metrics='accuracy')
checkpoint_cb = keras.callbacks.ModelCheckpoint('best-cnn-model.h5',
save_best_only=True)
early_stopping_cb = keras.callbacks.EarlyStopping(patience = 2,
restore_best_weights=True)
early_stopping_cb = keras.callbacks.EarlyStopping(patience = 2,
restore_best_weights=True)
history = model.fit(train_scaled, train_target, epochs = 20,
validation_data=(val_scaled, val_target),
callbacks=[checkpoint_cb, early_stopping_cb])
실행
Epoch 1/20
1500/1500 [==============================] - 27s 17ms/step - loss: 0.5075 - accuracy: 0.8179 - val_loss: 0.3253 - val_accuracy: 0.8817
Epoch 2/20
1500/1500 [==============================] - 25s 17ms/step - loss: 0.3334 - accuracy: 0.8809 - val_loss: 0.2711 - val_accuracy: 0.9009
Epoch 3/20
1500/1500 [==============================] - 24s 16ms/step - loss: 0.2825 - accuracy: 0.8971 - val_loss: 0.2612 - val_accuracy: 0.9053
Epoch 4/20
1500/1500 [==============================] - 23s 16ms/step - loss: 0.2540 - accuracy: 0.9085 - val_loss: 0.2359 - val_accuracy: 0.9146
Epoch 5/20
1500/1500 [==============================] - 25s 17ms/step - loss: 0.2302 - accuracy: 0.9148 - val_loss: 0.2358 - val_accuracy: 0.9121
Epoch 6/20
1500/1500 [==============================] - 26s 18ms/step - loss: 0.2109 - accuracy: 0.9232 - val_loss: 0.2291 - val_accuracy: 0.9134
Epoch 7/20
1500/1500 [==============================] - 30s 20ms/step - loss: 0.1924 - accuracy: 0.9289 - val_loss: 0.2284 - val_accuracy: 0.9178
Epoch 8/20
1500/1500 [==============================] - 26s 17ms/step - loss: 0.1774 - accuracy: 0.9330 - val_loss: 0.2292 - val_accuracy: 0.9195
Epoch 9/20
1500/1500 [==============================] - 28s 19ms/step - loss: 0.1652 - accuracy: 0.9387 - val_loss: 0.2363 - val_accuracy: 0.9193
에포크 절반도 안되어서 조기종료가 되었다.
손실그래프를 그려보자.
import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
최적 = 7~8번째 에포크 같다
EarlyStopping클래스에서 restore_best_weights 매개변수를 True로 지정해서
현재 model 객체가 최적의 모델 파라미터로 복원되어 있다.
즉 ModelCheckpoint 콜백이 저장한 best-cnn-model.h5파일을 다시 읽을 필요 X
이제 세트에 대한 성능을 평가해보자.
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 2s 5ms/step - loss: 0.2284 - accuracy: 0.9178
[0.22835350036621094, 0.9178333282470703]
fit()의 결과 중 에포크 7번째 때와 결과값이 같다.!! --> 7번째가 최적의 에포크
첫 번째 샘플 이미지를 확인해보자.!!
핸드백인것을 볼 수 있다.
predict() 메소드를 이용해서 10개의 클래스에 대한 예측을 해보자.
preds = model.predict(val_scaled[0:1])
print(preds)
1/1 [==============================] - 0s 75ms/step
[[1.8688267e-19 4.8781057e-26 4.4762546e-23 1.3098311e-21 1.7252202e-19
4.3341434e-19 1.1465990e-20 3.6049053e-22 1.0000000e+00 2.2943934e-20]]
결과를 보면 아홉번 째가 1이고 나머지는 0에 가까운 숫자들뿐이다.
시각화를 해보면 더 직관적일 것이다.
이제 리스트로 정리해보자
classes= ['티셔츠','바지','스웨터','드레스','코트','샌달','셔츠','스니커즈','가방','앵클 부츠']
import numpy as np
print(classes[np.argmax(preds)])
가방