본문 바로가기

인공지능/딥러닝

[딥러닝DL] 심층신경망 훈련 및 성능향상2 - 성능규제(Dropout), 모델 저장 및 불러오기, 콜백함수(ModelCheckpoint, EarlyStopping)

~ 목차 ~

 

 

 

심층신경망 실습🦄

 

 

- 새로운 모델 생성 : model20 변수명 사용
- epoch 20번 반복 수행
- 프로그래스바가 보이도록 훈련시 출력하기
- 손실 및 정확도 곡선 각각 그려주세요~

 

 

* 함수 정의

def model_fn(a_layer = None):
    
    """모델 생성"""
    model = keras.Sequential()

    """입력층(1차원 전처리계층) 추가"""
    model.add(keras.layers.Flatten(input_shape = (28,28)))
    """100개의 출력을 담당하는 은닉계층 추가, 활성화 함수 relu"""
    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
    
    """모델 생성 계층 확인하기"""
    print(f"{model.summary()}")

 

* 함수 호출

model20 = model_fn()
model20

 

* 모델 설정하기

model20.compile(loss="sparse_categorical_crossentropy", metrics="accuracy")

 

* 모델 훈련하기

history20=model20.fit(train_scaled, train_target, epochs=20verbose=1)

모델 훈련하기

 

* 훈련에 대한 손실 및 정확도 곡선을 하나의 그래프로 그리기

def loss_accuracy_one_plt(model_name):
    plt.title(f"Epoch20 - Loss & Acc")
    plt.plot(model_name.epoch, model_name.history["loss"])
    plt.plot(model_name.epoch, model_name.history["accuracy"])
    plt.xlabel("epoch")
    plt.ylabel(f"loss & acc")
    plt.grid()
    plt.legend(["loss", "acc"])


    """이미지로 저장 시키기"""
    plt.savefig(f"./saveFig/Epoch20-loss_acc.png")
    plt.show()

loss_accuracy_one_plt(history20)

손실 및 정확도곡선

 


 

훈련 및 검증에 대한 손실 및 정확도 모두 표현하기 🦄

 

 

* 훈련과 검증을 동시에 수행하기

- validation_data : 검증 데이터를 이용해서 성능평가(evaluate)를 동시에 수행함

 

 

* 함수 호출

model = model_fn()
model

 

* 모델 설정하기

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

 

* 모델 훈련하기

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

 

훈련과 검증을 동시 수행

 

* 훈련에 대한 4가지 정보를 가져다 사용할 수 있다.

history.history.keys()

 

출력 : dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])

 

 

* 훈련과 검증에 대한 손실(loss) 곡선

