상세 컨텐츠

본문 제목

[tensorflow] 모델 정보와 History 정보 저장하기

머신러닝 딥러닝/Keras

by 힐둔 2021. 12. 15. 16:40

본문

 

문서 작업 후 저장하지 않아서 애써 작성한 문서가 날라가는 경우처럼, tensorflow를 이용해서 학습 까지 완료한 이후에 어떠한 사유로 Jupyter notebook의 kernel이 죽거나, window 창을 닫거나 PC가 재부팅 하는 경우, 우리는 애써 학습한 결과를 날리게 됩니다. 모델이 가벼운 경우에는 다시 Trainig을 돌리면 되지만 무겁거나 GPU가 없이 CPU 만으로 힘들게 하루 꼬박 돌려 결과를 얻은 경우에는 참으로 안타까운 일이 아닐수 없습니다.

 

그래서 이번에는 training model과 History를 저장하는 방법과 저장한 파일을 사용하는 방법을 알아보도록 하겠습니다.

 

model을 저장하는 방법은 두 가지 방법이 있습니다.

  • model.save_weights()
  • model.save()

그리고 학습결과를 담고 있는 history를 저장하는 방법은 다음과 같습니다.

  • pickle,json, csv

모델 생성

일단 모델이 하나 있어야겠죠? MNIST를 이용하는 간단한 CNN 모델을 구성해봅니다. 유명해서 코드가 널려 있습니다. 우리는 그거 하나를 가져오기로 합니다. 저는 여기에서 가져왔습니다.

 

import numpy as np
import mnist
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten
from tensorflow.keras.models import Sequential
import matplotlib.pyplot as plt

train_images = mnist.train_images()
train_labels = mnist.train_labels()
test_images = mnist.test_images()
test_labels = mnist.test_labels()

# Normalize the images.
train_images = (train_images / 255) - 0.5
test_images = (test_images / 255) - 0.5

# Reshape the images.
train_images = np.expand_dims(train_images, axis=3)
test_images = np.expand_dims(test_images, axis=3)

print(train_images.shape) # (60000, 28, 28, 1)
print(test_images.shape)  # (10000, 28, 28, 1)

num_filters = 8
filter_size = 3
pool_size = 2

model = Sequential([
  Conv2D(num_filters, filter_size, input_shape=(28, 28, 1)),
  MaxPooling2D(pool_size=pool_size),
  Flatten(),
  Dense(10, activation='softmax'),
])

model.compile(
  'adam',
  loss='categorical_crossentropy',
  metrics=['accuracy'],
)

model summary를 보면 Converlution layer, Pooling, 그리고 Dense 층이 각각 하나씩 밖에 없는 간단한 모델입니다.

 

그리고 fit() 함수를 통해 학습을 하고, 그 결과를 hist에 받도록 합니다. hist는 tf.keras.callbacks.History 형 이며, 학습의 결과를 dictionary 타입으로 저장하고 있습니다. 아래는 epochs가 3개 뿐이라 저장의 중요성을 약하지만, (필요시 마다 돌리면 되니) 데이터 종류가 더 크고, 모델이 복잡하며 그리고 epochs이 100개 이상 되는 몇 시간 이상 돌려야 하는 데이터의 경우는 저장은 필수입니다. 그리고 보통 하나만 돌리는게 아니라 여러개를 돌리게 되니까요~

hist = model.fit(
  train_images,
  to_categorical(train_labels),
  epochs=3,
  validation_data=(test_images, to_categorical(test_labels)),
)

결과는 다음과 같습니다.

Evaluation 결과는 다음과 같습니다.

model.evaluate(test_images, to_categorical(test_labels))

 


model을 저장하는 방법  

1. model.save_weights()는 학습 중인 weights를 저장합니다. 모델 정보를 저장하지 않기 때문에 이후에 사용할 때에는 정확한 모델을 알아야 합니다. 그리고 새로운 모델을 생성후 new_model.save_weights()를 통해 저장한 weights를 사용 가능 합니다.

 

