TensorFlow 2.0 : Beginner Tutorials : Keras ML 基本 :- モデルをセーブしてロードする (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/05/2019
* 本ページは、TensorFlow org サイトの TF 2.0 – Beginner Tutorials – ML basics with Keras の以下のページを翻訳した上で
適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
Keras ML 基本 :- モデルをセーブしてロードする
モデルの進捗は訓練の間に — そして後に — セーブすることが可能です。これは、モデルが (訓練を) 中止したところから再開できて長い訓練時間を回避できることを意味します。セービングはまた貴方がモデルを共有して他の人が貴方のワークを再作成できることもまた意味します。研究モデルとテクニックを公開するとき、多くの機械学習実践者は以下を共有します :
- モデルを作成するためのコード、そして
- モデルのために訓練された重み、またはパラメータ
このデータの共有は他の人たちがモデルがどのように動作するかを理解して新しいデータで彼ら自身がそれを試す手助けとなります。
Caution: 信頼できない (untrusted) コードに注意してください — TensorFlow モデルはコードです。詳細は Using TensorFlow Securely を見てください。
オプション
TensorFlow モデルをセーブする異なる方法があります — 貴方が使用している API に依拠します。このガイドは tf.keras, TensorFlow でモデルを構築して訓練するための高位 API を使用します。他のアプローチについては、TensorFlow Save and Restore ガイドや Saving in eager を見てください。
セットアップ
インストールとインポート
TensorFlow と依存関係をインストールしてインポートします :
!pip install -q pyyaml h5py # Required to save models in HDF5 format
from __future__ import absolute_import, division, print_function, unicode_literals import os import tensorflow as tf from tensorflow import keras print(tf.version.VERSION)
2.0.0
サンプル・データセットを取得する
重みをどのようにセーブしてロードするかを実演するために、MNIST データセット を使用します。これらの実行をスピードアップするために、最初の 1000 サンプルだけを使用します :
(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
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 11493376/11490434 [==============================] - 0s 0us/step
モデルを定義する
単純な sequential モデルを構築することで始めましょう。
# Define a simple sequential model 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, activation='softmax') ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) return model # Create a basic model instance model = create_model() # Display the model's architecture model.summary()
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 _________________________________________________________________
訓練の間にチェックポイントをセーブする
訓練されたモデルをそれを再訓練しなくても使用できたり、あるいは — 訓練プロセスが中断された場合には — 中止したところから訓練を選択することができます。tf.keras.callbacks.ModelCheckpoint コールバックは訓練の間と最後の両者でモデルを連続的にセーブすることを可能にします。
Checkpoint callback 使用方法
訓練の間だけに重みをセーブする tf.keras.callbacks.ModelCheckpoint コールバックを作成します :
checkpoint_path = "training_1/cp.ckpt" checkpoint_dir = os.path.dirname(checkpoint_path) # Create a callback that saves the model's weights cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path, save_weights_only=True, verbose=1) # Train the model with the new callback model.fit(train_images, train_labels, epochs=10, validation_data=(test_images,test_labels), callbacks=[cp_callback]) # Pass callback to training # This may generate warnings related to saving the state of the optimizer. # These warnings (and similar warnings throughout this notebook) # are in place to discourage outdated usage, and can be ignored.
Train on 1000 samples, validate on 1000 samples Epoch 1/10 672/1000 [===================>..........] - ETA: 0s - loss: 1.4858 - accuracy: 0.5789 Epoch 00001: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 1s 1ms/sample - loss: 1.2154 - accuracy: 0.6540 - val_loss: 0.7380 - val_accuracy: 0.7900 Epoch 2/10 704/1000 [====================>.........] - ETA: 0s - loss: 0.4405 - accuracy: 0.8750 Epoch 00002: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 187us/sample - loss: 0.4383 - accuracy: 0.8780 - val_loss: 0.5351 - val_accuracy: 0.8310 Epoch 3/10 672/1000 [===================>..........] - ETA: 0s - loss: 0.2541 - accuracy: 0.9375 Epoch 00003: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 207us/sample - loss: 0.2832 - accuracy: 0.9320 - val_loss: 0.4842 - val_accuracy: 0.8470 Epoch 4/10 704/1000 [====================>.........] - ETA: 0s - loss: 0.2369 - accuracy: 0.9418 Epoch 00004: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 196us/sample - loss: 0.2305 - accuracy: 0.9410 - val_loss: 0.4747 - val_accuracy: 0.8540 Epoch 5/10 672/1000 [===================>..........] - ETA: 0s - loss: 0.1562 - accuracy: 0.9702 Epoch 00005: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 199us/sample - loss: 0.1633 - accuracy: 0.9660 - val_loss: 0.4556 - val_accuracy: 0.8490 Epoch 6/10 704/1000 [====================>.........] - ETA: 0s - loss: 0.1330 - accuracy: 0.9716 Epoch 00006: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 195us/sample - loss: 0.1234 - accuracy: 0.9750 - val_loss: 0.4221 - val_accuracy: 0.8720 Epoch 7/10 672/1000 [===================>..........] - ETA: 0s - loss: 0.0936 - accuracy: 0.9866 Epoch 00007: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 199us/sample - loss: 0.0892 - accuracy: 0.9860 - val_loss: 0.4399 - val_accuracy: 0.8580 Epoch 8/10 704/1000 [====================>.........] - ETA: 0s - loss: 0.0704 - accuracy: 0.9915 Epoch 00008: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 194us/sample - loss: 0.0716 - accuracy: 0.9890 - val_loss: 0.4116 - val_accuracy: 0.8690 Epoch 9/10 672/1000 [===================>..........] - ETA: 0s - loss: 0.0466 - accuracy: 1.0000 Epoch 00009: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 195us/sample - loss: 0.0492 - accuracy: 0.9990 - val_loss: 0.4027 - val_accuracy: 0.8660 Epoch 10/10 672/1000 [===================>..........] - ETA: 0s - loss: 0.0433 - accuracy: 0.9970 Epoch 00010: saving model to training_1/cp.ckpt 1000/1000 [==============================] - 0s 197us/sample - loss: 0.0419 - accuracy: 0.9970 - val_loss: 0.4083 - val_accuracy: 0.8750 <tensorflow.python.keras.callbacks.History at 0x7face0242748>
これは、各エポックの最後に更新される TensorFlow チェックポイント・ファイルの単一のコレクションを作成します :
!ls {checkpoint_dir}
checkpoint cp.ckpt.data-00001-of-00002 cp.ckpt.data-00000-of-00002 cp.ckpt.index
新しい、未訓練のモデルを作成します。重みだけからモデルをリストアするときは、元のモデルと同じアーキテクチャを持つモデルを持たなければなりません。それは同じモデル・アーキテクチャですから、それがモデルの異なるインスタンスであるにもかかわらず重みを共有することができます。
さて未使用の、未訓練のモデルを再構築して、それをテストセット上で評価しましょう。未訓練モデルは偶然レベル (~10% 精度) で遂行します :
# Create a basic model instance model = create_model() # Evaluate the model loss, acc = model.evaluate(test_images, test_labels, verbose=2) print("Untrained model, accuracy: {:5.2f}%".format(100*acc))
1000/1 - 0s - loss: 2.3461 - accuracy: 0.0820 Untrained model, accuracy: 8.20%
それからチェックポイントから重みをロードして、再評価します :
# Loads the weights model.load_weights(checkpoint_path) # Re-evaluate the model loss,acc = model.evaluate(test_images, test_labels, verbose=2) print("Restored model, accuracy: {:5.2f}%".format(100*acc))
1000/1 - 0s - loss: 0.3580 - accuracy: 0.8750 Restored model, accuracy: 87.50%
Checkpoint callback オプション
コールバックはチェックポイントに一意な名前を提供して、チェックポイントする頻度を調整するために幾つかのオプションを提供します。
新しいモデルを訓練して、一意に名前付けられたチェックポイントを 5 エポック毎に一度セーブします :
# Include the epoch in the file name (uses `str.format`) checkpoint_path = "training_2/cp-{epoch:04d}.ckpt" checkpoint_dir = os.path.dirname(checkpoint_path) # Create a callback that saves the model's weights every 5 epochs cp_callback = tf.keras.callbacks.ModelCheckpoint( filepath=checkpoint_path, verbose=1, save_weights_only=True, period=5) # Create a new model instance model = create_model() # Save the weights using the `checkpoint_path` format model.save_weights(checkpoint_path.format(epoch=0)) # Train the model with the new callback 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 samples seen. 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/alpha/guide/checkpoints#loading_mechanics for details. 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 <tensorflow.python.keras.callbacks.History at 0x7fad5f4ba9e8>
さて、結果としてのチェックポイントを見て最新のものを選択します :
!ls {checkpoint_dir}
checkpoint cp-0025.ckpt.data-00001-of-00002 cp-0000.ckpt.data-00000-of-00002 cp-0025.ckpt.index cp-0000.ckpt.data-00001-of-00002 cp-0030.ckpt.data-00000-of-00002 cp-0000.ckpt.index cp-0030.ckpt.data-00001-of-00002 cp-0005.ckpt.data-00000-of-00002 cp-0030.ckpt.index cp-0005.ckpt.data-00001-of-00002 cp-0035.ckpt.data-00000-of-00002 cp-0005.ckpt.index cp-0035.ckpt.data-00001-of-00002 cp-0010.ckpt.data-00000-of-00002 cp-0035.ckpt.index cp-0010.ckpt.data-00001-of-00002 cp-0040.ckpt.data-00000-of-00002 cp-0010.ckpt.index cp-0040.ckpt.data-00001-of-00002 cp-0015.ckpt.data-00000-of-00002 cp-0040.ckpt.index cp-0015.ckpt.data-00001-of-00002 cp-0045.ckpt.data-00000-of-00002 cp-0015.ckpt.index cp-0045.ckpt.data-00001-of-00002 cp-0020.ckpt.data-00000-of-00002 cp-0045.ckpt.index cp-0020.ckpt.data-00001-of-00002 cp-0050.ckpt.data-00000-of-00002 cp-0020.ckpt.index cp-0050.ckpt.data-00001-of-00002 cp-0025.ckpt.data-00000-of-00002 cp-0050.ckpt.index
latest = tf.train.latest_checkpoint(checkpoint_dir) latest
'training_2/cp-0050.ckpt'
Note: デフォルトの tensorflow フォーマットは 5 つの直近のチェックポイントだけをセーブします。
テストするために、モデルをリセットして最新のチェックポイントをロードします :
# Create a new model instance model = create_model() # Load the previously saved weights model.load_weights(latest) # Re-evaluate the model loss, acc = model.evaluate(test_images, test_labels, verbose=2) print("Restored model, accuracy: {:5.2f}%".format(100*acc))
1000/1 - 0s - loss: 0.5667 - accuracy: 0.8760 Restored model, accuracy: 87.60%
これらのファイルは何でしょう?
上のコードは重みを (訓練された重みだけをバイナリ形式で含む) チェックポイント 形式ファイルのコレクションにストアします。チェックポイントは次を含みます : * モデルの重みを含む一つまたはそれ以上のシャード。* どの重みがどのシャードにストアされているかを指し示すインデックスファイル。
単一のマシン上でモデルを訓練しているだけであれば、サフィックス: .data-00000-of-00001 を持つ一つのシャードを持つでしょう。
重みを手動でセーブする
重みをどのようにモデルにロードするかを見ました。手動でそれらをセーブすることは Model.save_weights メソッドにより同様に単純です。デフォルトでは、tf.keras — そして特に save_weights — は .ckpt エクステンションを持つ TensorFlow checkpoints (訳注: リンク切れ ; こちら を参照) 形式を使用します (.h5 エクステンションを持つ HDF5 でセーブすることは Save and serialize models ガイドでカバーされます) :
# Save the weights model.save_weights('./checkpoints/my_checkpoint') # Create a new model instance model = create_model() # Restore the weights model.load_weights('./checkpoints/my_checkpoint') # Evaluate the model loss,acc = model.evaluate(test_images, test_labels, verbose=2) print("Restored model, accuracy: {:5.2f}%".format(100*acc))
1000/1 - 0s - loss: 0.5667 - accuracy: 0.8760 Restored model, accuracy: 87.60%
モデル全体をセーブする
モデルのアーキテクチャ、重みと訓練 configuration を単一のファイル/フォルダにセーブするためには model.save を呼び出します。これはモデルをエクスポートすることを可能にしますので、それは元の python コード* へのアクセスなしに使用できます。optimizer-状態がリカバーされますので、正確に貴方がやめたところから訓練を再開することができます。
完全に機能するモデルのセーブは非常に有用です — それらを TensorFlow.js にロード (HDF5, Saved Model) してから web ブラウザでそれらを訓練して実行することができます、あるいは TensorFlow Lite を使用して (HDF5, Saved Model) モバイルデバイス上で実行するためそれらを変換できます。
* カスタム・オブジェクト (e.g. サブクラス化されたモデルや層) はセーブしてロードするとき特別な注意が必要です。下の Saving custom objects セクションを見てください。
HDF5 形式
Keras は HDF5 標準を使用する基本的なセーブ・フォーマットを提供します。
# Create and train a new model instance. model = create_model() model.fit(train_images, train_labels, epochs=5) # Save the entire model to a HDF5 file. # The '.h5' extension indicates that the model shuold be saved to HDF5. model.save('my_model.h5')
Train on 1000 samples Epoch 1/5 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/alpha/guide/checkpoints#loading_mechanics for details. 1000/1000 [==============================] - 1s 587us/sample - loss: 1.1852 - accuracy: 0.6470 Epoch 2/5 1000/1000 [==============================] - 0s 81us/sample - loss: 0.4299 - accuracy: 0.8840 Epoch 3/5 1000/1000 [==============================] - 0s 82us/sample - loss: 0.2817 - accuracy: 0.9310 Epoch 4/5 1000/1000 [==============================] - 0s 80us/sample - loss: 0.2034 - accuracy: 0.9550 Epoch 5/5 1000/1000 [==============================] - 0s 82us/sample - loss: 0.1521 - accuracy: 0.9700
今、そのファイルからモデルを再作成します :
# Recreate the exact same model, including its weights and the optimizer new_model = tf.keras.models.load_model('my_model.h5') # Show the model architecture 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('Restored model, accuracy: {:5.2f}%'.format(100*acc))
1000/1 - 0s - loss: 0.5676 - accuracy: 0.8640 Restored model, accuracy: 86.40%
このテクニックは総てをセーブします :
- 重み値。
- モデルの構成 (= configuration) (アーキテクチャ)
- optimizer 構成
Keras はアーキテクチャを調べてモデルをセーブします。現在、TensorFlow optimizer ( from tf.train ) をセーブすることはできません。それらを使用するときはモデルをロードした後で再コンパイルする必要があり、そして optimizer の状態を失うでしょう。
SavedModel 形式
SavedModel 形式はモデルをシリアライズするもう一つの方法です。この形式でセーブされたモデルは tf.keras.models.load_model を使用してリストアできて TensorFlow Serving と互換です。SavedModel ガイド は SavedModel をどのようにサーブ/調査するかの詳細に進みます。下のセクションはモデルをセーブしてリストアするステップを示しています。
# Create and train a new model instance. model = create_model() model.fit(train_images, train_labels, epochs=5) # Save the entire model as a SavedModel. model.save('saved_model/my_model')
Train on 1000 samples Epoch 1/5 1000/1000 [==============================] - 0s 440us/sample - loss: 1.1505 - accuracy: 0.6660 Epoch 2/5 1000/1000 [==============================] - 0s 81us/sample - loss: 0.4187 - accuracy: 0.8810 Epoch 3/5 1000/1000 [==============================] - 0s 81us/sample - loss: 0.2721 - accuracy: 0.9320 Epoch 4/5 1000/1000 [==============================] - 0s 80us/sample - loss: 0.2056 - accuracy: 0.9580 Epoch 5/5 1000/1000 [==============================] - 0s 83us/sample - loss: 0.1569 - accuracy: 0.9700 WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1781: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. INFO:tensorflow:Assets written to: saved_model/my_model/assets
SavedModel 形式は protobuf バイナリと Tensorflow チェックポイントを含むディレクトリです。saved model ディレクトリを調べてください :
# my_model directory !ls saved_model # Contains an assets folder, saved_model.pb, and variables folder. !ls saved_model/my_model
my_model assets saved_model.pb variables
saved model から新しい (= fresh) Keras モデルを再ロードします :
new_model = tf.keras.models.load_model('saved_model/my_model') # Check its architecture 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 _________________________________________________________________
リストアされたモデルは元のモデルと同じ引数でコンパイルされます。evaluate を実行してロードされたモデルで予測してみましょう :
# Evaluate the restored model loss, acc = new_model.evaluate(test_images, test_labels, verbose=2) print('Restored model, accuracy: {:5.2f}%'.format(100*acc)) print(new_model.predict(test_images).shape)
1000/1 - 0s - loss: 0.4523 - accuracy: 0.8610 Restored model, accuracy: 86.10% (1000, 10)
カスタムオブジェクトをセーブする
SavedModel 形式を使用している場合、このセクションをスキップできます。HDF5 と SavedModel の主な違いは、SavedModel は実行グラフをセーブしている一方で、HDF5 はモデルアーキテクチャをセーブするために object configs を使用していることです。こうして、SavedModel はサブクラス化されたモデルのようなカスタムオブジェクトとカスタム層を元のコードを必要とすることなくセーブすることができます。
カスタムオブジェクトを HDF5 にセーブするには、次を行なわければなりません :
- 貴方のオブジェクトで get_config メソッド、そしてオプションで from_config クラスメソッドを定義します。
- get_config(self) はオブジェクトを再作成するために必要なパラメータの JSON-serializable 辞書を返します。
- from_config(cls, config) は新しいオブジェクトを作成するために get_config から返された config を使用します。デフォルトでは、この関数は config を初期化 kwargs (return cls(**config)) として使用します。
- モデルをロードするときオブジェクトを custom_objects 引数に渡します。引数は、文字列クラス名を Python クラスにマップする辞書でなければなりません。E.g. tf.keras.models.load_model(path, custom_objects={‘CustomLayer’: CustomLayer})
カスタムオブジェクトと get_config のサンプルのためには Writing layers and models from scratch チュートリアルを見てください。
以上