In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
In [ ]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 공식 영문 문서의 내용과 일치하지 않을 수 있습니다. 이 번역에 개선할 부분이 있다면 tensorflow/docs-l10n 깃헙 저장소로 풀 리퀘스트를 보내주시기 바랍니다. 문서 번역이나 리뷰에 참여하려면 docs-ko@tensorflow.org로 메일을 보내주시기 바랍니다.
훈련하는 도중이나 훈련이 끝난 후에 모델을 저장할 수 있습니다. 모델을 중지된 지점부터 다시 훈련할 수 있어 한 번에 오랫동안 훈련하지 않아도 됩니다. 또 모델을 저장하면 다른 사람에게 공유할 수 있고 작업을 재현할 수 있습니다. 연구한 모델과 기법을 공개할 때 많은 머신 러닝 기술자들이 다음과 같은 것들을 제공합니다:
이런 데이터를 공유하면 다른 사람들이 모델의 작동 방식을 이해하고 새로운 데이터로 모델을 실험하는데 도움이 됩니다.
주의: 신뢰할 수 없는 코드는 조심하세요. 텐서플로 모델은 프로그램 코드입니다. 자세한 내용은 텐서플로를 안전하게 사용하기 문서를 참고하세요.
사용하는 API에 따라서 여러가지 방법으로 텐서플로 모델을 저장할 수 있습니다. 이 문서는 텐서플로 모델을 만들고 훈련하기 위한 고수준 API인 tf.keras를 사용합니다. 다른 방법들에 대해서는 텐서플로의 저장과 복원 문서와 즉시 실행(eager execution) 문서의 저장하기 섹션을 참고하세요.
필요한 라이브러리를 설치하고 텐서플로를 임포트(import)합니다:
In [ ]:
!pip install pyyaml h5py # HDF5 포맷으로 모델을 저장하기 위해서 필요합니다
In [ ]:
import os
import tensorflow as tf
from tensorflow import keras
print(tf.version.VERSION)
MNIST 데이터셋으로 모델을 훈련하여 가중치를 저장하는 예제를 만들어 보겠습니다. 모델 실행 속도를 빠르게 하기 위해 샘플에서 처음 1,000개만 사용겠습니다:
In [ ]:
(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
먼저 간단한 모델을 하나 만들어 보죠.
In [ ]:
# 간단한 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()
In [ ]:
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]) # 콜백을 훈련에 전달합니다
# 옵티마이저의 상태를 저장하는 것과 관련되어 경고가 발생할 수 있습니다.
# 이 경고는 (그리고 이 노트북의 다른 비슷한 경고는) 이전 사용 방식을 권장하지 않기 위함이며 무시해도 좋습니다.
이 코드는 텐서플로 체크포인트 파일을 만들고 에포크가 종료될 때마다 업데이트합니다:
In [ ]:
!ls {checkpoint_dir}
훈련하지 않은 새로운 모델을 만들어 보겠습니다. 가중치만 복원할 땐 원본 모델과 동일한 구조로 모델을 만들어야 합니다. 여기서는 동일한 구조로 모델을 만들었으므로 다른 객체이지만 가중치를 공유할 수 있습니다.
훈련하지 않은 새 모델을 만들고 테스트 세트에서 평가해 보죠. 훈련되지 않은 모델의 성능은 무작위로 선택하는 정도의 수준입니다(~10% 정확도):
In [ ]:
# 기본 모델 객체를 만듭니다
model = create_model()
# 모델을 평가합니다
loss, acc = model.evaluate(test_images, test_labels, verbose=2)
print("훈련되지 않은 모델의 정확도: {:5.2f}%".format(100*acc))
체크포인트에서 가중치를 로드하고 다시 평가해 보죠:
In [ ]:
# 가중치 로드
model.load_weights(checkpoint_path)
# 모델 재평가
loss,acc = model.evaluate(test_images, test_labels, verbose=2)
print("복원된 모델의 정확도: {:5.2f}%".format(100*acc))
In [ ]:
# 파일 이름에 에포크 번호를 포함시킵니다(`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)
만들어진 체크포인트를 확인해 보고 마지막 체크포인트를 선택해 보겠습니다:
In [ ]:
!ls {checkpoint_dir}
In [ ]:
latest = tf.train.latest_checkpoint(checkpoint_dir)
latest
노트: 텐서플로는 기본적으로 최근 5개의 체크포인트만 저장합니다.
모델을 초기화하고 최근 체크포인트를 로드하여 테스트해 보겠습니다:
In [ ]:
# 새로운 모델 객체를 만듭니다
model = create_model()
# 이전에 저장한 가중치를 로드합니다
model.load_weights(latest)
# 모델을 재평가합니다
loss, acc = model.evaluate(test_images, test_labels, verbose=2)
print("복원된 모델의 정확도: {:5.2f}%".format(100*acc))
The above code stores the weights to a collection of checkpoint-formatted files that contain only the trained weights in a binary format. Checkpoints contain:
If you are only training a model on a single machine, you'll have one shard with the suffix: .data-00000-of-00001
앞에서 가중치를 모델에 로드하는 방법을 보았습니다. 수동으로 가중치를 저장하는 것도 쉽습니다. Model.save_weights
메서드를 사용합니다. tf.keras
는, 특히 save_weights
는 .ckpt 확장자를 가진 텐서플로 체크포인트 포맷을 사용합니다(.h5
확장자의 HDF5으로 저장하는 것은 Save and serialize models 가이드에서 다룹니다):
In [ ]:
# 가중치를 저장합니다
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))
model.save 메서드를 호출하여 모델의 구조, 가중치, 훈련 설정을 하나의 파일/폴더에 저장합니다. 모델을 저장하기 때문에 원본 파이썬 코드*가 없어도 사용할 수 있습니다. 옵티마이저 상태가 복원되므로 정확히 중지한 시점에서 다시 훈련을 시작할 수 있습니다.
두 개의 포맷(SavedModel
과 HDF5
)으로 모델을 저장할 수 있습니다. 텐서플로의 SavedModel
포맷은 TF2.x에서기본 파일 포맷입니다. 하지만 HDF5
포맷으로 저장할 수도 있습니다. 두 파일 포맷으로 전체 모델을 저장하는 방법은 아래에서 자세히 설명합니다.
전체 모델을 저장하는 기능은 매우 유용합니다. TensorFlow.js로 모델을 로드한 다음 웹 브라우저에서 모델을 훈련하고 실행할 수 있습니다(Saved Model, HDF5). 또는 모바일 장치에 맞도록 변환한 다음 TensorFlow Lite를 사용하여 실행할 수 있습니다(Saved Model, HDF5).
* 사용자 정의 객체(예를 들면 상속으로 만든 클래스나 층)는 저장하고 로드하는데 특별한 주의가 필요합니다. 아래 사용자 정의 객체 저장하기 섹션을 참고하세요.
SavedModel 포맷은 모데을 직렬화하는 다른 방법입니다. 이 포맷으로 저장한 모델은 tf.keras.models.load_model
로 복원할 수 있고 텐서플로 서빙과 호환됩니다. SavedModel 가이드에서 SavedModel를 서빙하고 점검하는 자세한 방법을 제공합니다. 이 섹션에서는 모델을 저장하고 복원하는 방법을 안내하겠습니다.
In [ ]:
# 새로운 모델 객체를 만들고 훈련합니다
model = create_model()
model.fit(train_images, train_labels, epochs=5)
# SavedModel로 전체 모델을 저장합니다
!mkdir -p saved_model
model.save('saved_model/my_model')
SavedModel 포맷은 프로토콜 버퍼 이진 파일과 텐서플로 체크포인트를 담고 있는 디렉토리입니다. 저장된 모델의 디렉토리를 확인해 보죠:
In [ ]:
# my_model 디렉토리
!ls saved_model
# assests 폴더, saved_model.pb, variables 폴더
!ls saved_model/my_model
저장된 모델로부터 새로운 케라스 모델을 로드합니다:
In [ ]:
new_model = tf.keras.models.load_model('saved_model/my_model')
# 모델 구조를 확인합니다
new_model.summary()
복원된 모델은 원본 모델과 동일한 매개변수로 컴파일되어 있습니다. 이 모델을 평가하고 예측에 사용해 보죠:
In [ ]:
# 복원된 모델을 평가합니다
loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)
print('복원된 모델의 정확도: {:5.2f}%'.format(100*acc))
print(new_model.predict(test_images).shape)
케라스는 HDF5 표준을 따르는 기본 저장 포맷을 제공합니다.
In [ ]:
# 새로운 모델 객체를 만들고 훈련합니다
model = create_model()
model.fit(train_images, train_labels, epochs=5)
# 전체 모델을 HDF5 파일로 저장합니다
# '.h5' 확장자는 이 모델이 HDF5로 저장되었다는 것을 나타냅니다
model.save('my_model.h5')
이제 이 파일로부터 모델을 다시 만들어 보죠:
In [ ]:
# 가중치와 옵티마이저를 포함하여 정확히 동일한 모델을 다시 생성합니다
new_model = tf.keras.models.load_model('my_model.h5')
# 모델 구조를 출력합니다
new_model.summary()
정확도를 확인해 보겠습니다:
In [ ]:
loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)
print('복원된 모델의 정확도: {:5.2f}%'.format(100*acc))
케라스는 모델 구조를 파악하여 저장합니다. 이 방식은 다음과 같은 모든 것을 저장합니다:
체크포인트가 호환되지 않기 때문에 케라스는 v1.x 옵티마이저(tf.compat.v1.train
)를 저장할 수 없습니다. v1.x 옵티마이저를 사용하려면 로드한 후에 모델을 다시 컴파일해야 합니다. 따라서 옵티마이저의 상태를 잃게 됩니다.
SaveModel 포맷을 사용한다면 이 섹션은 건너 뛰어도 됩니다. HDF5와 SavedModel 사이의 주요 차이점은 HDF5가 객체로 모델 구조를 저장하고 SavedModel은 실행 그래프로 저장하는 것입니다. 따라서 SavedModel은 원본 코드 없이 상속 모델과 사용자 정의 층 같은 사용자 정의 객체를 저장할 수 있습니다.
사용자 정의 객체를 HDF5로 저장하려면 다음 과정을 따르세요:
get_config
메서드를 정의하고 선택적으로 from_config
클래스 메서드를 정의합니다. get_config(self)
는 객체를 다시 생성하기 위해 필요한 JSON 직렬화된 매개변수 딕셔너리를 반환합니다.from_config(cls, config)
는 get_config
에서 반환된 설정을 사용해 새로운 객체를 만듭니다. 기본적으로 이 함수는 이 설정을 초기화 메서드의 매개변수로 사용합니다(return cls(**config)
).custom_objects
매개변수로 전달합니다. 문자열 클래스 이름과 파이썬 클래스를 매핑한 딕서너리를 매개변수로 제공해야 합니다. 예를 들면 tf.keras.models.load_model(path, custom_objects={'CustomLayer': CustomLayer})
사용자 정의 객체와 get_config
에 관한 예제를 보려면 Writing layers and models from scratch 튜토리얼을 참고하세요.