Tensorflow Tutorial 8

 

모델 저장과 복원

모델 저장과 복원

  • 모델의 저장
    • 긴 훈련 시간을 피할 수 있음
    • 모델을 공유할 수 있음
  • 공유되는 내용
    • 모델을 만드는 코드
    • 모델의 훈련된 가중치 또는 파라미터

설정

설치와 임포트

  • pyyaml, h5py 라이브러리 설치 - HDF5 포맷으로 모델을 저장하기 위해서 필요
import os

import tensorflow as tf
from tensorflow import keras

print(tf.version.VERSION)
2.7.0

데이터셋 받기

  • MNIST 데이터셋을 이용하여 모델을 만들고 저장
  • 모델의 실행 속도를 빠르게 하기 위해 처음 1,000개만 사용
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()

train_labels = train_labels[:1000]
test_labels = test_labels[:1000]

train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0
test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0

모델 정의

# 간단한 Sequential 모델을 정의합니다
def create_model():
  model = tf.keras.models.Sequential([
    keras.layers.Dense(512, activation='relu', input_shape=(784,)),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10)
  ])

  model.compile(optimizer='adam',
                loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
                metrics=['accuracy'])

  return model

# 모델 객체를 만듭니다
model = create_model()

# 모델 구조를 출력합니다
model.summary()
Metal device set to: Apple M1
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #
=================================================================
 dense (Dense)               (None, 512)               401920

 dropout (Dropout)           (None, 512)               0

 dense_1 (Dense)             (None, 10)                5130

=================================================================
Total params: 407,050
Trainable params: 407,050
Non-trainable params: 0
_________________________________________________________________


2022-02-17 16:46:00.393796: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support.
2022-02-17 16:46:00.395131: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: <undefined>)

훈련하는 동안 체크포인트 저장하기

  • 훈련한 모델을 다시 훈련할 필요 없이 사용
  • 중단한 부분부터 다시 훈련을 시작
  • tf.keras.callbacks.ModelCheckpoint 콜백을 사용
checkpoint_path = "training_1/cp.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

# 모델의 가중치를 저장하는 콜백 만들기
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,
                                                 save_weights_only=True,
                                                 verbose=1)

# 새로운 콜백으로 모델 훈련하기
model.fit(train_images,
          train_labels,
          epochs=10,
          validation_data=(test_images,test_labels),
          callbacks=[cp_callback])  # 콜백을 훈련에 전달합니다

# 옵티마이저의 상태를 저장하는 것과 관련되어 경고가 발생할 수 있습니다.
# 이 경고는 (그리고 이 노트북의 다른 비슷한 경고는) 이전 사용 방식을 권장하지 않기 위함이며 무시해도 좋습니다.
2022-02-17 16:49:51.105323: W tensorflow/core/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz


Epoch 1/10


2022-02-17 16:49:51.368642: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.


32/32 [==============================] - ETA: 0s - loss: 1.1427 - accuracy: 0.6720
Epoch 00001: saving model to training_1/cp.ckpt
32/32 [==============================] - 1s 17ms/step - loss: 1.1427 - accuracy: 0.6720 - val_loss: 0.7174 - val_accuracy: 0.7760
Epoch 2/10
 1/32 [..............................] - ETA: 0s - loss: 0.5445 - accuracy: 0.8750

2022-02-17 16:49:52.117317: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.