일단, new_model을 아래와 같이 기존 코드와 동일하게 생성하도록 합니다. 이처럼 기존 모델을 알아야 되겠죠?

num_filters = 8
filter_size = 3
pool_size = 2

new_model = Sequential([
  Conv2D(num_filters, filter_size, input_shape=(28, 28, 1)),
  MaxPooling2D(pool_size=pool_size),
  Flatten(),
  Dense(10, activation='softmax'),
])

new_model.compile(
  'adam',
  loss='categorical_crossentropy',
  metrics=['accuracy'],
)

 

그리고, 아무것도 안한 상태로 evaluation을 하게 되면 당연히 accuracy가 낮게 나옵니다.

 

위에서 학습을 했던 model의 weights를 저장하고

model.save_weights("test_save_weight")

 

new_model을 이용해 loading 하고, evaluation 하면 아래와 같이 accuracy가 높게 나음을 확인할 수 있습니다.

new_model.load_weights("test_save_weight")
new_model.evaluate(test_images, to_categorical(test_labels))

 

2. model.save() 는 모델 정보 및 학습 가중치를 모두 저장합니다. 처음의 model 저장 후  tf.keras.models.load_model를 이용해서 다시 로딩 후 확인 시 처음의 모델 결과와 정확히 일치하는 것을 확인할 수 있습니다. 모델 정보를 몰라도 load_model의 return 값을 받아서 사용 가능합니다. 저는 save_weight() 보다는 아무래도 이게 편한 것 같습니다...

model.save("test_save_model")
reconstructed_model = tf.keras.models.load_model("test_save_model")
reconstructed_model.summary()

그리고 이전 모델 (model)과 복원한 모델(reconstructed_model)을 evaluation 하게 되면, 동일한 결과를 출력 하는 것을 확인 할 수 있습니다.

model.evaluate(test_images, to_categorical(test_labels))
reconstructed_model.evaluate(test_images, to_categorical(test_labels))

 


Training이 끝난 History 결과를 저장하는 방법

pickle.dump로 저장하고, pickle.load로 저장한 것을 로딩해서 재 사용 가능하다. 학습의 결과를 보려면 그래프 작업을 해야 하는데, 이렇게 저장하는 경우 추후에라도 재 사용이 가능해서 분석에 더욱 유리합니다. 많은 모델을 돌리고 그 결과를 저장해서 한꺼번에 결과 데이터를 만들때 다 로딩해서 확인하면 좋을 것 같습니다.

 

  with open('/trainHistoryDict', 'wb') as file_pi:
        pickle.dump(hist.history, file_pi)
history = pickle.load(open('/trainHistoryDict', "rb"))

 

History는 Dictinary 형식이므로 아래와 같이 data frame으로 변환 후, json이나 csv로도 저장할 수 있습니다.

# convert the history.history dict to a pandas DataFrame:     
hist_df = pd.DataFrame(history.history) 

# save to json:  
hist_json_file = 'history.json' 
with open(hist_json_file, mode='w') as f:
    hist_df.to_json(f)

# or save to csv: 
hist_csv_file = 'history.csv'
with open(hist_csv_file, mode='w') as f:
    hist_df.to_csv(f)

 

아래와 같은 코드로 저장했던 history 데이터의 그래프를 그려볼 수 있습니다.

fig, loss_ax = plt.subplots()
acc_ax = loss_ax.twinx()

loss_ax.plot(hist.history['loss'], 'y', label='train loss')
loss_ax.plot(hist.history['val_loss'], 'r', label='val loss')
loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
loss_ax.legend(loc='upper left')

acc_ax.plot(hist.history['accuracy'], 'b', label='train acc')
acc_ax.plot(hist.history['val_accuracy'], 'g', label='val acc')
acc_ax.set_ylabel('accuracy')
acc_ax.legend(loc='upper left')

plt.show()

 

 

'머신러닝 딥러닝 > Keras' 카테고리의 다른 글

fashion_mnist tensorflow DNN 예제  (0) 2022.06.15
[tensorflow] optuna tensorflow cnn 예제 #1  (0) 2022.01.23

관련글 더보기

댓글 영역