21강 - 합성곱 신경망을 사용한 이미지 분류

2021. 7. 8. 00:49ICT 멘토링/혼자 공부하는 머신러닝+딥러닝

21강 - 합성곱 신경망을 사용한 이미지 분류

학습 로드맵

패션 MNIST 데이터

(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)

이전과 다르게 합성곱 신경망을 사용하여 이미지 그대로 사용함.

28*28 -> 28*28*1의 3차원 배열

차원이 1 추가되어도 배열의 원소의 개수는 변함 없음.

배치 차원까지 고려하면 4차원이 될 것.

첫 번째 합성곱 층

model = keras.Sequential()

model.add(keras.layers.Conv2D(32, kernel_size=3, activation='relu', 
                              padding='same', input_shape=(28,28,1)))
                              
model.add(keras.layers.MaxPooling2D(2))

32개의 필터 사용.

필터 크기: 3 - 너비, 높이 모두 동일.

여기에 depth 차원은 없음.

입력 데이터의 채널과 동일하게 채널 차원 따로 구성됨.

활성함수 = 'relu'

padding='same'

input_shape=(28,28,1) 지정 해줌으로 나중에 따로 build 메소드 안 호출해도 괜찮음.

배치차원은 지정하지 않고 첫 번째 층 크기 지정.

Conv2D 결과는 28*28*32

 

풀링레이어 보통 MaxPooling이 많은 사람들에 의해 선호되어짐!

풀링 후 결과는 14*14*32

두 번째 합성곱 층 + 완전 연결 층

64개의 필터, 커널 사이즈 3*3, depth는 입력과 동일한 32, 활성함수, padding 그대로 사용.

14*14*32 -> 14*14*64

14*14*64 -> 7*7*64

분류를 위해서는 dense 층을 둬서 확률값을 구해야 하므로 dense 층으로 만들어 줌.

Flatten 층에서 1차원 배열로 펼침.

dense에서 100개 뉴런이 은닉층이 만들어짐.

첫 번째 dense층의 파라미터가 2번째에 비해 너무 많기 때문에 과대적합 가능.

과대적합을 막기위해 Dropout 사용.

10개의 출력층 만듦.

model.add(keras.layers.Conv2D(64, kernel_size=(3,3), activation='relu', padding='same'))
model.add(keras.layers.MaxPooling2D(2))

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'))

모델 요약

model.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 (MaxPooling2 (None, 7, 7, 64)          0         
#// _________________________________________________________________
#// 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
#// _________________________________________________________________

plot_model()

keras.utils.plot_model(model)

keras.utils.plot_model(model, show_shapes=True, to_file='cnn-architecture.png', dpi=300)

show_shapes = True 가 되면 input, output 같이 보여줌.

컴파일과 훈련

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)

history = model.fit(train_scaled, train_target, epochs=20,
                    validation_data=(val_scaled, val_target),
                    callbacks=[checkpoint_cb, early_stopping_cb])

optimizer = 'adam', 타깃 값이 정수 레이블이나 loss 함수를 sparse_categorical_crossentropy 사용

정확도 함께 출력하고자 metrics='accuracy' 사용

 

체크포인트와 콜백 지정

 

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()

7번째 epoch 즉, 6에서 모델 종료!

평가와 예측

model.evaluate(val_scaled, val_target)

#//375/375 [==============================] - 1s 2ms/step - loss: 0.2118 - accuracy: 0.9212
#//[0.2118101418018341, 0.9212499856948853]

손실 0.2, 정확도 92%

 

plt.imshow(val_scaled[0].reshape(28, 28), cmap='gray_r')
plt.show()

preds = model.predict(val_scaled[0:1])
print(preds)

#//[[1.4339859e-16 8.4426813e-24 2.2553201e-18 4.8564068e-16 3.6903781e-15
#//  6.4212738e-20 3.1580050e-15 9.1121079e-19 1.0000000e+00 1.0684053e-20]]

소프트함수 결과값

9번째 값이 가방 의미

테스트 세트 점수

test_scaled = test_input.reshape(-1, 28, 28, 1) / 255.0
model.evaluate(test_scaled, test_target)

#//313/313 [==============================] - 1s 3ms/step - loss: 0.2360 - accuracy: 0.9163
#//[0.23596987128257751, 0.9162999987602234]

검증세트보다 조금 낮은 91% 성능

합성곱 모델 구성 방식만 다르지 검증이나 테스트는 동일함.

 

참고자료

https://www.youtube.com/watch?v=WuHD9yUuTDk&list=PLVsNizTWUw7HpqmdphX9hgyWl15nobgQX&index=21