23/32 [====================>.........] - ETA: 0s - loss: 0.4335 - accuracy: 0.8859
Epoch 00002: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.4143 - accuracy: 0.8890 - val_loss: 0.5200 - val_accuracy: 0.8290
Epoch 3/10
26/32 [=======================>......] - ETA: 0s - loss: 0.2802 - accuracy: 0.9279
Epoch 00003: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.2809 - accuracy: 0.9280 - val_loss: 0.4814 - val_accuracy: 0.8420
Epoch 4/10
26/32 [=======================>......] - ETA: 0s - loss: 0.2033 - accuracy: 0.9531
Epoch 00004: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.2021 - accuracy: 0.9530 - val_loss: 0.4407 - val_accuracy: 0.8560
Epoch 5/10
25/32 [======================>.......] - ETA: 0s - loss: 0.1396 - accuracy: 0.9725
Epoch 00005: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.1496 - accuracy: 0.9720 - val_loss: 0.4382 - val_accuracy: 0.8560
Epoch 6/10
26/32 [=======================>......] - ETA: 0s - loss: 0.1006 - accuracy: 0.9820
Epoch 00006: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.1018 - accuracy: 0.9810 - val_loss: 0.4350 - val_accuracy: 0.8610
Epoch 7/10
26/32 [=======================>......] - ETA: 0s - loss: 0.0784 - accuracy: 0.9868
Epoch 00007: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.0800 - accuracy: 0.9870 - val_loss: 0.4303 - val_accuracy: 0.8710
Epoch 8/10
26/32 [=======================>......] - ETA: 0s - loss: 0.0549 - accuracy: 0.9988
Epoch 00008: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.0572 - accuracy: 0.9950 - val_loss: 0.4145 - val_accuracy: 0.8650
Epoch 9/10
25/32 [======================>.......] - ETA: 0s - loss: 0.0513 - accuracy: 0.9962
Epoch 00009: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.0513 - accuracy: 0.9960 - val_loss: 0.4254 - val_accuracy: 0.8610
Epoch 10/10
23/32 [====================>.........] - ETA: 0s - loss: 0.0391 - accuracy: 1.0000
Epoch 00010: saving model to training_1/cp.ckpt
32/32 [==============================] - 0s 8ms/step - loss: 0.0360 - accuracy: 1.0000 - val_loss: 0.4128 - val_accuracy: 0.8710





<keras.callbacks.History at 0x2a162ee50>
os.listdir(checkpoint_dir)
['cp.ckpt.data-00000-of-00001', 'checkpoint', 'cp.ckpt.index']
  • 두 모델이 동일한 아키텍처를 공유하기만 한다면 두 모델 간에 가중치를 공유할 수 있다.
  • 따라서 가중치 전용에서 모델을 복원할 때 원래 모델과 동일한 아키텍처로 모델을 만든 다음 가중치를 설정
# 기본 모델 객체를 만듭니다
model = create_model()

# 모델을 평가합니다
loss, acc = model.evaluate(test_images,  test_labels, verbose=2)
print("훈련되지 않은 모델의 정확도: {:5.2f}%".format(100*acc))
32/32 - 0s - loss: 2.3495 - accuracy: 0.1340 - 176ms/epoch - 5ms/step
훈련되지 않은 모델의 정확도: 13.40%


2022-02-17 16:52:26.824308: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.
  • 체크포인트에서 가중치 로드 후 다시 실행
# 가중치 로드
model.load_weights(checkpoint_path)

# 모델 재평가
loss,acc = model.evaluate(test_images,  test_labels, verbose=2)
print("복원된 모델의 정확도: {:5.2f}%".format(100*acc))
32/32 - 0s - loss: 0.4128 - accuracy: 0.8710 - 101ms/epoch - 3ms/step
복원된 모델의 정확도: 87.10%

체크포인트 콜백 매개변수

# 파일 이름에 에포크 번호를 포함시킵니다(`str.format` 포맷)
checkpoint_path = "training_2/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

# 다섯 번째 에포크마다 가중치를 저장하기 위한 콜백을 만듭니다
cp_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_path,
    verbose=1,
    save_weights_only=True,
    period=5)

# 새로운 모델 객체를 만듭니다
model = create_model()

# `checkpoint_path` 포맷을 사용하는 가중치를 저장합니다
model.save_weights(checkpoint_path.format(epoch=0))

# 새로운 콜백을 사용하여 모델을 훈련합니다
model.fit(train_images,
          train_labels,
          epochs=50,
          callbacks=[cp_callback],
          validation_data=(test_images,test_labels),
          verbose=0)
