인공 신경망 모델을 훈련하는 모범 사례 필요한 도구들을 살펴보자.

이번 절에서는 케라스 API를 사용해서 모델을 훈련하는데 필요한 다양한 도구들을 살펴보자.

손실곡선

앞에서 fit()을 출력하면 마지막 출력으로

<keras.callbacks.History at 0x264150f7040>

가 출력된다.

이 코드는 훈련에서 사용한 지표, 즉 손실과 정확도 값이 저장되어 있는데, 이를 그래프로 그려보자.

 

처음부터 코드 다시짜보자.!

from tensorflow impor 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, trian_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_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten (Flatten)           (None, 784)               0         
                                                                 
 dense (Dense)               (None, 100)               78500     
                                                                 
 dense_1 (Dense)             (None, 10)                1010      
                                                                 
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________

이제 fit() 메소드의 결과를 history 변수에 담아 보겠다.

model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
history = model.fit(train_scaled, train_target, epochs=5, verbose=0)
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()

 

5개의 에포크가 0~4사이에 포함되어 있다.

y축은 계산된 손실

 

이번에는 정확도를 출력 해보자.

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

에포크마다 손실이 감소하고 정확도가 올라감을 확인할 수 있다.

어?! 그러면 에포크를 ㅈㄴ 늘리면 좋은거 아닐까??

20으로 해보자.

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

history 딕셔너리에 어떤 키가 들어 있는지 보자.

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('epochs')
plt.ylabel('loss')
plt.legend(['train'])

주황 = 검증 세트

파랑 = 훈련 세트

에포크가 증가할 수록 훈련세트의 손실은 꾸준히 감소하지만, 검증세트의 손실은 5를 기준을 증가한다!!!!

에포크가 증가할수록 과대적합이 일어나는 것을 위 그래프를 통해 확인할 수 있다.

 

 

이제 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('epochs')
plt.ylabel('loss')
plt.legend(['train','val'])
plt.show()

검증세트의 loss가 위의 SGD? 를 썼을때보다 확실히 낮은것을 볼 수 있다.

이는 Adam 옵티마이저가 이 데이터셋에 더 유용하다는것을 보여준다!!

 

규제방식에 대해서 알아보자!!

 

드롭아웃

드롭아웃은 아래 그림처럼 훈련과정에서 층에 있는 일부 뉴런을 랜덤하게 꺼서( 뉴런의 출력을 0으로 만들어)

과대 적합을 막는다.

 

말그대로 층에 있는 뉴런 한명 드롭아웃 시키는것!! (랜덤)

하이퍼파라미터 : 몇개의 뉴런을 드롭아웃 시킬건지..

 

드롭아웃이 어떻게 과적합을 막지???

----------------->

1. 이전 층의 일부 뉴런이 랜덤하게 꺼지면 (0이 되면) 특정 뉴런에 과대하게 의존하는것을 줄이고 모든 입력에 주의를 기울이는쪽으로 변함.

2. 일종의 앙상블 기법임. 랜덤하게 드롭아웃된 신경들끼리 훈련하기 때문에 다른 알고리즘끼리 학습되는 느낌.

 

Dropout을 적용해보자.

model = model_fn(keras.layers.Dropout(0.3))   # 30%를 버리기로 했다!!!
model.summary()

Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_2 (Flatten)         (None, 784)               0         
                                                                 
 dense_4 (Dense)             (None, 100)               78500     
                                                                 
 dropout (Dropout)           (None, 100)               0         
                                                                 
 dense_5 (Dense)             (None, 10)                1010      
                                                                 
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________

 생각해보면

 Dropout() 메소드는 훈련할 때만 사용해야하고, 훈련이 끝난 후 평가, 예측을 할 때는 사용하지 말아야한다.

그러려면 모델을 훈련할때 Dropout()을 사용했다면 끝난후 층을 다시 빼야 한다.

하지만 Keras(tensorflow)는 자동으로 dropout을 적용하지 않는다. (평가/예측 시) 따라서 따로 빼줄 필요가 없다.

 

어쨌든 dropout해서 훈련한 결과를 그래프로 그려보자 !!

 

주황색 (검증세트)의 loss가 더 줄어든 모습이다.

과대적이 확실히 줄어든 모습이다.

 

모델 저장과 복원

에포크 횟수를 20에서 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')
model.save('model-whole.h5')
!ls -al *.h5

 

모델 predict() 메소드에서 가장 큰 값을 고르기 위해 argmax() 함수를 사용하자.!

이 함수는 배열에서 가장 큰 값의 인덱스를 반환한다.

예를 들어 배열의 첫번째 원소가 가 큰 값일 경 0을 반환한다.

 

다행히 우리가 준비한 타겟값도 0부터 시작하기 때문에 비교하기 쉽다.

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

argmax()함수의 axis = -1은 배열의 마지막 차원을 따라 최대값을 고릅니다.

검증 세트는 2차원 배열이기 때문에 마지막 차원은 1이 된다.

아래 사진을 통해 이해하자.

axis=1이면 열을 따라 각 행의 최대값의 인덱스를 선택하고, axis=0 이면 행을 따라 각 열의 최대값의 인덱스를 선택합니다.

 

그 다음 라인은 argmax()로 고른 index(val_labels)와 타깃(val_target)을 비교한다.

두 배열에서 각 위치의 값이 같으면 1이되고 다르면 0이 됩니다. 이를 평균하면 정확도 된다.

 

이번에는 모델 전체를 파일에서 읽은 다음 검증 세트의 정확도를 출력해보자.

 

model = keras.models.load_model('model-whole.h5')
model.evaluate(val_scaled, val_target)


375/375 [==============================] - 1s 3ms/step - loss: 0.3393 - accuracy: 0.8792
[0.33925992250442505, 0.8791666626930237]

 

콜 백

 콜백 = 훈련 과정 중에 어떤 작업을 수행할 수 있게 해주는 객체로 keras.callbacks로 사용가능

여기서는 keras.callbacks.ModelCheckpoint을 사용. 역할 = 에포크마다 모델을 저장함!!

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)
model.fit(train_scaled,train_target, epochs=20, verbose=0,
			validation_data=(val_scaled, val_target),
            callbacks=[checkpoint_cb])

왜 가장 낮은 검증점수를 저장????

 검증점수가 상승하기 시작하면 과적합이 발생해서 훈련 의미? 필요가없다.

이 때 중지한다면 상당한 시간 (자원)을 아낄 수 있다.

 

이를 조기 종료(early stopping)이라고 하는데, 딥러닝분야에서 아주 많이 쓰인다고 한다.

규제 방법중에 하나라고 생각하면 편할듯.

 

코드 = EarlyStopping 콜백 클래스

 

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)
history  = model.fit(train_scaled, train_target, epochs=20, verbose=0,
					validation_data=(val_scaled, val_target),
                    callbacks = [checkpoint_cb, early_stopping_cb])

훈련을 마치고나서 몇 번째 에포크에서 훈련이 중지되었는지 확인가능!!!(아래 코드)

early_stopping_cb.stopped_epoch

 

이어서 훈련 손실과 검증 손실을 출력해서 확인해보자.

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

 

 

+ Recent posts