plt.title("Epoch - Train & Val Loss")
plt.plot(history.epoch, history.history["loss"])
plt.plot(history.epoch, history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.grid()
plt.legend(["Train", "Val"])
"""이미지로 저장 시키기"""
plt.savefig(f"./saveFig/Epoch-Train_Val_loss.png")
plt.show()

 

해석🪄 : 훈련 손실율이 검증 손실율 그래프보다 작을때가 과소적합이 덜 일어나므로 적당함. 
                x=2일때가 가장 차이가 적으므로 좋은 시점임.

 

 

* 훈련과 검증에 대한 정확도(accuracy) 곡선

plt.title("Epoch - Train & Val accuracy")
plt.plot(history.epoch, history.history["accuracy"])
plt.plot(history.epoch, history.history["val_accuracy"])
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.grid()
plt.legend(["Train", "Val"])
"""이미지로 저장 시키기"""
plt.savefig(f"./saveFig/Epoch-Train_Val_accuracy.png")
plt.show()

 

해석🪄 : 훈련 할수록 과대적합이 일어나고 있음 (그래프 사이간격 멀어짐), 가장 근접했을 때가 좋은 epoch.

 

 

훈련과 검증 손실&정확도 곡선

 


 

옵티마이저 adam 사용 🦄

 

 

* 과적합 해소하기

 - model 변수명으로 신규 모델 만들기
     → 옵티마이저 adam 사용
 - 훈련 및 검증 동시에 훈련시킨 후 손실 및 검증 곡선 그려서 과적합 여부 확인하기

 

 

* 함수 호출

model = model_fn()
model

 

* 모델 설정하기

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

 

* 모델 훈련하기

history=model.fit(train_scaled, train_target, epochs=200, verbose=1, validation_data=(val_scaled, val_target))

 

 

* 훈련과 검증에 대한 손실(loss) 곡선

plt.title("Epoch - Train & Val Loss (Adam)")
plt.plot(history.epoch, history.history["loss"])
plt.plot(history.epoch, history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.grid()
plt.legend(["Train", "Val"])
"""이미지로 저장 시키기"""
plt.savefig(f"./saveFig/Epoch-Train_Val_loss(Adam).png")
plt.show()

 

* 훈련과 검증에 대한 정확도(accuracy) 곡선

plt.title("Epoch - Train & Val accuracy (Adam)")
plt.plot(history.epoch, history.history["accuracy"])
plt.plot(history.epoch, history.history["val_accuracy"])
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.grid()
plt.legend(["Train", "Val"])
"""이미지로 저장 시키기"""
plt.savefig(f"./saveFig/Epoch-Train_Val_accuracy(Adam).png")
plt.show()

 

 

 

해석🪄 과대적합이 발생하고 있다. 올라가다가 꺽이는 지점(val기준)이 가장 좋은 지점

 


 

성능 규제하기 - 드롭아웃(Dropout)🦄

 

 

* 성능 규제

 - 성능(과적합 여부 포함)을 높이기 위한 방법
 - 보통 전처리 계층을 사용하게 됩니다.
 - 전처리 계층은 훈련에 영향을 미치지 않음

 

* 성능 규제 방법 → 드롭 아웃(Dropout())

 

 

 

* 드롭아웃(Dropout)

 - 훈련 과정 중 일부 특성들을 랜덤하게 제외 시켜서 과대적합을 해소하는 방법
 - 딥러닝에서 자주 사용되는 전처리 계층으로 성능 개선에 효율적으로 사용됨

 

* 사용방법

 - 계층의 중간에 은닉층(hidden layer)로 추가하여 사용됨 ;보통 은닉계층 전에 넣어줌

 - 훈련에 관여하지는 않음 → 데이터에 대한 전처리라고 보시면 됩니다.

 

 ex)keras.layers.Dropout(0.3)
       Dropout(0.3) : 사용되는 특성 30% 정도를 제외하기

 

 ** 조금 멍청하게 만드는 방법...(똑똑해지는 것을 방지)

 

 

 

* 모델 생성하기

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

 

드롭아웃 계층 확인

 

* 모델 설정하기

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

 

* 모델 훈련하기

history=model.fit(train_scaled, train_target, epochs=200, verbose=1, validation_data=(val_scaled, val_target))

 

epochs=200

 

 

* 모델 훈련하기 2차 (훈련과 검증데이터가 근접한 epoch를 찾아서 다시 훈련시켜봄)

history=model.fit(train_scaled, train_target, epochs=14, verbose=1, validation_data=(val_scaled, val_target))

 

epochs=14

 

 

 

* 훈련과 검증에 대한 손실(loss) 곡선

plt.title("Epoch - Train & Val Loss (Adam-Dropout)")
plt.plot(history.epoch, history.history["loss"], marker=".")
plt.plot(history.epoch, history.history["val_loss"], marker=".")
plt.xlabel("epoch")
plt.ylabel("loss")
plt.grid()
plt.legend(["Train", "Val"])
"""이미지로 저장 시키기"""
plt.savefig(f"./saveFig/Epoch-Train_Val_loss(Adam-Dropout).png")
plt.show()

Adam-Dropout 손실곡선

 

해석🪄

- 7.5 epoch를 기점으로 그 전에는 과소적합이 나타나고 그 이후에는 점점 진행할 수록 과대적합이 나타나고 있다.

- 가장 근접했을 8정도가 적당한 시점으로 보인다.

 

 

* 훈련과 검증에 대한 정확도(accuracy) 곡선

plt.title("Epoch - Train & Val accuracy (Adam-Dropout)")
plt.plot(history.epoch, history.history["accuracy"] , marker="." )
plt.plot(history.epoch, history.history["val_accuracy"] , marker="." )
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.grid()
plt.legend(["Train", "Val"])
"""이미지로 저장 시키기"""
plt.savefig(f"./saveFig/Epoch-Train_Val_accuracy(Adam-Dropout).png")
plt.show()

 

Adam-Dropout 정확도 곡선

 

해석🪄

- 훈련이 위로가야됨, 10을 이후로 과대적합 , 12일때 가장 근접해보이므로 정확도를 보았을때 12가 적당해 보임.
- 두 그래프 모두 과소적합이 일어나지 않으면서 과대적합이 크게 일어나지 않아야하고 손실율이 낮으면서 정확도가 좋은 지점은 12가 되는거 같다.

 


 

모델 저장 및 복원하기 🦄

 

<모델 저장하는 방법>

 

* 가중치만 저장하기

  - 모델이 훈련하면서 찾아낸 가중치 값들만 저장하기
  - 모델 자체가 저장되지는 않습니다.
  - 모델 신규생성 > 저장된 가중치 불러와서 반영 > 예측 진행
  - 별도로 훈련(fit)은 하지 않아도 됩니다.

 

* 모델 자체 저장하기

  - 저장된 모델을 불러와서 > 예측 진행

 

 

가중치 저장 및 불러들이기

 

* 가중치 저장하기

   - save_weights() : 가중치 저장하기

   - 저장시 사용되는 확장자는 보통 h5를 사용합니다.

model.save_weights("./model/model_weights.h5")

 

 

* 저장된 가중치 불러들이기

   - load_weights () : 가중치 불러오기

"""1. 모델 생성"""
model_weight = model_fn(keras.layers.Dropout(0.3))
model_weight.summary()

"""2. 가중치 적용하기"""
model_weight.load_weights("./model/model_weights.h5")

"""이후 부터는 바로 예측으로 사용"""

가중치 모델

 

 

모델 자체 저장하기

 

* 모델 자체 저장하기

  - save()

model.save("./model/model_all.h5")

 

 

* 모델 자체 불러들이기

  - load_model()

model_all = keras.models.load_model("./model/model_all.h5")
model_all.summary()

"""이후부터는 바로 예측으로 사용 가능"""

저장한 모델

 

 

 

예측하기

 

* 예측하기

pred_data = model_all.predict(val_scaled)

"""첫번째 값만 추출"""
pred_data[0]

 

출력 : array([4.2536481e-11, 2.3170347e-15, 9.8706080e-13, 8.7341098e-12,
                     1.1521755e-10, 1.7207690e-06, 5.6376002e-14, 4.6494847e-08,
                     9.9999821e-01, 1.0138960e-14], dtype=float32)


 

  - np.argmax() : 배열에서 가장 큰 값을 가지는 인덱스를 추출

import numpy as np

np.argmax(pred_data[0]), val_target[0]

 

출력 : (8, 8)

해석🪄   8번째 인덱스 값이 가장 값이 크게 나왔다. 예측 성공


 

* 예측 결과의 모든 행에 대해서 가장 높은 값을 가지는 열의 인덱스 위치 추출 

  - axis=1 : 열 단위로 뽑아라

val_pred = np.argmax(pred_dataaxis=1)
val_pred

 

출력 : array([8, 8, 7, ..., 8, 8, 6], dtype=int64)


 

정답갯수, 오답갯수, 정답률, 오답률을 출력

 

<내 코드>

true = 0
false = len(val_pred)
for x, y in zip(val_pred, val_target):
    # print(f"x : {x}, y : {y}")
    if x == y:
        true += 1
        false -= 1
        
true_per = true/len(val_pred)*100
false_per = false/len(val_pred)*100

print(f"정답갯수 : {true} / 오답갯수 : {false}")
print(f"정답률 : {true_per:.2f}% / 오답률 : {false_per:.2f}%")

 

출력 :  정답갯수 : 10525 / 오답갯수 : 1475
            정답률 : 87.71% / 오답률 : 12.29%

 

<강사님 코드>

# ok = np.sum(val_pred == val_target)
ok = len(val_pred[val_pred == val_target])

no = np.sum(val_pred != val_target)

ok_p = ok / len(val_target)
no_p = no / len(val_target)

ok, no, ok_p, no_p

 

출력 :  (10525, 1475, 0.8770833333333333, 0.12291666666666666)

 

 


 

 

성능향상 - 콜백(Callback) 함수 🦄

 

< 성능향상 - 콜백함수>

 

* 콜백함수(Callback Function)

 - 모델 훈련 중에 특정 작업(함수)를 호출할 수 있는 기능
 - 훈련(fit)시에 지정하는 함수를 호출하는 방식
 - 훈련 중에 발생시키는 "이벤트"라고 생각하시면 됩니다.
 - 별도의 계층은 아니며, 속성(매개변수)으로 정의됩니다.

 

* 콜백함수 종류

 - ModelCheckpoint()
   : epoch 마다 모델을 저장하는 방식
   : 단, 앞에서 실행된 훈련 성능보다 높아진 경우에만 저장됨
   
 - EarlyStopping()
   : 훈련이 더이상 좋아지지 않으면 훈련(fit)을 종료시키는 방식
   : 일반적으로 ModelCheckpoint()와 함께 사용

 

 

ModelCheckPoint 콜백함수

 

1. 모델 생성하기

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

모델 확인하기

 

 

2. 모델 설정하기

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

 

 

3. 콜백함수 생성하기

< 콜백함수 - ModelCheckpoint >

* 콜백함수 생성

 - 훈련(fit) 전에 생성합니다.
 
 - save_best_only = True 
    : 이전에 수행한 검증 손실율보다 좋을 때 마다 훈련모델 자동 저장시키기 
    : 훈련이 종료되면, 가장 좋은 모델만 저장되어 있습니다.
    
 - save_best_only = False
    : epoch마다 훈련모델 자동 저장 시키기

 - 저장된 모델은 : 모델 자체가 저장되는 방식으로 추후 불러들인 후 바로 예측으로 사용 가능

 

checkpoint_cb = keras.callbacks.ModelCheckpoint(
    ### 모델 저장 경로 설정
    "./model/best_model.h5",
    ### 모델 저장 방법 설정
    save_best_only = True
)
checkpoint_cb

 

<keras.callbacks.ModelCheckpoint at 0x1c0973051f0>

 

 

4. 모델 훈련 시키기 - 콜백함수 적용

< 콜백함수 - ModelCheckpoint >

* 콜백함수로  훈련시키기

fit()함수 내에 콜백함수 매개변수에 정의

- 콜백함수 리스트 형식으로 정의

 ex) checkpoint_cb = keras.callbacks.ModelCheckpoint("./model/best_model.h5", save_best_only = True)
 ex) callbacks = [checkpoint_cb]

 

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

    ### 콜백함수에 대한 매개변수 : 리스트 타입으로 정의
    callbacks = [checkpoint_cb]
)