WARNING:tensorflow:`period` argument is deprecated. Please use `save_freq` to specify the frequency in number of batches seen.


2022-02-17 17:03:47.143254: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.
2022-02-17 17:03:47.447065: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.



Epoch 00005: saving model to training_2/cp-0005.ckpt

Epoch 00010: saving model to training_2/cp-0010.ckpt

Epoch 00015: saving model to training_2/cp-0015.ckpt

Epoch 00020: saving model to training_2/cp-0020.ckpt

Epoch 00025: saving model to training_2/cp-0025.ckpt

Epoch 00030: saving model to training_2/cp-0030.ckpt

Epoch 00035: saving model to training_2/cp-0035.ckpt

Epoch 00040: saving model to training_2/cp-0040.ckpt

Epoch 00045: saving model to training_2/cp-0045.ckpt

Epoch 00050: saving model to training_2/cp-0050.ckpt





<keras.callbacks.History at 0x29d93a280>
os.listdir(checkpoint_dir)
['cp-0005.ckpt.data-00000-of-00001',
 'cp-0050.ckpt.index',
 'cp-0005.ckpt.index',
 'cp-0050.ckpt.data-00000-of-00001',
 'checkpoint',
 'cp-0020.ckpt.data-00000-of-00001',
 'cp-0000.ckpt.index',
 'cp-0030.ckpt.index',
 'cp-0025.ckpt.data-00000-of-00001',
 'cp-0000.ckpt.data-00000-of-00001',
 'cp-0035.ckpt.index',
 'cp-0010.ckpt.index',
 'cp-0045.ckpt.index',
 'cp-0045.ckpt.data-00000-of-00001',
 'cp-0010.ckpt.data-00000-of-00001',
 'cp-0035.ckpt.data-00000-of-00001',
 'cp-0015.ckpt.index',
 'cp-0040.ckpt.index',
 'cp-0025.ckpt.index',
 'cp-0030.ckpt.data-00000-of-00001',
 'cp-0040.ckpt.data-00000-of-00001',
 'cp-0015.ckpt.data-00000-of-00001',
 'cp-0020.ckpt.index']
latest = tf.train.latest_checkpoint(checkpoint_dir)
latest
'training_2/cp-0050.ckpt'

참고: 기본 TensorFlow 형식은 가장 최근의 체크포인트 5개만 저장

# 새로운 모델 객체를 만듭니다
model = create_model()

# 이전에 저장한 가중치를 로드합니다
model.load_weights(latest)

# 모델을 재평가합니다
loss, acc = model.evaluate(test_images,  test_labels, verbose=2)
print("복원된 모델의 정확도: {:5.2f}%".format(100*acc))
32/32 - 0s - loss: 0.5124 - accuracy: 0.8720 - 170ms/epoch - 5ms/step
복원된 모델의 정확도: 87.20%


2022-02-17 17:05:40.713189: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.

이 파일들은 무엇인가요?

  • 위의 코드는 이진 형식의 훈련된 가중치만 포함하는 체크포인트 형식의 파일 모음에 가중치를 저장한다.
  • 체크 포인트에는 다음이 저장된다.
    • 모델의 가중치를 포함하는 하나 이상의 샤드
    • 어떤 가중치가 어떤 샤드에 저장되어 있는지 나타내는 인덱스 파일
  • 단일 머신에서 모델을 훈련하는 경우 접미사가 .data-00000-of-00001인 하나의 샤드를 갖게 된다.

수동으로 가중치 저장하기

  • Model.save_weights 메서드를 사용하여 수동으로 가중치를 저장
  • 기본적으로 tf.keras, 특히 save_weights는 .ckpt 확장자가 있는 TensorFlow 체크포인트 형식을 사용
# 가중치를 저장합니다
model.save_weights('./checkpoints/my_checkpoint')

# 새로운 모델 객체를 만듭니다
model = create_model()

