카테고리 없음

[딥러닝] 신경망 모델 훈련

moru_xz 2023. 4. 14. 16:43

✅ 정리

- 드롭아웃: 은닉층에 있는 뉴런의 출력을 랜덤하게 꺼서 과대적합 막는기법

- 콜백: 케라스 모델을 훈련하는 도중에 어떤 작업을 수행할 수 있도록 도와주는 도구

- 조기종료(early stopping): 검증 점수가 더 이상 감소하지 않고 상승하여 과대적합이 일어남녀 훈련을 계속 진행하지 않고 멈추는 기법

 


 

머신러닝 알고리즘들은 좋은 성능을 내기 위해 매개변수를 조정하고 훈련하는 과정 반복 -> 모델의 구조가 어느 정도 고정

딥러닝에서는 모델의 구조를 직접 만드는 느낌이 강함(층을 추가하고 층에 있는 뉴런의 개수와 활성화 함수를 결정하는 과정)

 

케라스의 fit()메서드는 History 클래스 객체를 반환 -> History 객체에는 훈련과정에서 계산한 지표, 즉 손실과 정확도 값이 저장되어 있음 

 

데이터 불러오기

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

-> if 구문의 역할은 model_fn() 함수에 케라스 층을 추가하면 은닉층 뒤에 또 하나의 층을 추가하는 것

 

model = model_fn()
model.summary()

 

history()

model.compile(loss = 'sparse_categorical_crossentropy', metrics = 'accuracy')
history = model.fit(train_scaled, train_target, epochs = 5, verbose = 0)
# verbose: 훈련 과정 출력을 조절

print(history.history.keys())

-> history딕셔너리 안에는 손실과 정확도 포함

 

import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'])
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()

-> 에포크마다 손실이 감소하고 정확도가 향상 => 에포크 횟수를 늘려서 더 훈련

 

model.compile(loss = 'sparse_categorical_crossentropy', metrics = 'accuracy')
history = model.fit(train_scaled, train_target, epochs = 20, verbose = 0)

import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

-> 손실 감소 but 훈련 세트 점수뿐만 아니라 검증 세트에 대한 점수도 필요

 

검증 손실

손실과 정확도 중 어떤 것을 확인해야 하나?

: 인공 신경망 모델이 최적화 하는 대상은 정확도가 아닌 손실 함수 어떤 경우에는 손실 감소에 비례하여 정확도가 높아지지 않는 경우도 있음 -> 모델이 잘 훈련되었는지 판단하려면 정확도 보다는 손실 함수의 값을 확인하는 것이 더 낫다 

 

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

-> 에포크마다 검증 손실을 계산하기 위해 케라스 모델의 fit() 메서드에 검증 데이터 전달할 수 있음

 

print(history.history.keys())

-> 훈련 세트와 검증 세트의 손실과 정확도 들어있음 

 

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])

plt.xlabel('epoch')
plt.ylabel('loss')

plt.legend(['train', 'val'])
plt.show()

 

-> 초기에 검증 손실이 감소하다가 다시 상승, 훈련 손실은 꾸준히 감소하기 때문에 과대적합 모델이 만들어짐 -> 검증 손실이 상승하는 시점을 가능한 뒤로 늦추면 검증 세트에 대한 손실이 줄어들 뿐만 아니라 검증 세트에 대한 정확도도 증가

 

=> 어떻게 과대적합 막을 수 있을까? 옵티마이저 조정, 드롭아웃

 

옵티마이저 하이퍼파라미터 조정

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

-> 과대적합 줄어듦

 

드롭아웃

훈련 과정에서 층에 있는 일부 뉴련을 랜덤하게 꺼서(출력을 0으로) 과대적합을 막음 

뉴런은 랜덤하게 드롭아웃 되고 얼마나 많은 뉴런을 드롭할지는 우리가 결정해야 함 

 

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

-> 어떤 층 뒤에 드롭아웃을 두어 이 층의 출력을 랜덤하게 0으로 만듦 -> 드롭아웃이 층처럼 사용되지만 훈련되는 모델 파라미터는 없음 

출력결고에서 볼 수 있듯이 은닉층 뒤에 추가된 드롭아웃 층(Dropout)은 훈련되는 모델 파라미터가 없음. 또한 입력과 출력의 크기가 같음. 일부 뉴런의 출력을 0으로 만들지만 전체 출력 배열의 크기를 바꾸지는 않음 

 

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

-> 과대적합 줄었음 epoch를 20번 동안 훈련했기 때문에 과대적합 되었음. 10회로 조정

 

콜백 - Early Stopping

콜백은 훈련 과정 중간에 어떤 작업을 수행할 수 있게 하는 객체로 keras.callbacks 패키지 아래에 있는 클래스

 

20번에 에포크를 설정해주는 경우 검증 점수가 상승하기 시작하면 그 이후에는 과대적합이 커지기 때문에 훈련을 계속할 필요가 없음 -> 이때 훈련을 미리 중지하는 것을 early stopping이라고 부름 

early stopping은 훈련 에포크 횟수를 제한하는 역할이지만 모델이 과대적합 되는 것을 막아주기 때문에 규제 방법 중 하나로 생각할 수 있음 

 

patience 매개변수는 검증 점수가 향상되지 않더라도 참을 에포크 횟수로 지정

restore_best_weights 매개변수를 True로 지정하면 가장 낮은 검증 손실을 낸 모델 파라미터로 되돌림 

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

model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', 
              metrics = 'accuracy')
early_stopping_cb = keras.callbacks.EarlyStopping(patience = 2,
                                                 restore_best_weights = True)
history = model.fit(train_scaled, train_target, epochs = 10, verbose = 0,
                    validation_data = (val_scaled, val_target),
                    callbacks = early_stopping_cb)

 

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

평가

model.evaluate(val_scaled, val_target)


참고:

https://hongong.hanbit.co.kr/%ED%98%BC%EC%9E%90-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8A%94-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%94%A5%EB%9F%AC%EB%8B%9D/