59doit
합성곱 (6) 본문
합성곱 신경망 모델훈련
# 모델 컴파일한 다음 훈련
conv1.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) |
▶ 다중분류를 위한 크로스 엔트로피 손실 함수 사용
metrics 매개변수에 'accuracy'를 전달하여 훈련
# 아담 옵티마이저 사용
history = conv1.fit(x_train, y_train_encoded, epochs=20, validation_data=(x_val, y_val_encoded)) #20번의 에포크 동안 훈련 |
▶ 적응적 학습률 알고리즘 중 하나인 아담(Adam) 옵티마이저를 사용
아담은 손실 함수의 값이 최적값에 가까워질수록 학습률을 낮춰 손실 함수의 값이 안정적으로 수렴될 수 있게 해 준다.
# 손실 그래프
plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train_loss', 'val_loss']) plt.show() |
▶
# 정확도 그래프
plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train_accuracy', 'val_accuracy']) plt.show() |
▶
# 정확도
loss, accuracy = conv1.evaluate(x_val, y_val_encoded, verbose=0) print(accuracy) |
# 0.9115833044052124 |
드롭아웃
신경망에서 과대 적합을 줄이는 방법 중 하나는 드롭아웃
드롭아웃은 무작위로 일부 뉴런을 비활성화시킨다.
무작위로 일부 뉴런을 비활성화시키면 특정 뉴런에 과도하게 의존하여 훈련하는 것을 막아준다.
고르게 훈련시켜 전력 손실을 최소화해야 한다.
★일부 뉴런이 비활성화되었을 때에도 타깃을 잘 예측하려면
★특정 뉴런에 과도하게 의존하지 않고 모든 뉴런이 의미 있는 패턴을 학습해야 한다.
뉴런이 훈련 세트에 있는 패턴을 고르게 감지하므로 전체적인 일반화 성능이 높아진다.
드롭아웃은 모델을 학습할 때만 적용한다.
상대적으로 테스트와 실전의 출력값이 훈련할 때의 출력값보다 높아지므로
테스트나 실전에서는 출력값을 드롭아웃 비율만큼 낮춰야 한다.
**
텐서플로에서는 드롭아웃의 비율만큼 뉴런의 출력을 높인다.
출력값을 드롭아웃 비율만큼 낮춰야 한다.
하지만 텐서플로를 비롯하여 대부분의 딥러닝 프레임워크는 반대로 이 문제를 해결한다.
즉, 훈련할 때 드롭아웃 비율만큼 뉴런의 출력을 높여 훈련시킨다.
# 케라스로 만든 합성곱 신경망에 드롭아웃 적용하기
from tensorflow.keras.layers import Dropout conv2 = tf.keras.Sequential() conv2.add(Conv2D(10, (3, 3), activation='relu', padding='same', input_shape=(28, 28, 1))) conv2.add(MaxPooling2D((2, 2))) conv2.add(Flatten()) conv2.add(Dropout(0.5)) conv2.add(Dense(100, activation='relu')) conv2.add(Dense(10, activation='softmax')) |
▶ 합성곱층과 완전연결층 사이에 드롭아웃층을 추가하여 과대적합이 어떻게 바뀌는지 확인
# 드롭아웃층 확인하기
conv2.summary() |
Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 28, 28, 10) 100 max_pooling2d_1 (MaxPooling (None, 14, 14, 10) 0 2D) flatten_1 (Flatten) (None, 1960) 0 dropout (Dropout) (None, 1960) 0 dense_4 (Dense) (None, 100) 196100 dense_5 (Dense) (None, 10) 1010 ================================================================= Total params: 197,210 Trainable params: 197,210 Non-trainable params: 0 _________________________________________________________________ |
▶ 드롭아웃층은 훈련되는 가중치가 없고 텐서의 차원을 바꾸지 않는다
# 훈련하기
conv2.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) history = conv2.fit(x_train, y_train_encoded, epochs=20, validation_data=(x_val, y_val_encoded)) |
▶
# 손실그래프
plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train_loss', 'val_loss']) plt.show() |
# 정확도 그래프
plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train_accuracy', 'val_accuracy']) plt.show() |
▶ 그래프 결과 검증 손실이 증가되는 에포크가 확실히 더 늦춰졌고
훈련 손실과의 차이도 좁혀졌다. 정확도는 미세하게 증가되었다.
=> 분류문제에서 정확도를 직접 최적화 할 수는 없다.
대신 크로스 엔트로피 손실 함수를 대신 최적화한다.
손실함수를 최소화하면 정확도가 높아질 것으로 기대할 수 있지만 반드시 그렇지만은 않다.
# 정확도
loss, accuracy = conv2.evaluate(x_val, y_val_encoded, verbose=0) print(accuracy) |
# 0.9208333492279053 |