# 가중치를 복원합니다
model.load_weights('./checkpoints/my_checkpoint')

# 모델을 평가합니다
loss,acc = model.evaluate(test_images,  test_labels, verbose=2)
print("복원된 모델의 정확도: {:5.2f}%".format(100*acc))
2022-02-18 09:50:04.928420: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.


32/32 - 0s - loss: 0.5124 - accuracy: 0.8720 - 313ms/epoch - 10ms/step
복원된 모델의 정확도: 87.20%

전체 모델 저장하기

  • model.save 메서드를 호출하여 모델의 구조, 가중치, 훈련 설정을 하나의 파일/폴더에 저장
  • 원본 파이썬 코드가 없어도 사용 가능
  • 옵티마이저 상태가 복원되어 중지한 시점에서 훈련을 다시 시작할 수 있음
  • 두가지 다른 형식으로 저장 가능 (SavedModel, HDF5)
  • Tensorflow.js나 Tensorflolw Lite 등에서도 모델을 로드하여 사용 가능

SavedModel 포맷

  • 형식으로 저장된 모델은 tf.keras.models.load_model을 사용하여 복원
  • Tensorflow Serving과 호환
# 새로운 모델 객체를 만들고 훈련합니다
model = create_model()
model.fit(train_images, train_labels, epochs=5)

# SavedModel로 전체 모델을 저장합니다
!mkdir -p saved_model
model.save('saved_model/my_model')
Epoch 1/5
 6/32 [====>.........................] - ETA: 0s - loss: 2.0630 - accuracy: 0.3229

2022-02-18 09:57:29.318031: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.


32/32 [==============================] - 0s 7ms/step - loss: 1.1610 - accuracy: 0.6730
Epoch 2/5
32/32 [==============================] - 0s 4ms/step - loss: 0.4282 - accuracy: 0.8870
Epoch 3/5
32/32 [==============================] - 0s 4ms/step - loss: 0.2902 - accuracy: 0.9320
Epoch 4/5
32/32 [==============================] - 0s 4ms/step - loss: 0.2063 - accuracy: 0.9560
Epoch 5/5
32/32 [==============================] - 0s 4ms/step - loss: 0.1629 - accuracy: 0.9650
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.iter
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.beta_1
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.beta_2
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.decay
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.learning_rate
WARNING:tensorflow:A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.iter
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.beta_1
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.beta_2
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.decay
WARNING:tensorflow:Unresolved object in checkpoint: (root).optimizer.learning_rate
WARNING:tensorflow:A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.
INFO:tensorflow:Assets written to: saved_model/my_model/assets


2022-02-18 09:57:31.037605: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
  • SavedModel 형식은 protobuf 바이너리와 TensorFlow 체크포인트를 포함하는 디렉토리
# my_model 디렉토리
%ls saved_model

# assests 폴더, saved_model.pb, variables 폴더
%ls saved_model/my_model
my_model/
assets/            keras_metadata.pb  saved_model.pb     variables/
  • 저장된 모델로부터 새로운 모델 생성
new_model = tf.keras.models.load_model('saved_model/my_model')

# 모델 구조를 확인합니다
new_model.summary()
Model: "sequential_5"
_________________________________________________________________
 Layer (type)                Output Shape              Param #
=================================================================
 dense_10 (Dense)            (None, 512)               401920

 dropout_5 (Dropout)         (None, 512)               0

 dense_11 (Dense)            (None, 10)                5130

=================================================================
Total params: 407,050
Trainable params: 407,050
Non-trainable params: 0
_________________________________________________________________
# 복원된 모델을 평가합니다
loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)
print('복원된 모델의 정확도: {:5.2f}%'.format(100*acc))

print(new_model.predict(test_images).shape)
32/32 - 0s - loss: 0.4517 - accuracy: 0.8550 - 217ms/epoch - 7ms/step


2022-02-18 10:02:53.156661: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.


복원된 모델의 정확도: 85.50%
(1000, 10)


