데이터분석-머신러닝-AI/강의 정리

[혼자 공부하는 머신러닝+딥러닝] 19강. 신경망 모델 훈련 ▶️인경 신경망 모델 훈련의 모범 사례 학습하기 - 모델 재사용

bluebamus 2023. 11. 25.

https://www.youtube.com/watch?v=2by0Fz3XC84&list=PLJN246lAkhQjoU0C4v8FgtbjOIXxSs_4Q&index=20

 

 1. 신경망 모델 훈련

   - 준비 작업 및 신경망 모델 코드 함수화 하기

      - 준비 작업

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 / 255.0 

# # 훈련 테스트 분할
train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)

 

      - 신경망 모델 코드 함수화

def model_fn(a_layer=None):
    model = keras.Sequential()
    model.add(keras.layers.Flatten(input_shape=(28, 28)))
    model.add(keras.layers.Dense(100, activation='relu'))
    if a_layer: # 입력되는 값(새로운 층)이 있으면 추가한다.
        model.add(a_layer)
    model.add(keras.layers.Dense(10, activation='softmax'))
    return model

 

      - 기본 함수 테스트

model = model_fn()

model.summary()

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten (Flatten)           (None, 784)               0         
                                                                 
 dense (Dense)               (None, 100)               78500     
                                                                 
 dense_1 (Dense)             (None, 10)                1010      
                                                                 
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)

 

   - compile과 fit 그리고 시각화

model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')

history = model.fit(train_scaled, train_target, epochs=5, verbose=0)

   

      - keras의 .fit() 에는 훈련측정값을 가지고 있는 History 딕셔너리 객체가 있다. 기본적으로 loss만 반환되며 metrics에 선언된 값이 있으면 이에 대한 값도 같이 반환된다.

print(history.history.keys())

dict_keys(['loss', 'accuracy'])

 

      - 그래프로 그리기

import matplotlib.pyplot as plt

plt.plot(history.history['loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

plt.plot(history.history['accuracy'])
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()

   - 에포크 늘리기

      - 에포크를 더 늘려보면 손실이 점차 감소하는 것을 확인할 수 있다.

model = model_fn()
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')

history = model.fit(train_scaled, train_target, epochs=20, verbose=0)

 

plt.plot(history.history['loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

 

 

   - 검증손실과 과대적합

      - 훈련세트의 손실만 확인하게 되면 다른 데이터에 대한 정확도에 대해 정확히 판단하기 어렵다. 위에서 분리한 검증세트의 손실도 확인해 보자

model = model_fn()
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')

# 검증세트 결과 반환 추가
history = model.fit(train_scaled, train_target, epochs=20, verbose=0,
                    validation_data=(val_scaled, val_target))

 

      - 반환 결과 확인

print(history.history.keys())

# 반환 값에 추가 키 생성
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])

 

      - 그래프 확인

         - 훈련세트와 검증세트의 손실률을 확인하면 훈련세트에만 너무 잘 맞게 학습된 과대적합 상태인 것을 알 수 있다.

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

 

      - 옵티마이저 추가

         - adam을 추가하면 좀 더 완화된 그래프를 확인할 수 있다.

model = model_fn()
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
              metrics='accuracy')

history = model.fit(train_scaled, train_target, epochs=20, verbose=0,
                    validation_data=(val_scaled, val_target))
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()

 

 2. 드롭아웃

   - 신경망 모델에만 있는 귲제 방법이다.

   -  층에 있는 유닛 일부를 랜덤하게 동작하지 않도록 하여 훈련 성능을 낮춘다.

   - Dropout() : 얼마나 drop을 할 것인지에 대한 비율을 지정해야 한다. 

model = model_fn(keras.layers.Dropout(0.3))

model.summary()

Model: "sequential_7"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_7 (Flatten)         (None, 784)               0         
                                                                 
 dense_14 (Dense)            (None, 100)               78500     
                                                                 
 dropout (Dropout)           (None, 100)               0         
                                                                 
 dense_15 (Dense)            (None, 10)                1010      
                                                                 
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)

 

   - 드롭아웃 처리를 한 모델의 검증손실을 출력해 보면 과대적합이 완화된 결과를 확인할 수 있다.

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
              metrics='accuracy')

history = model.fit(train_scaled, train_target, epochs=20, verbose=0,
                    validation_data=(val_scaled, val_target))

 

   - 그래프 결과를 보면 에포크 10 정도에서 최적화가 이루어지는 것을 확인할 수 있다.

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

 

 3. 모델 저장과 복원

   - 최적의 값인 에포크 10으로 설정된 모델을 만든다

model = model_fn(keras.layers.Dropout(0.3))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
              metrics='accuracy')

history = model.fit(train_scaled, train_target, epochs=10, verbose=0,
                    validation_data=(val_scaled, val_target))

 

   - 모델 저장

      - .save_weights() : 훈련된 모델의 가중치를 저장한다.

model.save_weights('model-weights.h5')

 

      - .save() : 훈련된 모델의 구조와 가중치를 통째로 저장한다.

model.save('model-whole.h5')

 

 

   - 가중치 모델 복원

      - .load_weights() : 이전에 저장한 모델의 가중치를 불러온다.

         - 모델 구조가 정확히 같아야 불러올 수 있다.

      - .load_model() : 이전에 저장한 모델 전체를 불러온다.

model = model_fn(keras.layers.Dropout(0.3))

