Deep Learning/혼공 머신 러닝 - 딥러닝

[DL] 합성곱 신경망 이용한 Image Classification

KimTory 2022. 1. 4. 23:46

[TensorFlow 함수]

 

① Conv2D : 입력의 너비와 높이 방향의 합성곱 연산을 구현한 클래스

 

② MaxPooling2D : 입력의 너비와 높이를 줄이는 풀링 연산을 구현한 클래스

 

③ plot_model : 케라스 모델 구조를 그리거나 파일로 저장 (주피터 노트북)

 

from tensorflow import keras
from sklearn.model_selection import train_test_split

# train, test data 분류
(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

# test_size = 0.2는 전체 data set의 20%를 validation set으로 지정
# default = 0.25
train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)

 

[첫 번째 합성곱 층 생성]

model = keras.Sequential()

// 32개의 filter, 크기가 3인 filter
// 활성화 함수 relu
// kernel_size는 입력 데이터의 채널의 따라 필터의 채널이 달라진다
model.add(keras.layers.Conv2D(32, kernel_size=3, activation='relu', 
                              padding='same', input_shape=(28,28,1))) // 배치 차원 x
                              
model.add(keras.layers.MaxPooling2D(2))

# 64개의 필터 생성됨 (14, 14, 64)
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()) # 1차원 배열로 reshape (7 * 7 * 64)
model.add(keras.layers.Dense(100, activation='relu')) # 100개 뉴런 은닉층
model.add(keras.layers.Dropout(0.4)) # 과대 적합 방지/ 하이퍼파라미터로 40% 적용
model.add(keras.layers.Dense(10, activation='softmax')) # 출력층

입력 채널 1 채널이라 (3,3,1) Filter 32개 생성

→ padding= "same"를 설정하였기에, conv2D에서 (28,28, 32) 특성 맵이 생성됨

두 번째 합성공 - 풀링 층 추가

 

model.summary()


# result

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

# ------

① 첫 번째 conv2d 사용 하여, 너비 - 높이 - 채널층 생성

② max_pooling2d 사용 하여 너비 - 높이 차원이 / 2로 되어 (14,14,32)가 됨

③ 두 번째 합성곱에서 특성 맵의 크기가 64로 증가

④ 이후 다시 한 번 max_pooling2d 사용 하여 너비 - 높이를 절반으로 감소 시킴

이후 flatten 으로 1차원으로 재정렬 후, 100개의 뉴런과 완전 연결 하여 은닉층의 모델 파라미터 개수가

3,136 * 100 + 100 = 313,700이 됨

 

▶ max_pooling2d 층과 flatten 층은 가중치가 없음 (param # 확인)

 


[compile과 train]

# Adam 옵티마이저 사용
# 각 파라미터마다 다른 크기의 업데이트를 적용하는 방법
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', 
              metrics='accuracy')

# model 저장
checkpoint_cb = keras.callbacks.ModelCheckpoint('best-cnn-model.h5', 
                                                save_best_only=True)
                                                
# 검증 세트가 점수가 2회 epoch 중, 상승 하지 않을 시 조기 종료
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])
                    # callback 지정 (ModelCheckpoint ,EarlyStopping)
                    
                    
                    
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()


[평가와 예측]

model.evaluate(val_scaled, val_target)

# 맷플롯립에서는 깊이 차원이 없으므로 (28,28,1) 크기를 (28,28)로 바꾸어 출력
plt.imshow(val_scaled[0].reshape(28, 28), cmap="gray_r")
plt.show()

preds = model.predict(val_scaled[0:1])
print(preds)
[0.22364725172519684, 0.9206666946411133]
        손실                정확도

val_scaled[0].reshape(28, 28) → 출력