{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "g_nWetWWd_ns" }, "source": [ "##### Copyright 2019 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-14T20:23:00.927464Z", "iopub.status.busy": "2022-12-14T20:23:00.927011Z", "iopub.status.idle": "2022-12-14T20:23:00.931196Z", "shell.execute_reply": "2022-12-14T20:23:00.930537Z" }, "id": "2pHVBk_seED1" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-14T20:23:00.934781Z", "iopub.status.busy": "2022-12-14T20:23:00.934239Z", "iopub.status.idle": "2022-12-14T20:23:00.937687Z", "shell.execute_reply": "2022-12-14T20:23:00.937101Z" }, "id": "N_fMsQ-N8I7j" }, "outputs": [], "source": [ "#@title MIT License\n", "#\n", "# Copyright (c) 2017 François Chollet\n", "#\n", "# Permission is hereby granted, free of charge, to any person obtaining a\n", "# copy of this software and associated documentation files (the \"Software\"),\n", "# to deal in the Software without restriction, including without limitation\n", "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n", "# and/or sell copies of the Software, and to permit persons to whom the\n", "# Software is furnished to do so, subject to the following conditions:\n", "#\n", "# The above copyright notice and this permission notice shall be included in\n", "# all copies or substantial portions of the Software.\n", "#\n", "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n", "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n", "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n", "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n", "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n", "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n", "# DEALINGS IN THE SOFTWARE." ] }, { "cell_type": "markdown", "metadata": { "id": "pZJ3uY9O17VN" }, "source": [ "# 모델 저장과 복원" ] }, { "cell_type": "markdown", "metadata": { "id": "M4Ata7_wMul1" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
TensorFlow.org에서 보기Google Colab에서 실행하기GitHub에서 소스 보기노트북 다운로드하기
" ] }, { "cell_type": "markdown", "metadata": { "id": "mBdde4YJeJKF" }, "source": [ "모델 진행 상황은 훈련 중 및 훈련 후에 저장할 수 있습니다. 즉, 모델이 중단된 위치에서 다시 시작하고 긴 훈련 시간을 피할 수 있습니다. 저장은 또한 모델을 공유할 수 있고 다른 사람들이 작업을 다시 만들 수 있음을 의미합니다. 연구 모델 및 기술을 게시할 때 대부분의 머신러닝 실무자는 다음을 공유합니다.\n", "\n", "- 모델을 만드는 코드\n", "- 모델의 훈련된 가중치 또는 파라미터\n", "\n", "이런 데이터를 공유하면 다른 사람들이 모델의 작동 방식을 이해하고 새로운 데이터로 모델을 실험하는데 도움이 됩니다.\n", "\n", "주의: TensorFlow 모델은 코드이며 신뢰할 수 없는 코드에 주의하는 것이 중요합니다. 자세한 내용은 [TensorFlow 안전하게 사용하기](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md)를 참조하세요.\n", "\n", "### 저장 방식\n", "\n", "사용 중인 API에 따라 TensorFlow 모델을 저장하는 다양한 방법이 있습니다. 이 가이드에서는 TensorFlow에서 모델을 빌드하고 훈련하는 고급 API인 [tf.keras](https://www.tensorflow.org/guide/keras)를 사용합니다. 다른 접근 방식에 대해서는 [SavedModel 형식 사용 가이드](../../guide/saved_model.ipynb) 및 [Keras 모델 저장 및 로드 가이드](https://www.tensorflow.org/guide/keras/save_and_serialize)를 참조하세요." ] }, { "cell_type": "markdown", "metadata": { "id": "xCUREq7WXgvg" }, "source": [ "## 설정\n", "\n", "### 설치와 임포트" ] }, { "cell_type": "markdown", "metadata": { "id": "7l0MiTOrXtNv" }, "source": [ "필요한 라이브러리를 설치하고 텐서플로를 임포트(import)합니다:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:00.941521Z", "iopub.status.busy": "2022-12-14T20:23:00.941050Z", "iopub.status.idle": "2022-12-14T20:23:02.588875Z", "shell.execute_reply": "2022-12-14T20:23:02.587912Z" }, "id": "RzIOVSdnMYyO" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: pyyaml in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (6.0)\r\n", "Requirement already satisfied: h5py in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (3.7.0)\r\n", "Requirement already satisfied: numpy>=1.14.5 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from h5py) (1.24.0rc2)\r\n" ] } ], "source": [ "!pip install pyyaml h5py # Required to save models in HDF5 format" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:02.593863Z", "iopub.status.busy": "2022-12-14T20:23:02.593142Z", "iopub.status.idle": "2022-12-14T20:23:04.731800Z", "shell.execute_reply": "2022-12-14T20:23:04.731051Z" }, "id": "7Nm7Tyb-gRt-" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 20:23:03.644578: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 20:23:03.644690: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 20:23:03.644701: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2.11.0\n" ] } ], "source": [ "import os\n", "\n", "import tensorflow as tf\n", "from tensorflow import keras\n", "\n", "print(tf.version.VERSION)" ] }, { "cell_type": "markdown", "metadata": { "id": "SbGsznErXWt6" }, "source": [ "### 예제 데이터셋 받기\n", "\n", "[MNIST 데이터셋](http://yann.lecun.com/exdb/mnist/)으로 모델을 훈련하여 가중치를 저장하는 예제를 만들어 보겠습니다. 모델 실행 속도를 빠르게 하기 위해 샘플에서 처음 1,000개만 사용겠습니다:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:04.736077Z", "iopub.status.busy": "2022-12-14T20:23:04.735321Z", "iopub.status.idle": "2022-12-14T20:23:05.173652Z", "shell.execute_reply": "2022-12-14T20:23:05.172806Z" }, "id": "9rGfFwE9XVwz" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 8192/11490434 [..............................] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 7503872/11490434 [==================>...........] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "11490434/11490434 [==============================] - 0s 0us/step\n" ] } ], "source": [ "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n", "\n", "train_labels = train_labels[:1000]\n", "test_labels = test_labels[:1000]\n", "\n", "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n", "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0" ] }, { "cell_type": "markdown", "metadata": { "id": "anG3iVoXyZGI" }, "source": [ "### 모델 정의" ] }, { "cell_type": "markdown", "metadata": { "id": "wynsOBfby0Pa" }, "source": [ "먼저 간단한 모델을 하나 만들어 보죠." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:05.178538Z", "iopub.status.busy": "2022-12-14T20:23:05.177958Z", "iopub.status.idle": "2022-12-14T20:23:08.860875Z", "shell.execute_reply": "2022-12-14T20:23:08.860169Z" }, "id": "0HZbJIjxyX1S" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Layer (type) Output Shape Param # \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense (Dense) (None, 512) 401920 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dropout (Dropout) (None, 512) 0 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense_1 (Dense) (None, 10) 5130 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Total params: 407,050\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Trainable params: 407,050\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Non-trainable params: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] } ], "source": [ "# Define a simple sequential model\n", "def create_model():\n", " model = tf.keras.Sequential([\n", " keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n", " keras.layers.Dropout(0.2),\n", " keras.layers.Dense(10)\n", " ])\n", "\n", " model.compile(optimizer='adam',\n", " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", " metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])\n", "\n", " return model\n", "\n", "# Create a basic model instance\n", "model = create_model()\n", "\n", "# Display the model's architecture\n", "model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "soDE0W_KH8rG" }, "source": [ "## 훈련하는 동안 체크포인트 저장하기" ] }, { "cell_type": "markdown", "metadata": { "id": "mRyd5qQQIXZm" }, "source": [ "훈련된 모델을 다시 훈련할 필요 없이 사용하거나 훈련 과정이 중단된 경우 중단한 부분에서 훈련을 다시 시작할 수 있습니다. `tf.keras.callbacks.ModelCheckpoint` 콜백을 사용하면 훈련 *도중* 또는 훈련 *종료 시* 모델을 지속적으로 저장할 수 있습니다.\n", "\n", "### 체크포인트 콜백 사용하기\n", "\n", "훈련하는 동안 가중치를 저장하기 위해 `ModelCheckpoint` 콜백을 만들어 보죠:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:08.868200Z", "iopub.status.busy": "2022-12-14T20:23:08.867628Z", "iopub.status.idle": "2022-12-14T20:23:12.484476Z", "shell.execute_reply": "2022-12-14T20:23:12.483460Z" }, "id": "IFPuhwntH8VH" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 45s - loss: 2.2989 - sparse_categorical_accuracy: 0.1562" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "22/32 [===================>..........] - ETA: 0s - loss: 1.4028 - sparse_categorical_accuracy: 0.5909 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 1: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 2s 12ms/step - loss: 1.1664 - sparse_categorical_accuracy: 0.6690 - val_loss: 0.7275 - val_sparse_categorical_accuracy: 0.7790\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.5949 - sparse_categorical_accuracy: 0.8125" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.4540 - sparse_categorical_accuracy: 0.8723" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 2: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.4351 - sparse_categorical_accuracy: 0.8760 - val_loss: 0.5317 - val_sparse_categorical_accuracy: 0.8380\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.2466 - sparse_categorical_accuracy: 0.9375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "24/32 [=====================>........] - ETA: 0s - loss: 0.2708 - sparse_categorical_accuracy: 0.9284" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 3: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.2764 - sparse_categorical_accuracy: 0.9310 - val_loss: 0.4818 - val_sparse_categorical_accuracy: 0.8520\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.1013 - sparse_categorical_accuracy: 1.0000" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "24/32 [=====================>........] - ETA: 0s - loss: 0.2057 - sparse_categorical_accuracy: 0.9505" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 4: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.2113 - sparse_categorical_accuracy: 0.9500 - val_loss: 0.4803 - val_sparse_categorical_accuracy: 0.8430\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.0955 - sparse_categorical_accuracy: 1.0000" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.1490 - sparse_categorical_accuracy: 0.9674" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 5: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.1482 - sparse_categorical_accuracy: 0.9680 - val_loss: 0.4408 - val_sparse_categorical_accuracy: 0.8580\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 6/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.1782 - sparse_categorical_accuracy: 0.9688" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.1195 - sparse_categorical_accuracy: 0.9796" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 6: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.1105 - sparse_categorical_accuracy: 0.9810 - val_loss: 0.4570 - val_sparse_categorical_accuracy: 0.8560\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 7/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.1126 - sparse_categorical_accuracy: 0.9688" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.0786 - sparse_categorical_accuracy: 0.9905" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 7: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.0857 - sparse_categorical_accuracy: 0.9840 - val_loss: 0.4329 - val_sparse_categorical_accuracy: 0.8720\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 8/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.1016 - sparse_categorical_accuracy: 0.9688" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.0713 - sparse_categorical_accuracy: 0.9891" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 8: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.0707 - sparse_categorical_accuracy: 0.9880 - val_loss: 0.4151 - val_sparse_categorical_accuracy: 0.8670\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 9/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.0686 - sparse_categorical_accuracy: 1.0000" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.0484 - sparse_categorical_accuracy: 0.9946" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 9: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.0481 - sparse_categorical_accuracy: 0.9960 - val_loss: 0.4199 - val_sparse_categorical_accuracy: 0.8740\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 10/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.0195 - sparse_categorical_accuracy: 1.0000" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "22/32 [===================>..........] - ETA: 0s - loss: 0.0325 - sparse_categorical_accuracy: 1.0000" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 10: saving model to training_1/cp.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 6ms/step - loss: 0.0331 - sparse_categorical_accuracy: 1.0000 - val_loss: 0.4082 - val_sparse_categorical_accuracy: 0.8750\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "checkpoint_path = \"training_1/cp.ckpt\"\n", "checkpoint_dir = os.path.dirname(checkpoint_path)\n", "\n", "# Create a callback that saves the model's weights\n", "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n", " save_weights_only=True,\n", " verbose=1)\n", "\n", "# Train the model with the new callback\n", "model.fit(train_images, \n", " train_labels, \n", " epochs=10,\n", " validation_data=(test_images, test_labels),\n", " callbacks=[cp_callback]) # Pass callback to training\n", "\n", "# This may generate warnings related to saving the state of the optimizer.\n", "# These warnings (and similar warnings throughout this notebook)\n", "# are in place to discourage outdated usage, and can be ignored." ] }, { "cell_type": "markdown", "metadata": { "id": "rlM-sgyJO084" }, "source": [ "이 코드는 텐서플로 체크포인트 파일을 만들고 에포크가 종료될 때마다 업데이트합니다:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:12.488051Z", "iopub.status.busy": "2022-12-14T20:23:12.487772Z", "iopub.status.idle": "2022-12-14T20:23:12.493503Z", "shell.execute_reply": "2022-12-14T20:23:12.492597Z" }, "id": "gXG5FVKFOVQ3" }, "outputs": [ { "data": { "text/plain": [ "['cp.ckpt.index', 'checkpoint', 'cp.ckpt.data-00000-of-00001']" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "os.listdir(checkpoint_dir)" ] }, { "cell_type": "markdown", "metadata": { "id": "wlRN_f56Pqa9" }, "source": [ "두 모델이 동일한 아키텍처를 공유하기만 한다면 두 모델 간에 가중치를 공유할 수 있습니다. 따라서 가중치 전용에서 모델을 복원할 때 원래 모델과 동일한 아키텍처로 모델을 만든 다음 가중치를 설정합니다.\n", "\n", "이제 훈련되지 않은 새로운 모델을 다시 빌드하고 테스트 세트에서 평가합니다. 훈련되지 않은 모델은 확률 수준(~10% 정확도)에서 수행됩니다." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:12.497234Z", "iopub.status.busy": "2022-12-14T20:23:12.496746Z", "iopub.status.idle": "2022-12-14T20:23:12.737819Z", "shell.execute_reply": "2022-12-14T20:23:12.737083Z" }, "id": "Fp5gbuiaPqCT" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32/32 - 0s - loss: 2.4037 - sparse_categorical_accuracy: 0.0760 - 164ms/epoch - 5ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Untrained model, accuracy: 7.60%\n" ] } ], "source": [ "# Create a basic model instance\n", "model = create_model()\n", "\n", "# Evaluate the model\n", "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", "print(\"Untrained model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { "cell_type": "markdown", "metadata": { "id": "1DTKpZssRSo3" }, "source": [ "체크포인트에서 가중치를 로드하고 다시 평가해 보죠:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:12.741771Z", "iopub.status.busy": "2022-12-14T20:23:12.741076Z", "iopub.status.idle": "2022-12-14T20:23:12.870837Z", "shell.execute_reply": "2022-12-14T20:23:12.870021Z" }, "id": "2IZxbwiRRSD2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32/32 - 0s - loss: 0.4082 - sparse_categorical_accuracy: 0.8750 - 75ms/epoch - 2ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Restored model, accuracy: 87.50%\n" ] } ], "source": [ "# Loads the weights\n", "model.load_weights(checkpoint_path)\n", "\n", "# Re-evaluate the model\n", "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { "cell_type": "markdown", "metadata": { "id": "bpAbKkAyVPV8" }, "source": [ "### 체크포인트 콜백 매개변수\n", "\n", "이 콜백 함수는 몇 가지 매개변수를 제공합니다. 체크포인트 이름을 고유하게 만들거나 체크포인트 주기를 조정할 수 있습니다.\n", "\n", "새로운 모델을 훈련하고 다섯 번의 에포크마다 고유한 이름으로 체크포인트를 저장해 보겠습니다:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:12.874592Z", "iopub.status.busy": "2022-12-14T20:23:12.874069Z", "iopub.status.idle": "2022-12-14T20:23:21.284688Z", "shell.execute_reply": "2022-12-14T20:23:21.283905Z" }, "id": "mQF_dlgIVOvq" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 5: saving model to training_2/cp-0005.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 10: saving model to training_2/cp-0010.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 15: saving model to training_2/cp-0015.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 20: saving model to training_2/cp-0020.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 25: saving model to training_2/cp-0025.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 30: saving model to training_2/cp-0030.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 35: saving model to training_2/cp-0035.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 40: saving model to training_2/cp-0040.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 45: saving model to training_2/cp-0045.ckpt\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Epoch 50: saving model to training_2/cp-0050.ckpt\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Include the epoch in the file name (uses `str.format`)\n", "checkpoint_path = \"training_2/cp-{epoch:04d}.ckpt\"\n", "checkpoint_dir = os.path.dirname(checkpoint_path)\n", "\n", "batch_size = 32\n", "\n", "# Create a callback that saves the model's weights every 5 epochs\n", "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n", " filepath=checkpoint_path, \n", " verbose=1, \n", " save_weights_only=True,\n", " save_freq=5*batch_size)\n", "\n", "# Create a new model instance\n", "model = create_model()\n", "\n", "# Save the weights using the `checkpoint_path` format\n", "model.save_weights(checkpoint_path.format(epoch=0))\n", "\n", "# Train the model with the new callback\n", "model.fit(train_images, \n", " train_labels,\n", " epochs=50, \n", " batch_size=batch_size, \n", " callbacks=[cp_callback],\n", " validation_data=(test_images, test_labels),\n", " verbose=0)" ] }, { "cell_type": "markdown", "metadata": { "id": "1zFrKTjjavWI" }, "source": [ "이제 결과로 나온 체크포인트를 검토하고 최신 체크포인트를 선택합니다." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:21.288736Z", "iopub.status.busy": "2022-12-14T20:23:21.288172Z", "iopub.status.idle": "2022-12-14T20:23:21.293224Z", "shell.execute_reply": "2022-12-14T20:23:21.292619Z" }, "id": "p64q3-V4sXt0" }, "outputs": [ { "data": { "text/plain": [ "['cp-0040.ckpt.data-00000-of-00001',\n", " 'cp-0020.ckpt.index',\n", " 'cp-0000.ckpt.data-00000-of-00001',\n", " 'cp-0030.ckpt.index',\n", " 'cp-0050.ckpt.index',\n", " 'cp-0025.ckpt.index',\n", " 'cp-0010.ckpt.data-00000-of-00001',\n", " 'cp-0030.ckpt.data-00000-of-00001',\n", " 'cp-0000.ckpt.index',\n", " 'cp-0050.ckpt.data-00000-of-00001',\n", " 'cp-0005.ckpt.index',\n", " 'cp-0015.ckpt.data-00000-of-00001',\n", " 'cp-0025.ckpt.data-00000-of-00001',\n", " 'cp-0035.ckpt.index',\n", " 'cp-0015.ckpt.index',\n", " 'cp-0005.ckpt.data-00000-of-00001',\n", " 'checkpoint',\n", " 'cp-0010.ckpt.index',\n", " 'cp-0045.ckpt.index',\n", " 'cp-0045.ckpt.data-00000-of-00001',\n", " 'cp-0035.ckpt.data-00000-of-00001',\n", " 'cp-0020.ckpt.data-00000-of-00001',\n", " 'cp-0040.ckpt.index']" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "os.listdir(checkpoint_dir)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:21.296581Z", "iopub.status.busy": "2022-12-14T20:23:21.295991Z", "iopub.status.idle": "2022-12-14T20:23:21.300984Z", "shell.execute_reply": "2022-12-14T20:23:21.300372Z" }, "id": "1AN_fnuyR41H" }, "outputs": [ { "data": { "text/plain": [ "'training_2/cp-0050.ckpt'" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "latest = tf.train.latest_checkpoint(checkpoint_dir)\n", "latest" ] }, { "cell_type": "markdown", "metadata": { "id": "Zk2ciGbKg561" }, "source": [ "참고: 기본 TensorFlow 형식은 가장 최근의 체크포인트 5개만 저장합니다.\n", "\n", "테스트를 위해 모델을 재설정하고 최신 체크포인트를 로드합니다." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:21.304682Z", "iopub.status.busy": "2022-12-14T20:23:21.304077Z", "iopub.status.idle": "2022-12-14T20:23:21.557397Z", "shell.execute_reply": "2022-12-14T20:23:21.556610Z" }, "id": "3M04jyK-H3QK" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32/32 - 0s - loss: 0.4952 - sparse_categorical_accuracy: 0.8790 - 169ms/epoch - 5ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Restored model, accuracy: 87.90%\n" ] } ], "source": [ "# Create a new model instance\n", "model = create_model()\n", "\n", "# Load the previously saved weights\n", "model.load_weights(latest)\n", "\n", "# Re-evaluate the model\n", "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { "cell_type": "markdown", "metadata": { "id": "c2OxsJOTHxia" }, "source": [ "## 이 파일들은 무엇인가요?" ] }, { "cell_type": "markdown", "metadata": { "id": "JtdYhvWnH2ib" }, "source": [ "위의 코드는 이진 형식의 훈련된 가중치만 포함하는 [체크포인트](../../guide/checkpoint.ipynb) 형식의 파일 모음에 가중치를 저장합니다. 체크포인트에는 다음이 포함됩니다.\n", "\n", "- 모델의 가중치를 포함하는 하나 이상의 샤드\n", "- 어떤 가중치가 어떤 샤드에 저장되어 있는지 나타내는 인덱스 파일\n", "\n", "단일 머신에서 모델을 훈련하는 경우 접미사가 `.data-00000-of-00001`인 하나의 샤드를 갖게 됩니다." ] }, { "cell_type": "markdown", "metadata": { "id": "S_FA-ZvxuXQV" }, "source": [ "## 수동으로 가중치 저장하기\n", "\n", "가중치를 수동으로 저장하려면 `tf.keras.Model.save_weights`를 사용합니다. 기본적으로 `tf.keras`, 그리고 특히 `Model.save_weights` 메서드는 .ckpt 확장자가 있는 TensorFlow 체크포인트 형식을 사용합니다. `.h5` 확장자를 사용하여 HDF5 형식으로 저장하려면 [모델 저장 및 로드](https://www.tensorflow.org/guide/keras/save_and_serialize) 가이드를 참조하세요." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:21.561533Z", "iopub.status.busy": "2022-12-14T20:23:21.560963Z", "iopub.status.idle": "2022-12-14T20:23:21.824898Z", "shell.execute_reply": "2022-12-14T20:23:21.824117Z" }, "id": "R7W5plyZ-u9X" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32/32 - 0s - loss: 0.4952 - sparse_categorical_accuracy: 0.8790 - 166ms/epoch - 5ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Restored model, accuracy: 87.90%\n" ] } ], "source": [ "# Save the weights\n", "model.save_weights('./checkpoints/my_checkpoint')\n", "\n", "# Create a new model instance\n", "model = create_model()\n", "\n", "# Restore the weights\n", "model.load_weights('./checkpoints/my_checkpoint')\n", "\n", "# Evaluate the model\n", "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { "cell_type": "markdown", "metadata": { "id": "kOGlxPRBEvV1" }, "source": [ "## 전체 모델 저장하기\n", "\n", "`tf.keras.Model.save`를 호출하여 단일 `file/folder`에 모델의 아키텍처, 가중치 및 훈련 구성을 저장합니다. 이렇게 하면 원본 Python 코드에 액세스하지 않고도 사용할 수 있도록 모델을 내보낼 수 있습니다.* 옵티마이저 상태가 복구되므로 중단했던 지점부터 훈련을 재개할 수 있습니다.\n", "\n", "전체 모델은 두 가지 다른 파일 형식(`SavedModel` 및 `HDF5`)으로 저장할 수 있습니다. TensorFlow `SavedModel` 형식은 TF2.x의 기본 파일 형식입니다. 그러나 모델을 `HDF5` 형식으로 저장할 수 있습니다. 전체 모델을 두 가지 파일 형식으로 저장하는 방법에 대한 자세한 내용은 아래에 설명되어 있습니다.\n", "\n", "완전한 기능의 모델을 저장하는 것은 매우 유용합니다. 즉, TensorFlow.js([저장된 모델](https://www.tensorflow.org/js/tutorials/conversion/import_saved_model), [HDF5](https://www.tensorflow.org/js/tutorials/conversion/import_keras))에서 로드한 다음 웹 브라우저에서 훈련 및 실행하거나 TensorFlow Lite([저장된 모델](https://www.tensorflow.org/lite/models/convert/#convert_a_savedmodel_recommended_), [HDF5](https://www.tensorflow.org/lite/models/convert/#convert_a_keras_model_))를 사용하여 모바일 장치에서 실행되도록 변환할 수 있습니다.\n", "\n", "*사용자 정의 객체(예: 하위 클래싱된 모델 또는 레이어)는 저장 및 로드할 때 특별한 주의가 필요합니다. 아래의 **사용자 정의 객체 저장하기** 섹션을 참조하세요." ] }, { "cell_type": "markdown", "metadata": { "id": "kPyhgcoVzqUB" }, "source": [ "### SavedModel 포맷" ] }, { "cell_type": "markdown", "metadata": { "id": "LtcN4VIb7JkK" }, "source": [ "SavedModel 형식은 모델을 직렬화하는 또 다른 방법입니다. 이 형식으로 저장된 모델은 `tf.keras.models.load_model`을 사용하여 복원할 수 있으며 TensorFlow Serving과 호환됩니다. [SavedModel 가이드](../../guide/saved_model.ipynb)에 SavedModel을 제공/검사하는 방법이 자세히 설명되어 있습니다. 아래 섹션은 모델을 저장하고 복원하는 단계를 보여줍니다." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:21.829042Z", "iopub.status.busy": "2022-12-14T20:23:21.828434Z", "iopub.status.idle": "2022-12-14T20:23:23.898642Z", "shell.execute_reply": "2022-12-14T20:23:23.897753Z" }, "id": "sI1YvCDFzpl3" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Detecting that an object or model or tf.train.Checkpoint is being deleted with unrestored values. See the following logs for the specific values in question. To silence these warnings, use `status.expect_partial()`. See https://www.tensorflow.org/api_docs/python/tf/train/Checkpoint#restorefor details about the status object returned by the restore function.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.6\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.7\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Value in checkpoint could not be found in the restored object: (root).optimizer._variables.8\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 23s - loss: 2.4248 - sparse_categorical_accuracy: 0.0938" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 1.3202 - sparse_categorical_accuracy: 0.6440 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 1s 2ms/step - loss: 1.1550 - sparse_categorical_accuracy: 0.6920\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.4617 - sparse_categorical_accuracy: 0.8750" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "24/32 [=====================>........] - ETA: 0s - loss: 0.4221 - sparse_categorical_accuracy: 0.8906" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.4072 - sparse_categorical_accuracy: 0.8950\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.4280 - sparse_categorical_accuracy: 0.9062" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "24/32 [=====================>........] - ETA: 0s - loss: 0.3102 - sparse_categorical_accuracy: 0.9245" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.2911 - sparse_categorical_accuracy: 0.9220\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.2092 - sparse_categorical_accuracy: 0.9375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "22/32 [===================>..........] - ETA: 0s - loss: 0.2035 - sparse_categorical_accuracy: 0.9574" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.1990 - sparse_categorical_accuracy: 0.9580\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.2438 - sparse_categorical_accuracy: 0.9375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.1655 - sparse_categorical_accuracy: 0.9592" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.1525 - sparse_categorical_accuracy: 0.9630\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: saved_model/my_model/assets\n" ] } ], "source": [ "# Create and train a new model instance.\n", "model = create_model()\n", "model.fit(train_images, train_labels, epochs=5)\n", "\n", "# Save the entire model as a SavedModel.\n", "!mkdir -p saved_model\n", "model.save('saved_model/my_model') " ] }, { "cell_type": "markdown", "metadata": { "id": "iUvT_3qE8hV5" }, "source": [ "SavedModel 형식은 protobuf 바이너리와 TensorFlow 체크포인트를 포함하는 디렉토리입니다. 저장된 모델 디렉토리를 검사합니다." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:23.903183Z", "iopub.status.busy": "2022-12-14T20:23:23.902492Z", "iopub.status.idle": "2022-12-14T20:23:24.263104Z", "shell.execute_reply": "2022-12-14T20:23:24.261913Z" }, "id": "sq8fPglI1RWA" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "my_model\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "assets\tfingerprint.pb\tkeras_metadata.pb saved_model.pb variables\r\n" ] } ], "source": [ "# my_model directory\n", "!ls saved_model\n", "\n", "# Contains an assets folder, saved_model.pb, and variables folder.\n", "!ls saved_model/my_model" ] }, { "cell_type": "markdown", "metadata": { "id": "B7qfpvpY9HCe" }, "source": [ "저장된 모델로부터 새로운 케라스 모델을 로드합니다:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:24.267855Z", "iopub.status.busy": "2022-12-14T20:23:24.267519Z", "iopub.status.idle": "2022-12-14T20:23:24.509684Z", "shell.execute_reply": "2022-12-14T20:23:24.508932Z" }, "id": "0YofwHdN0pxa" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential_5\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Layer (type) Output Shape Param # \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense_10 (Dense) (None, 512) 401920 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dropout_5 (Dropout) (None, 512) 0 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense_11 (Dense) (None, 10) 5130 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Total params: 407,050\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Trainable params: 407,050\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Non-trainable params: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] } ], "source": [ "new_model = tf.keras.models.load_model('saved_model/my_model')\n", "\n", "# Check its architecture\n", "new_model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "uWwgNaz19TH2" }, "source": [ "복원된 모델은 원본 모델과 동일한 매개변수로 컴파일되어 있습니다. 이 모델을 평가하고 예측에 사용해 보죠:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:24.517024Z", "iopub.status.busy": "2022-12-14T20:23:24.516414Z", "iopub.status.idle": "2022-12-14T20:23:24.946495Z", "shell.execute_reply": "2022-12-14T20:23:24.945565Z" }, "id": "Yh5Mu0yOgE5J" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32/32 - 0s - loss: 0.4686 - sparse_categorical_accuracy: 0.8520 - 174ms/epoch - 5ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Restored model, accuracy: 85.20%\n", "\r", " 1/32 [..............................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 1ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "(1000, 10)\n" ] } ], "source": [ "# Evaluate the restored model\n", "loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)\n", "print('Restored model, accuracy: {:5.2f}%'.format(100 * acc))\n", "\n", "print(new_model.predict(test_images).shape)" ] }, { "cell_type": "markdown", "metadata": { "id": "SkGwf-50zLNn" }, "source": [ "### HDF5 파일로 저장하기\n", "\n", "케라스는 [HDF5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format) 표준을 따르는 기본 저장 포맷을 제공합니다. " ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:24.950129Z", "iopub.status.busy": "2022-12-14T20:23:24.949827Z", "iopub.status.idle": "2022-12-14T20:23:26.253725Z", "shell.execute_reply": "2022-12-14T20:23:26.252899Z" }, "id": "m2dkmJVCGUia" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 23s - loss: 2.4508 - sparse_categorical_accuracy: 0.0938" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "21/32 [==================>...........] - ETA: 0s - loss: 1.4227 - sparse_categorical_accuracy: 0.5848 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 1s 3ms/step - loss: 1.1802 - sparse_categorical_accuracy: 0.6620\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.4583 - sparse_categorical_accuracy: 0.8125" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.4319 - sparse_categorical_accuracy: 0.8641" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.4295 - sparse_categorical_accuracy: 0.8750\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.2316 - sparse_categorical_accuracy: 0.9375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.2780 - sparse_categorical_accuracy: 0.9334" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.2942 - sparse_categorical_accuracy: 0.9270\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.1834 - sparse_categorical_accuracy: 0.9375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.2171 - sparse_categorical_accuracy: 0.9470" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.2196 - sparse_categorical_accuracy: 0.9490\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/32 [..............................] - ETA: 0s - loss: 0.1569 - sparse_categorical_accuracy: 0.9688" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "23/32 [====================>.........] - ETA: 0s - loss: 0.1565 - sparse_categorical_accuracy: 0.9647" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "32/32 [==============================] - 0s 2ms/step - loss: 0.1616 - sparse_categorical_accuracy: 0.9650\n" ] } ], "source": [ "# Create and train a new model instance.\n", "model = create_model()\n", "model.fit(train_images, train_labels, epochs=5)\n", "\n", "# Save the entire model to a HDF5 file.\n", "# The '.h5' extension indicates that the model should be saved to HDF5.\n", "model.save('my_model.h5') " ] }, { "cell_type": "markdown", "metadata": { "id": "GWmttMOqS68S" }, "source": [ "이제 이 파일로부터 모델을 다시 만들어 보죠:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:26.258043Z", "iopub.status.busy": "2022-12-14T20:23:26.257750Z", "iopub.status.idle": "2022-12-14T20:23:26.337374Z", "shell.execute_reply": "2022-12-14T20:23:26.336667Z" }, "id": "5NDMO_7kS6Do" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential_6\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Layer (type) Output Shape Param # \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense_12 (Dense) (None, 512) 401920 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dropout_6 (Dropout) (None, 512) 0 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " dense_13 (Dense) (None, 10) 5130 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "=================================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Total params: 407,050\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Trainable params: 407,050\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Non-trainable params: 0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n" ] } ], "source": [ "# Recreate the exact same model, including its weights and the optimizer\n", "new_model = tf.keras.models.load_model('my_model.h5')\n", "\n", "# Show the model architecture\n", "new_model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "JXQpbTicTBwt" }, "source": [ "정확도를 확인해 보겠습니다:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T20:23:26.343938Z", "iopub.status.busy": "2022-12-14T20:23:26.343636Z", "iopub.status.idle": "2022-12-14T20:23:26.560663Z", "shell.execute_reply": "2022-12-14T20:23:26.559793Z" }, "id": "jwEaj9DnTCVA" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32/32 - 0s - loss: 0.4311 - sparse_categorical_accuracy: 0.8640 - 171ms/epoch - 5ms/step\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Restored model, accuracy: 86.40%\n" ] } ], "source": [ "loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)\n", "print('Restored model, accuracy: {:5.2f}%'.format(100 * acc))" ] }, { "cell_type": "markdown", "metadata": { "id": "dGXqd4wWJl8O" }, "source": [ "Keras는 아키텍처를 검사하여 모델을 저장합니다. 이 기술은 모든 내용을 저장합니다.\n", "\n", "- 가중치 값\n", "- 모델 구조\n", "- 모델의 훈련 구성(`.compile()` 메서드에 전달하는 내용)\n", "- 존재하는 옵티마이저와 그 상태(훈련을 중단한 곳에서 다시 시작할 수 있게 해줌)\n", "\n", "체크포인트가 호환되지 않기 때문에 케라스는 v1.x 옵티마이저(`tf.compat.v1.train`)를 저장할 수 없습니다. v1.x 옵티마이저를 사용하려면 로드한 후에 모델을 다시 컴파일해야 합니다. 따라서 옵티마이저의 상태를 잃게 됩니다.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "kAUKJQyGqTNH" }, "source": [ "### 사용자 정의 객체\n", "\n", "SavedModel 형식을 사용하는 경우, 이 섹션을 건너뛸 수 있습니다. HDF5와 SavedModel의 주요 차이점은 HDF5는 객체 구성을 사용하여 모델 아키텍처를 저장하는 반면, SavedModel은 실행 그래프를 저장한다는 것입니다. 따라서 SavedModel은 원본 코드 없이도 서브클래싱된 모델 및 사용자 지정 레이어와 같은 사용자 지정 객체를 저장할 수 있습니다.\n", "\n", "사용자 정의 객체를 HDF5로 저장하려면 다음 과정을 따르세요:\n", "\n", "1. 이 객체에 `get_config` 메서드를 정의하고 선택적으로 `from_config` 클래스 메서드를 정의합니다.\n", " - `get_config(self)`는 객체를 다시 생성하기 위해 필요한 JSON 직렬화된 매개변수 딕셔너리를 반환합니다.\n", " - `from_config(cls, config)`는 `get_config`에서 반환된 설정을 사용해 새로운 객체를 만듭니다. 기본적으로 이 함수는 이 설정을 초기화 메서드의 매개변수로 사용합니다(`return cls(**config)`).\n", "2. 모델을 로드할 때 이 객체를 `custom_objects` 매개변수로 전달합니다. 문자열 클래스 이름과 파이썬 클래스를 매핑한 딕서너리를 매개변수로 제공해야 합니다. 예를 들면 `tf.keras.models.load_model(path, custom_objects={'CustomLayer': CustomLayer})`\n", "\n", "사용자 정의 객체 및 get_config의 예를 보려면 처음부터 레이어 및 모델 작성하기 튜토리얼을 참조하세요.\n" ] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "save_and_load.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" } }, "nbformat": 4, "nbformat_minor": 0 }