model.load_weights('model-weights.h5')

 

   - 검증세트의 정확도 계산

      - evaluate()를 사용해도 되지만, 복원한 모델의 다시 compile()을 실행해야 한다. 때문에 이하 강의에서는 새로운 데이터에 대해 정확도만 계산하는 것으로 가정한다.

      - 예측클래스를 직접 구하고, 타깃이랑 비교하여 동일한 비율을 구할 것이다.

 

      - .predict() : 샘플마다 각 클래스일 확률을 반환해 준다. == 사이킷런 predict_proba

         - 모든 클래스별 확률을 제공하는데 그 중 가장 높은 것을 다시 선택하는 과정을 사용자가 직접 해줘야 한다.

import numpy as np

# predict_classes 함수가 제거됨으로 이렇게 수동으로 사용자가 수행해줘야 한다.
val_labels = np.argmax(model.predict(val_scaled), axis=-1)

# 정답을 비교하여 맞춘 비율 확인
print(np.mean(val_labels == val_target))

37/375 [=>............................] - ETA: 0s 
375/375 [==============================] - 1s 1ms/step
0.8765

 

         - .argmax() : predict가 출력한 확률들 중 가장 큰 값을 뽑기 위해 넘파이를 활용한다.

             - axis = -1 : 배열의 마지막 차원, 축을 선택한다 이 코드에서는 axis = 1이 선택된다.

         - 반환된 최대값의 인덱스 val_labels와 val_target을 비교하여 일치하는 비율이 검증세트의 정확도가 된다.

import numpy as np

val_labels = np.argmax(model.predict(val_scaled), axis=-1)
print(np.mean(val_labels == val_target))

 37/375 [=>............................] - ETA: 0s 
375/375 [==============================] - 1s 1ms/step
0.8765

 

   - 전체 모델 복원

      - 모델의 구조와 옵티마이저까지 모두 복원이 되기 때문에 evaluate()를 바로 사용할 수 있다.

      - .load_model() : 이전에 저장한 모델 전체를 불러온다.

model = keras.models.load_model('model-whole.h5')

model.evaluate(val_scaled, val_target)

375/375 [==============================] - 1s 1ms/step - loss: 0.3402 - accuracy: 0.8765
[0.34021928906440735, 0.8765000104904175]

 

 4. 콜백

   - 훈련 과정 중간 특정 작업을 수행하게 해주는 객체로 keras.callbacks 패키지에 있다.

   - ModelCheckpoint 콜백

      - ModelCheckpoint() : 가장 자주 사용되는 콜백으로 에포크마다 모델을 저장해 준다.

         - save_best_only = True : 손실이 가장 낮은 모델만 저장하도록 설정

model = model_fn(keras.layers.Dropout(0.3))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
              metrics='accuracy')

# 콜백으로 체크 포인트를 객체로 만든다.
checkpoint_cb = keras.callbacks.ModelCheckpoint('best-model.h5',
                                                save_best_only=True)

# fit을 호출할 때 함수 내 매개변수로 정의해준다.
model.fit(train_scaled, train_target, epochs=20, verbose=0,
          validation_data=(val_scaled, val_target),
          callbacks=[checkpoint_cb])

 

   - 자동으로 저장된 최적의 모델을 load 해서 사용하면 된다.

# 콜백해둔 모델을 불러온다
model = keras.models.load_model('best-model.h5')

# 정확도를 확인한다. (다시 모델을 만들 필요가 없다)
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 1s 1ms/step - loss: 0.3197 - accuracy: 0.8857
[0.3197357654571533, 0.8856666684150696]

 

   - 조기종료 : EarlyStopping 콜백

      - 최적의 모델을 찾을 때 에포크를 일단 높게 설정하고 찾게 된다. 이럴 경우 불필요하게 오랫동안 훈련을 하게 된다.

         - 학습을 하는 과정에 성능이 좋아졌다가 나빠졌다가를 반복한다 이 과정들을 제한하여 최적의 위치를 찾는다.

      - EarlyStopping() : 과대적합이 시작되면 정의된 조건 범위에서 훈련을 조기종료 해주는 콜백

      - patience : 검증세트 성능이 떨어지더라도 넘어가는 유효한 에포크 제한 횟수 설정

      - restore_best_weights = True : 훈련동안 가장 손실이 낮았던 최적 가중치로 돌리는 설정

model = model_fn(keras.layers.Dropout(0.3)) # 모델 만들기
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
              metrics='accuracy')

# 체크포인트 콜백 설정
checkpoint_cb = keras.callbacks.ModelCheckpoint('best-model.h5',
                                                save_best_only=True)

# 조기종료 콜백 추가
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2,
                                                  restore_best_weights=True)
# fit에 정의
history = model.fit(train_scaled, train_target, epochs=20, verbose=0,
                    validation_data=(val_scaled, val_target),
                    callbacks=[checkpoint_cb, early_stopping_cb])

 

   - .stopped_epoch : 몇 번째 에포크에서 조기종료 했는지 저장되어 있는 변수

print(early_stopping_cb.stopped_epoch)
10

 

   - 그래프 그리기

      - 2번의 손실 발생 후 종료가 되었다. 최적의 에포크는 8이라 할 수 있다.

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)

375/375 [==============================] - 0s 1ms/step - loss: 0.3253 - accuracy: 0.8790
[0.32525375485420227, 0.8790000081062317]

 

   - fit의 매개변수: verbose

      - 훈련과정의 출력되는 log의 format을 조절한다.

      - 1 : 진행 막대와 측정값 출력 ( 기본 )

      - 2 : 진행막대 빼고 출력

      - 0 : 훈련과정을 출력하지 않는다.

 

 

 - reference : 

https://velog.io/@simon919/%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A0-7-3.-%EC%8B%A0%EA%B2%BD%EB%A7%9D-%EB%AA%A8%EB%8D%B8-%ED%9B%88%EB%A0%A8

 

[혼공머신] 7-3. 신경망 모델 훈련

🛠️신경망 모델을 훈련할 때 알아야 할 다양한 도구들🛠️

velog.io

 

댓글