콜백함수 넣고 훈련

 

 

5.콜백함수를 통해 저장된 모델 불러들이기

model_cp_cb = keras.models.load_model("./model/best_model.h5")
model_cp_cb.summary()

"""성능 평가"""
model_cp_cb.evaluate(val_scaled, val_target)

 

 

 

 

EarlyStopping 콜백함수

 

< 콜백함수 - EarlyStopping>

* EarlyStopping()

 - 훈련 성능이 더 이상 좋아지지 않으면 훈련을 종료시킴
 - 과대적합을 해소하는데 좋음(과대 적합이 발생하기 전에 종료시킴)

 - 보통 콜백함수 ModelCheckpoint()와 함께 사용함


patience=2 : 더 이상 좋아지지 않는 epoch의 갯수 지정
                       가장 좋은 시점의 epoch 이후 2번 더 수행 후 그래도 좋아지지 않으면 종료시킨다는 의미

restore_best_weights=True : 가장 낮은 검증 손실을 나타낸 모델의 하이퍼파라메터로 모델을 업데이트 시킴


 ex) early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)
 ex) callbacks = [checkpoint_cb, early_stopping_cb]

 

 

1. 모델 생성하기

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

모델 생성

 

 

2. 모델 설정하기

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

 

 

3. 콜백함수 생성하기

"""ModelCheckPoint()"""

checkpoint_cb = keras.callbacks.ModelCheckpoint("./model/best_model.h5", save_best_only = True)

 

"""EarlyStopping()"""

early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)

 

 

4. 모델 훈련 시키기 - 콜백함수 적용

history = model.fit(
    train_scaled, train_target, epochs=100, verbose=1,
    validation_data=(val_scaled, val_target),

    ### 콜백함수에 대한 매개변수 : 리스트 타입으로 정의
    callbacks = [checkpoint_cb, early_stopping_cb]
)

해석🪄

- Epoch 8/100이 시점의 데이터가 정확하다는 뜻( -2 해야함 why?  patience=2 했으므로)
- loss: 0.3358 - accuracy: 0.8759 - val_loss: 0.3310 - val_accuracy: 0.8789

 

 

 

5. 콜백함수를 통해 저장된 모델 불러들이기

model_f= keras.models.load_model("./model/best_model.h5")
model_f.summary()

"""성능 평가"""
print(model_f.evaluate(train_scaled, train_target))
print(model_f.evaluate(val_scaled, val_target))

 

 

 

 

728x90