2022-02-18 10:02:53.440760: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.

HDF5 파일로 저장하기

# 새로운 모델 객체를 만들고 훈련합니다
model = create_model()
model.fit(train_images, train_labels, epochs=5)

# 전체 모델을 HDF5 파일로 저장합니다
# '.h5' 확장자는 이 모델이 HDF5로 저장되었다는 것을 나타냅니다
model.save('my_model.h5')
Epoch 1/5
 7/32 [=====>........................] - ETA: 0s - loss: 1.9692 - accuracy: 0.3616

2022-02-18 10:03:56.196978: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.


32/32 [==============================] - 0s 6ms/step - loss: 1.1620 - accuracy: 0.6560
Epoch 2/5
32/32 [==============================] - 0s 4ms/step - loss: 0.4278 - accuracy: 0.8780
Epoch 3/5
32/32 [==============================] - 0s 4ms/step - loss: 0.2873 - accuracy: 0.9170
Epoch 4/5
32/32 [==============================] - 0s 4ms/step - loss: 0.2016 - accuracy: 0.9530
Epoch 5/5
32/32 [==============================] - 0s 4ms/step - loss: 0.1544 - accuracy: 0.9680
  • .h5 파일로부터 모델을 다시 생성
# 가중치와 옵티마이저를 포함하여 정확히 동일한 모델을 다시 생성합니다
new_model = tf.keras.models.load_model('my_model.h5')

# 모델 구조를 출력합니다
new_model.summary()
Model: "sequential_6"
_________________________________________________________________
 Layer (type)                Output Shape              Param #
=================================================================
 dense_12 (Dense)            (None, 512)               401920

 dropout_6 (Dropout)         (None, 512)               0

 dense_13 (Dense)            (None, 10)                5130

=================================================================
Total params: 407,050
Trainable params: 407,050
Non-trainable params: 0
_________________________________________________________________
loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)
print('복원된 모델의 정확도: {:5.2f}%'.format(100*acc))
32/32 - 0s - loss: 0.4469 - accuracy: 0.8560 - 172ms/epoch - 5ms/step
복원된 모델의 정확도: 85.60%


2022-02-18 10:05:44.776935: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.
  • 저장되는 내용
    • 가중치 값
    • 모델 구조
    • 모델의 훈련 구성(.compile() 메서드에 전달하는 내용)
    • 존재하는 옵티마이저와 그 상태(훈련을 중단한 곳에서 다시 시작할 수 있게 해줌)

체크포인트가 호환되지 않기 때문에 케라스는 v1.x 옵티마이저(tf.compat.v1.train)를 저장할 수 없다.

사용자 정의 객체

  • HDF5와 SavedModel의 주요 차이점
    • HDF5는 객체 구성을 사용하여 모델 아키텍처를 저장
    • SavedModel은 실행 그래프를 저장
  • 따라서 SavedModel은 원본 코드 없이도 서브클래싱된 모델 및 사용자 지정 레이어와 같은 사용자 지정 객체를 저장할 수 있다.
  • 사용자 정의 객체를 HDF5로 저장하려면 다음 과정을 따라야 한다.
    1. 이 객체에 get_config 메서드를 정의하고 선택적으로 from_config 클래스 메서드를 정의한다.
      • get_config(self)는 객체를 다시 생성하기 위해 필요한 JSON 직렬화된 매개변수 딕셔너리를 반환한다.
      • from_config(cls, config)는 get_config에서 반환된 설정을 사용해 새로운 객체를 만든다. 기본적으로 이 함수는 이 설정을 초기화 메서드의 매개변수로 사용한다(return cls(**config)).
    2. 모델을 로드할 때 이 객체를 custom_objects 매개변수로 전달한다. 문자열 클래스 이름과 파이썬 클래스를 매핑한 딕서너리를 매개변수로 제공해야 한다. 예를 들면 tf.keras.models.load_model(path, custom_objects={‘CustomLayer’: CustomLayer})