TensorFlow 2.0 : ガイド : Keras :- Keras で訓練と評価 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 12/03/2019
* 本ページは、TensorFlow org サイトの Guide – 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 :- Keras で訓練と評価
このガイドは 2 つの広範な状況で TensorFlow 2.0 において訓練、評価そして予測 (推論) モデルをカバーします :
- (model.fit(), model.evaluate(), model.predict() のような) 訓練 & 検証のための組み込み API を使用するとき。これはセクション「組み込み訓練 & 評価ループを使用する」でカバーされます。
- eager execution と GradientTape オブジェクトを使用してカスタム・ループをスクラッチから書くとき。これはセクション「スクラッチから貴方自身の訓練 & 評価ループを書く」でカバーされます。
一般に、組み込みループを使用していようが貴方自身のものを書いていようが、モデル訓練 & 評価は総ての種類の Keras モデル — Sequential モデル、Functional API で構築されたモデル、そしてモデル・サブクラス化を通してスクラッチから書かれたモデル — に渡り厳密に同じように動作します。
このガイドは分散訓練はカバーしません。
セットアップ
from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf tf.keras.backend.clear_session() # For easy reset of notebook state.
Part I: 組み込み訓練 & 評価ループを使用する
データをモデルの組み込み訓練ループに渡すとき、(もし貴方のデータが小さくてメモリに収まるのであれば) Numpy 配列 か tf.data Dataset オブジェクトを使用するべきです。次の幾つかのパラグラフでは、optimizer、損失そしてメトリクスをどのように使用するかを実演するために、MNIST データセットを Numpy 配列として使用します。
API 概要: 最初の end-to-end サンプル
次のモデルを考えましょう (ここでは、Functional API で構築しますが、それは Sequential モデルやサブクラス化されたモデルでもかまいません) :
from tensorflow import keras from tensorflow.keras import layers inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs)
ここに典型的な end-to-end ワークフローがどのようなものかがあります、訓練、元の訓練データから生成された取り置いたセット上の検証、そして最後にテストデータ上の評価です :
# Load a toy dataset for the sake of this example (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() # Preprocess the data (these are Numpy arrays) x_train = x_train.reshape(60000, 784).astype('float32') / 255 x_test = x_test.reshape(10000, 784).astype('float32') / 255 y_train = y_train.astype('float32') y_test = y_test.astype('float32') # Reserve 10,000 samples for validation x_val = x_train[-10000:] y_val = y_train[-10000:] x_train = x_train[:-10000] y_train = y_train[:-10000] # Specify the training configuration (optimizer, loss, metrics) model.compile(optimizer=keras.optimizers.RMSprop(), # Optimizer # Loss function to minimize loss=keras.losses.SparseCategoricalCrossentropy(), # List of metrics to monitor metrics=[keras.metrics.SparseCategoricalAccuracy()]) # Train the model by slicing the data into "batches" # of size "batch_size", and repeatedly iterating over # the entire dataset for a given number of "epochs" print('# Fit model on training data') history = model.fit(x_train, y_train, batch_size=64, epochs=3, # We pass some validation for # monitoring validation loss and metrics # at the end of each epoch validation_data=(x_val, y_val)) # The returned "history" object holds a record # of the loss values and metric values during training print('\nhistory dict:', history.history) # Evaluate the model on the test data using `evaluate` print('\n# Evaluate on test data') results = model.evaluate(x_test, y_test, batch_size=128) print('test loss, test acc:', results) # Generate predictions (probabilities -- the output of the last layer) # on new data using `predict` print('\n# Generate predictions for 3 samples') predictions = model.predict(x_test[:3]) print('predictions shape:', predictions.shape)
WARNING: Logging before flag parsing goes to stderr. W0611 18:50:37.143470 139764873668352 deprecation.py:323] From /home/kbuilder/.local/lib/python3.5/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version. Instructions for updating: Use tf.where in 2.0, which has the same broadcast rule as np.where # Fit model on training data Train on 50000 samples, validate on 10000 samples Epoch 1/3 50000/50000 [==============================] - 3s 59us/sample - loss: 0.3343 - sparse_categorical_accuracy: 0.9061 - val_loss: 0.1900 - val_sparse_categorical_accuracy: 0.9457 Epoch 2/3 50000/50000 [==============================] - 2s 50us/sample - loss: 0.1577 - sparse_categorical_accuracy: 0.9539 - val_loss: 0.1314 - val_sparse_categorical_accuracy: 0.9629 Epoch 3/3 50000/50000 [==============================] - 2s 50us/sample - loss: 0.1152 - sparse_categorical_accuracy: 0.9654 - val_loss: 0.1163 - val_sparse_categorical_accuracy: 0.9650 history dict: {'loss': [0.3343376000738144, 0.1576878201198578, 0.11524733116716146], 'val_loss': [0.18996894600391387, 0.13136221459209918, 0.11630819611549377], 'sparse_categorical_accuracy': [0.90608, 0.9539, 0.96542], 'val_sparse_categorical_accuracy': [0.9457, 0.9629, 0.965]} # Evaluate on test data 10000/10000 [==============================] - 0s 17us/sample - loss: 0.1126 - sparse_categorical_accuracy: 0.9660 test loss, test acc: [0.11255755196213722, 0.966] # Generate predictions for 3 samples predictions shape: (3, 10)
損失、メトリクスと optimizer を指定する
fit でモデルを訓練するためには、損失関数、optimizer そしてオプションで監視するための幾つかのメトリクスを指定する必要があります。
これらをモデルに compile() メソッドへの引数として渡します :
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss=keras.losses.SparseCategoricalCrossentropy(), metrics=[keras.metrics.SparseCategoricalAccuracy()])
metrics 引数はリストであるべきです — 貴方のモデルは任意の数のメトリクスを持つことができます。
貴方のモデルがマルチ出力を持つ場合、各出力に対して異なる損失とメトリクスを指定できて、そしてモデルのトータル損失への各出力の寄与を調節できます。これについての更なる詳細をセクション「データをマルチ入力、マルチ出力モデルに渡す」で見つけるでしょう。
多くの場合、損失とメトリクスはショートカットとして、文字列識別子で指定されることに注意してください :
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy'])
後で再利用するために、モデル定義と compile ステップを関数内に配置しましょう ; それらをこのガイドの異なるサンプルに渡り幾度か呼び出します。
def get_uncompiled_model(): inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs) return model def get_compiled_model(): model = get_uncompiled_model() model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy']) return model
多くの組み込み optimizer、損失とメトリクスが利用可能です
一般に、貴方自身の損失、メトリクスや optimizer をスクラッチから作成する必要はないでしょう、何故ならば貴方が必要なものは既に Keras API の一部でありがちだからです :
Optimizers: – SGD() (with or without モメンタム) – RMSprop() – Adam() – 等。
損失: – MeanSquaredError() – KLDivergence() – CosineSimilarity() – 等。
メトリクス: – AUC() – Precision() – Recall() – 等。
カスタム損失
Keras でカスタム損失を提供するためには 2 つの方法があります。最初のサンプルは入力 y_true と y_pred を受け取る関数を作成します。次のサンプルは実データと予測の間の平均距離を計算する損失関数を示します :
def basic_loss_function(y_true, y_pred): return tf.math.reduce_mean(y_true - y_pred) model.compile(optimizer=keras.optimizers.Adam(), loss=basic_loss_function) model.fit(x_train, y_train, batch_size=64, epochs=3)
Train on 50000 samples Epoch 1/3 50000/50000 [==============================] - 2s 38us/sample - loss: 4.3488 Epoch 2/3 50000/50000 [==============================] - 2s 33us/sample - loss: 4.3488 Epoch 3/3 50000/50000 [==============================] - 2s 32us/sample - loss: 4.3488 <tensorflow.python.keras.callbacks.History at 0x7f3bd04da518>
y_true と y_pred の他のパラメータを取る損失関数を必要とする場合、tf.keras.losses.Loss クラスをサブクラス化して次の 2 つのメソッドを実装することができます :
- __init__(self) — 損失関数の呼び出しの間に渡すためのパラメータを受け取ります。
- call(self, y_true, y_pred) — モデルの損失を計算するためにターゲット (y_true) とモデル予測 (y_pred) を使用します。
__init__() に渡されるパラメータは損失を計算するとき call() の間に使用できます。
次のサンプルはBinaryCrossEntropy 損失を計算する WeightedCrossEntropy 損失関数をどのように実装するかを示します、そこではあるクラスの損失か総ての関数がスカラーにより変更できます。
class WeightedBinaryCrossEntropy(keras.losses.Loss): """ Args: pos_weight: Scalar to affect the positive labels of the loss function. weight: Scalar to affect the entirety of the loss function. from_logits: Whether to compute loss form logits or the probability. reduction: Type of tf.keras.losses.Reduction to apply to loss. name: Name of the loss function. """ def __init__(self, pos_weight, weight, from_logits=False, reduction=keras.losses.Reduction.AUTO, name='weighted_binary_crossentropy'): super(WeightedBinaryCrossEntropy, self).__init__(reduction=reduction, name=name) self.pos_weight = pos_weight self.weight = weight self.from_logits = from_logits def call(self, y_true, y_pred): if not self.from_logits: # Manually calculate the weighted cross entropy. # Formula is qz * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x)) # where z are labels, x is logits, and q is the weight. # Since the values passed are from sigmoid (assuming in this case) # sigmoid(x) will be replaced by y_pred # qz * -log(sigmoid(x)) 1e-6 is added as an epsilon to stop passing a zero into the log x_1 = y_true * self.pos_weight * -tf.math.log(y_pred + 1e-6) # (1 - z) * -log(1 - sigmoid(x)). Epsilon is added to prevent passing a zero into the log x_2 = (1 - y_true) * -tf.math.log(1 - y_pred + 1e-6) return tf.add(x_1, x_2) * self.weight # Use built in function return tf.nn.weighted_cross_entropy_with_logits(y_true, y_pred, self.pos_weight) * self.weight model.compile(optimizer=keras.optimizers.Adam(), loss=WeightedBinaryCrossEntropy(0.5, 2)) model.fit(x_train, y_train, batch_size=64, epochs=3)
Train on 50000 samples Epoch 1/3 50000/50000 [==============================] - 2s 42us/sample - loss: 10.0479 Epoch 2/3 50000/50000 [==============================] - 2s 36us/sample - loss: 9.5181 Epoch 3/3 50000/50000 [==============================] - 2s 36us/sample - loss: 9.5174 <tensorflow.python.keras.callbacks.History at 0x7f3bdc0d1c88>
カスタム・メトリクス
API の一部ではないメトリックを必要とする場合、Metric クラスをサブクラス化することによりカスタム・メトリクスを容易に作成できます。4 つのメソッドを実装する必要があります :
- __init__(self), そこでは貴方のメトリックのための状態変数を作成します。
- update_state(self, y_true, y_pred, sample_weight=None), これは状態変数を更新するためにターゲット y_true と モデル予測 y_pred を使用します。
- result(self), それは最終結果を計算するために状態変数を使用します。
- reset_states(self), それはメトリックの状態を再初期化します。
状態更新と結果計算は (それぞれ update_state() と result() で) 別々にしておきます、何故ならばある場合には、結果計算は非常に高価であるかもしれないためで、それは定期のみに行われるでしょう。
ここに CatgoricalTruePositives メトリックをどのように実装するかの単純なサンプルがあります、それは与えられたクラスに属するものとして正しく分類されたサンプルが幾つかを数えます :
class CategoricalTruePositives(keras.metrics.Metric): def __init__(self, name='categorical_true_positives', **kwargs): super(CategoricalTruePositives, self).__init__(name=name, **kwargs) self.true_positives = self.add_weight(name='tp', initializer='zeros') def update_state(self, y_true, y_pred, sample_weight=None): y_pred = tf.reshape(tf.argmax(y_pred, axis=1), shape=(-1, 1)) values = tf.cast(y_true, 'int32') == tf.cast(y_pred, 'int32') values = tf.cast(values, 'float32') if sample_weight is not None: sample_weight = tf.cast(sample_weight, 'float32') values = tf.multiply(values, sample_weight) self.true_positives.assign_add(tf.reduce_sum(values)) def result(self): return self.true_positives def reset_states(self): # The state of the metric will be reset at the start of each epoch. self.true_positives.assign(0.) model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss=keras.losses.SparseCategoricalCrossentropy(), metrics=[CategoricalTruePositives()]) model.fit(x_train, y_train, batch_size=64, epochs=3)
Train on 50000 samples Epoch 1/3 50000/50000 [==============================] - 2s 49us/sample - loss: 0.2017 - categorical_true_positives: 46988.0000 Epoch 2/3 50000/50000 [==============================] - 2s 41us/sample - loss: 0.0853 - categorical_true_positives: 48723.0000 Epoch 3/3 50000/50000 [==============================] - 2s 41us/sample - loss: 0.0703 - categorical_true_positives: 48949.0000 <tensorflow.python.keras.callbacks.History at 0x7f3be3e724e0>
標準的なシグネチャに当てはまらない損失とメトリクスを扱う
損失とメトリクスの圧倒的な大部分は y_true と y_pred から計算できます、ここで y_pred はモデルの出力です。しかし総てではありません。例えば、正則化損失は層の活性を必要とするだけかもしれません (この場合ターゲットはありません)、そしてこの活性はモデル出力ではないかもしれません。
そのような場合、カスタム層の call メソッドの内側から self.add_loss(loss_value) を呼び出すことができます。ここに activity 正則化を追加する単純なサンプルがあります (activity 正則化は総ての Keras 層で組み込みであることに注意してください — この層は具体的な例を提供する目的のためだけです) :
class ActivityRegularizationLayer(layers.Layer): def call(self, inputs): self.add_loss(tf.reduce_sum(inputs) * 0.1) return inputs # Pass-through layer. inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) # Insert activity regularization as a layer x = ActivityRegularizationLayer()(x) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs) model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss='sparse_categorical_crossentropy') # The displayed loss will be much higher than before # due to the regularization component. model.fit(x_train, y_train, batch_size=64, epochs=1)
Train on 50000 samples 50000/50000 [==============================] - 2s 49us/sample - loss: 2.4801 <tensorflow.python.keras.callbacks.History at 0x7f3bbc32ea58>
logging メトリック値に対しても同じことを行うことができます :
class MetricLoggingLayer(layers.Layer): def call(self, inputs): # The `aggregation` argument defines # how to aggregate the per-batch values # over each epoch: # in this case we simply average them. self.add_metric(keras.backend.std(inputs), name='std_of_activation', aggregation='mean') return inputs # Pass-through layer. inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) # Insert std logging as a layer. x = MetricLoggingLayer()(x) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs) model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss='sparse_categorical_crossentropy') model.fit(x_train, y_train, batch_size=64, epochs=1)
Train on 50000 samples 50000/50000 [==============================] - 2s 48us/sample - loss: 0.3369 - std_of_activation: 1.0045 <tensorflow.python.keras.callbacks.History at 0x7f3b88143390>
Functional API では、model.add_loss(loss_tensor) か model.add_metric(metric_tensor, name, aggregation) を呼び出すこともできます。
ここに単純なサンプルがあります :
inputs = keras.Input(shape=(784,), name='digits') x1 = layers.Dense(64, activation='relu', name='dense_1')(inputs) x2 = layers.Dense(64, activation='relu', name='dense_2')(x1) outputs = layers.Dense(10, activation='softmax', name='predictions')(x2) model = keras.Model(inputs=inputs, outputs=outputs) model.add_loss(tf.reduce_sum(x1) * 0.1) model.add_metric(keras.backend.std(x1), name='std_of_activation', aggregation='mean') model.compile(optimizer=keras.optimizers.RMSprop(1e-3), loss='sparse_categorical_crossentropy') model.fit(x_train, y_train, batch_size=64, epochs=1)
Train on 50000 samples 50000/50000 [==============================] - 3s 58us/sample - loss: 2.5077 - std_of_activation: 0.0020 <tensorflow.python.keras.callbacks.History at 0x7f3b782b09e8>
自動的に検証取り置き (= holdout) セットを別にする
貴方が見た最初の end-to-end サンプルでは、各エポックの終わりに検証損失と検証メトリクスを評価するために Numpy 配列のタプル (x_val, y_val) をモデルに渡すために validation_data 引数を使用しました。
ここにもう一つのオプションがあります : 引数 validation_split は検証のために訓練データの一部を自動的に取っておくことを可能にします。引数値は検証のために取っておかれるデータの割合を表しますので、それは 0 より高く 1 より低い数字に設定されるべきです。例えば、validation_split=0.2 は「検証のためにデータの 20% を使用する」ことを意味し、そして validation_split=0.6 は「検証のためにデータの 60% を使用する」ことを意味します。
検証が計算される方法は任意のシャッフルの前に、fit コールにより受け取った配列の最後の x% サンプルを取ります。
Numpy データによる訓練のときに validation_split を使用できるだけです。
model = get_compiled_model() model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=1, steps_per_epoch=1)
Train on 40000 samples, validate on 10000 samples 64/40000 [..............................] - ETA: 7:57 - loss: 2.3474 - sparse_categorical_accuracy: 0.1875 - val_loss: 0.0000e+00 - val_sparse_categorical_accuracy: 0.0000e+00 <tensorflow.python.keras.callbacks.History at 0x7f3b6c34f940>
tf.data Datasets からの訓練 & 評価
前の 2, 3 のパラグラフでは、損失、メトリクスと optimizer をどのように扱うかを見ました、そしてデータが Numpy 配列として渡されるとき、fit で validation_data と validation_split 引数をどのように使用するかを見ました。
今は貴方のデータが tf.data Dataset の形式でもたらされる場合を見ましょう。
tf.data API はデータを高速でスケーラブルな方法でロードして前処理するための TensorFlow 2.0 のユティリティのセットです。
Datasets の作成についての完全なガイドは、tf.data ドキュメント を見てください。
Dataset インスタンスをメソッド fit(), evaluate() と predict() に直接的に渡すことができます :
model = get_compiled_model() # First, let's create a training Dataset instance. # For the sake of our example, we'll use the same MNIST data as before. train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) # Shuffle and slice the dataset. train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64) # Now we get a test dataset. test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test)) test_dataset = test_dataset.batch(64) # Since the dataset already takes care of batching, # we don't pass a `batch_size` argument. model.fit(train_dataset, epochs=3) # You can also evaluate or predict on a dataset. print('\n# Evaluate') model.evaluate(test_dataset)
Epoch 1/3 782/782 [==============================] - 4s 5ms/step - loss: 0.3421 - sparse_categorical_accuracy: 0.9039 Epoch 2/3 782/782 [==============================] - 2s 3ms/step - loss: 0.1603 - sparse_categorical_accuracy: 0.9521 Epoch 3/3 782/782 [==============================] - 2s 3ms/step - loss: 0.1166 - sparse_categorical_accuracy: 0.9647 # Evaluate 157/157 [==============================] - 0s 2ms/step - loss: 0.1380 - sparse_categorical_accuracy: 0.9567 [0.1379790138586715, 0.9567]
Dataset は各エポックの最後にリセットされますので、それは次のエポックで再利用できることに注意してください。
このデータセットから特定の数のバッチ上でだけ訓練を実行することを望む場合、steps_per_epoch 引数を渡すことができます、これは次のエポックに移る前にこの Dataset を使用してモデルが幾つの訓練ステップを実行するべきかを指定します。
これを行なう場合、dataset は各エポックの最後にリセットされません、代わりに次のバッチを単にドローし続けます。dataset はやがてデータを使い果たします (それが無限ループな dataset でない限りは)。
model = get_compiled_model() # Prepare the training dataset train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64) # Only use the 100 batches per epoch (that's 64 * 100 samples) model.fit(train_dataset.take(100), epochs=3)
Epoch 1/3 100/100 [==============================] - 1s 10ms/step - loss: 0.8005 - sparse_categorical_accuracy: 0.7956 Epoch 2/3 100/100 [==============================] - 1s 5ms/step - loss: 0.3299 - sparse_categorical_accuracy: 0.9091 Epoch 3/3 100/100 [==============================] - 0s 5ms/step - loss: 0.2584 - sparse_categorical_accuracy: 0.9286 <tensorflow.python.keras.callbacks.History at 0x7f3b2020df60>
検証 dataset を使用する
Dataset インスタンスを fit の validation_data 引数として渡すことができます :
model = get_compiled_model() # Prepare the training dataset train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64) # Prepare the validation dataset val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val)) val_dataset = val_dataset.batch(64) model.fit(train_dataset, epochs=3, validation_data=val_dataset)
Epoch 1/3 782/782 [==============================] - 4s 5ms/step - loss: 0.3376 - sparse_categorical_accuracy: 0.9043 - val_loss: 0.0000e+00 - val_sparse_categorical_accuracy: 0.0000e+00 Epoch 2/3 782/782 [==============================] - 3s 4ms/step - loss: 0.1623 - sparse_categorical_accuracy: 0.9523 - val_loss: 0.1406 - val_sparse_categorical_accuracy: 0.9602 Epoch 3/3 782/782 [==============================] - 3s 4ms/step - loss: 0.1213 - sparse_categorical_accuracy: 0.9638 - val_loss: 0.1233 - val_sparse_categorical_accuracy: 0.9632 <tensorflow.python.keras.callbacks.History at 0x7f3b08b84550>
各エポックの最後に、モデルは検証 Dataset に渡り iterate して検証損失と検証メトリクスを計算します。
この Dataset から特定の数のバッチ上でだけ検証を実行することを望む場合、validation_steps 引数を渡すことができます、これはモデルが検証を中断して次のエポックに進む前に検証 Dataset で幾つの検証ステップを実行するべきかを指定します :
model = get_compiled_model() # Prepare the training dataset train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64) # Prepare the validation dataset val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val)) val_dataset = val_dataset.batch(64) model.fit(train_dataset, epochs=3, # Only run validation using the first 10 batches of the dataset # using the `validation_steps` argument validation_data=val_dataset, validation_steps=10)
Epoch 1/3 782/782 [==============================] - 4s 5ms/step - loss: 0.3322 - sparse_categorical_accuracy: 0.9068 - val_loss: 0.0000e+00 - val_sparse_categorical_accuracy: 0.0000e+00 Epoch 2/3 782/782 [==============================] - 2s 3ms/step - loss: 0.1554 - sparse_categorical_accuracy: 0.9540 - val_loss: 0.2302 - val_sparse_categorical_accuracy: 0.9375 Epoch 3/3 782/782 [==============================] - 2s 3ms/step - loss: 0.1146 - sparse_categorical_accuracy: 0.9665 - val_loss: 0.1813 - val_sparse_categorical_accuracy: 0.9484 <tensorflow.python.keras.callbacks.History at 0x7f3b084e4e80>
検証 Dataset は各使用の後にリセットされることに注意してください (その結果エポックからエポックへ同じサンプル上で常に評価しています)。
Dataset オブジェクトから訓練するときには (訓練データから取り置いたセットを生成する) 引数 validation_split はサポートされません、何故ならばこの機能は (Dataset API では一般に可能ではない) dataset のサンプルをインデックスする機能を必要とするからです。
サポートされる他の入力フォーマット
Numpy 配列と TensorFlow Dataset の他にも、Pandas dataframe を使用したりバッチを yield する Python ジェネレータから Keras モデルを訓練することが可能です。
一般に、貴方のデータが小さくてメモリに収まるのであれば Numpy 入力データを使用し、そうでなければ Datset を使用することを勧めます。
サンプル重み付けとクラス重み付けを使用する
入力データとターゲットデータの他にも、fit を使用するときモデルにサンプル重みやクラス重みを渡すことも可能です :
- Numpy データから訓練するとき: sample_weight と class_weight 引数を通して。
- Datasets から訓練するとき: Dataset にタプル (input_batch, target_batch, sample_weight_batch) を返させることによって。
“sample weights” 配列は、トータル損失を計算するときにバッチの各サンプルがどのくらいの重みを持つべきであるかを指定する数字の配列です。それは一般に不均衡な分類問題で使用されます (滅多に見られないクラスにより大きい重みを与えるアイデアです)。使用される重みが ones か zeros であるとき、配列は損失関数のためのマスクとして使用できます (特定のサンプルのトータル損失への寄与を完全に捨てます)。
“class weights” 辞書は同じ概念のより明確なインスタンスです : それはクラス・インデックスをこのクラスに属するサンプルのために使用されるべきサンプル重みにマップします。例えば、貴方のデータでクラス “0” がクラス “1” よりも 2 倍少なく表わされるのであれば、class_weight={0: 1., 1: 0.5} を使用できるでしょう。
ここに Numpy サンプルがあります、そこではクラス #5 (これは MNIST データセットの数字 “5” です) の正しい分類により多くの重要性を与えるためにクラス重みかサンプル重みを使用します。
import numpy as np class_weight = {0: 1., 1: 1., 2: 1., 3: 1., 4: 1., # Set weight "2" for class "5", # making this class 2x more important 5: 2., 6: 1., 7: 1., 8: 1., 9: 1.} print('Fit with class weight') model.fit(x_train, y_train, class_weight=class_weight, batch_size=64, epochs=4) # Here's the same example using `sample_weight` instead: sample_weight = np.ones(shape=(len(y_train),)) sample_weight[y_train == 5] = 2. print('\nFit with sample weight') model = get_compiled_model() model.fit(x_train, y_train, sample_weight=sample_weight, batch_size=64, epochs=4)
Fit with class weight Train on 50000 samples Epoch 1/4 50000/50000 [==============================] - 3s 52us/sample - loss: 0.1035 - sparse_categorical_accuracy: 0.9710 Epoch 2/4 50000/50000 [==============================] - 2s 46us/sample - loss: 0.0858 - sparse_categorical_accuracy: 0.9763 Epoch 3/4 50000/50000 [==============================] - 2s 46us/sample - loss: 0.0744 - sparse_categorical_accuracy: 0.9788 Epoch 4/4 50000/50000 [==============================] - 2s 46us/sample - loss: 0.0645 - sparse_categorical_accuracy: 0.9821 Fit with sample weight Train on 50000 samples Epoch 1/4 50000/50000 [==============================] - 3s 56us/sample - loss: 0.3751 - sparse_categorical_accuracy: 0.9004 Epoch 2/4 50000/50000 [==============================] - 2s 46us/sample - loss: 0.1703 - sparse_categorical_accuracy: 0.9530 Epoch 3/4 50000/50000 [==============================] - 2s 46us/sample - loss: 0.1269 - sparse_categorical_accuracy: 0.9646 Epoch 4/4 50000/50000 [==============================] - 2s 45us/sample - loss: 0.1032 - sparse_categorical_accuracy: 0.9713 <tensorflow.python.keras.callbacks.History at 0x7f3ae81b0eb8>
ここに適合している Dataset サンプルがあります :
sample_weight = np.ones(shape=(len(y_train),)) sample_weight[y_train == 5] = 2. # Create a Dataset that includes sample weights # (3rd element in the return tuple). train_dataset = tf.data.Dataset.from_tensor_slices( (x_train, y_train, sample_weight)) # Shuffle and slice the dataset. train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64) model = get_compiled_model() model.fit(train_dataset, epochs=3)
Epoch 1/3 782/782 [==============================] - 4s 5ms/step - loss: 0.3659 - sparse_categorical_accuracy: 0.9045 Epoch 2/3 782/782 [==============================] - 3s 3ms/step - loss: 0.1710 - sparse_categorical_accuracy: 0.9529 Epoch 3/3 782/782 [==============================] - 3s 3ms/step - loss: 0.1244 - sparse_categorical_accuracy: 0.9652 <tensorflow.python.keras.callbacks.History at 0x7f3ae0218da0>
データをマルチ入力、マルチ出力モデルに渡す
前の例では、単一の入力 (shape (764,) の tensor) と単一の出力 (shape (10,) の予測 tensor) を持つモデルを考えていました。しかしマルチ入力か出力を持つモデルについてはどうでしょう?
次のモデルを考えます、それは shape (32, 32, 3) (それは (高さ、幅、チャネル)) の画像入力と shape (None, 10) (それは (時間ステップ, 特徴)) の時系列入力を持ちます。私達のモデルはこれらの入力の組み合わせから計算された 2 つの出力を持ちます : (shape (1,) の) 「スコア」と (shape (5,) の) 5 クラスに渡る確率分布です。
from tensorflow import keras from tensorflow.keras import layers image_input = keras.Input(shape=(32, 32, 3), name='img_input') timeseries_input = keras.Input(shape=(None, 10), name='ts_input') x1 = layers.Conv2D(3, 3)(image_input) x1 = layers.GlobalMaxPooling2D()(x1) x2 = layers.Conv1D(3, 3)(timeseries_input) x2 = layers.GlobalMaxPooling1D()(x2) x = layers.concatenate([x1, x2]) score_output = layers.Dense(1, name='score_output')(x) class_output = layers.Dense(5, activation='softmax', name='class_output')(x) model = keras.Model(inputs=[image_input, timeseries_input], outputs=[score_output, class_output])
このモデルをプロットしましょう、そうすれば私達がここで何をしているかを明瞭に見ることができます (プロットで示される shape はサンプル毎 shape ではなくバッチ shape であることに注意してください)。
keras.utils.plot_model(model, 'multi_input_and_output_model.png', show_shapes=True)
コンパイル時、損失関数をリストとして渡すことにより異なる出力に対して異なる損失を指定できます :
model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss=[keras.losses.MeanSquaredError(), keras.losses.CategoricalCrossentropy()])
モデルに単一の損失関数を渡すだけの場合には、同じ損失関数が総ての出力に適用されるでしょう、ここではそれは適切ではありません。
メトリクスについても同様です :
model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss=[keras.losses.MeanSquaredError(), keras.losses.CategoricalCrossentropy()], metrics=[[keras.metrics.MeanAbsolutePercentageError(), keras.metrics.MeanAbsoluteError()], [keras.metrics.CategoricalAccuracy()]])
出力層に名前を与えましたので、辞書を通して出力毎の損失とメトリクスを指定することもできるでしょう :
model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss={'score_output': keras.losses.MeanSquaredError(), 'class_output': keras.losses.CategoricalCrossentropy()}, metrics={'score_output': [keras.metrics.MeanAbsolutePercentageError(), keras.metrics.MeanAbsoluteError()], 'class_output': [keras.metrics.CategoricalAccuracy()]})
2 出力以上を持つ場合、明示的な名前と辞書の使用を勧めます。
loss_weight 引数を使用して、異なる出力固有の損失に異なる重みを与えることも可能です (例えば、私達の例の「スコア」損失にクラス損失の 2 倍の重要性を与えることにより、特権を与えることを望むかもしれません) :
model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss={'score_output': keras.losses.MeanSquaredError(), 'class_output': keras.losses.CategoricalCrossentropy()}, metrics={'score_output': [keras.metrics.MeanAbsolutePercentageError(), keras.metrics.MeanAbsoluteError()], 'class_output': [keras.metrics.CategoricalAccuracy()]}, loss_weights={'score_output': 2., 'class_output': 1.})
これらの出力が訓練のためではなく予測のためであれば、特定の出力のための損失を計算しないことも選択できるでしょう :
# List loss version model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss=[None, keras.losses.CategoricalCrossentropy()]) # Or dict loss version model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss={'class_output': keras.losses.CategoricalCrossentropy()})
WARNING:tensorflow:Output score_output missing from loss dictionary. We assume this was done on purpose. The fit and evaluate APIs will not be expecting any data to be passed to score_output.
マルチ入力やマルチ出力モデルに fit でデータを渡すことは compile で損失関数を指定するのと同様な方法で動作します : (損失関数を受け取った出力への 1:1 マッピングを持つ) Numpy 配列のリストや出力名を訓練データの Numpy 配列にマップする辞書を渡すことができます。
model.compile( optimizer=keras.optimizers.RMSprop(1e-3), loss=[keras.losses.MeanSquaredError(), keras.losses.CategoricalCrossentropy()]) # Generate dummy Numpy data img_data = np.random.random_sample(size=(100, 32, 32, 3)) ts_data = np.random.random_sample(size=(100, 20, 10)) score_targets = np.random.random_sample(size=(100, 1)) class_targets = np.random.random_sample(size=(100, 5)) # Fit on lists model.fit([img_data, ts_data], [score_targets, class_targets], batch_size=32, epochs=3) # Alternatively, fit on dicts model.fit({'img_input': img_data, 'ts_input': ts_data}, {'score_output': score_targets, 'class_output': class_targets}, batch_size=32, epochs=3)
Train on 100 samples Epoch 1/3 100/100 [==============================] - 3s 28ms/sample - loss: 7.5105 - score_output_loss: 2.7916 - class_output_loss: 4.5724 Epoch 2/3 100/100 [==============================] - 0s 210us/sample - loss: 6.5208 - score_output_loss: 1.7519 - class_output_loss: 4.8270 Epoch 3/3 100/100 [==============================] - 0s 202us/sample - loss: 6.0499 - score_output_loss: 1.0947 - class_output_loss: 5.2064 Train on 100 samples Epoch 1/3 100/100 [==============================] - 0s 307us/sample - loss: 5.7626 - score_output_loss: 0.8008 - class_output_loss: 4.9479 Epoch 2/3 100/100 [==============================] - 0s 200us/sample - loss: 5.5649 - score_output_loss: 0.6005 - class_output_loss: 4.7794 Epoch 3/3 100/100 [==============================] - 0s 188us/sample - loss: 5.4176 - score_output_loss: 0.4619 - class_output_loss: 5.0290 <tensorflow.python.keras.callbacks.History at 0x7f36f6f996a0>
ここに Dataset のユースケースがあります : Numpy 配列のために行なったことと同様です、Dataset は辞書のタプルを返すべきです。
train_dataset = tf.data.Dataset.from_tensor_slices( ({'img_input': img_data, 'ts_input': ts_data}, {'score_output': score_targets, 'class_output': class_targets})) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64) model.fit(train_dataset, epochs=3)
Epoch 1/3 2/2 [==============================] - 0s 238ms/step - loss: 5.4252 - score_output_loss: 0.3387 - class_output_loss: 5.0865 Epoch 2/3 2/2 [==============================] - 0s 12ms/step - loss: 5.2802 - score_output_loss: 0.2856 - class_output_loss: 5.0243 Epoch 3/3 2/2 [==============================] - 0s 10ms/step - loss: 5.2754 - score_output_loss: 0.2699 - class_output_loss: 4.9820 <tensorflow.python.keras.callbacks.History at 0x7f36fc3cb048>
コールバックを使用する
Keras の Callbacks は訓練の間に異なるポイント (エポックの最初、バッチの最後、エポックの最後, etc.) で呼び出されるオブジェクトでそれは次のような動作を実装するために使用できます :
- 訓練の間に異なるポイントで検証を行なう (組み込みのエポック毎検証を越えて)
- 定期の間隔であるいはそれが特定の精度しきい値を超えたときにモデルをチェックポイントする
- 訓練が頭打ちになったように思われるときにモデルの学習率を変更する
- 訓練が頭打ちになったように思われるときに top 層の再調整を行なう
- 訓練が終わるときあるいは特定のパフォーマンスしきい値を超えた場合に電子メールかインスタントメッセージ通知を送る
- Etc.
Callback は fit への呼び出しにリストとして渡すことができます :
model = get_compiled_model() callbacks = [ keras.callbacks.EarlyStopping( # Stop training when `val_loss` is no longer improving monitor='val_loss', # "no longer improving" being defined as "no better than 1e-2 less" min_delta=1e-2, # "no longer improving" being further defined as "for at least 2 epochs" patience=2, verbose=1) ] model.fit(x_train, y_train, epochs=20, batch_size=64, callbacks=callbacks, validation_split=0.2)
Train on 40000 samples, validate on 10000 samples Epoch 1/20 40000/40000 [==============================] - 3s 64us/sample - loss: 0.3884 - sparse_categorical_accuracy: 0.8889 - val_loss: 0.2472 - val_sparse_categorical_accuracy: 0.9264 Epoch 2/20 40000/40000 [==============================] - 2s 43us/sample - loss: 0.1775 - sparse_categorical_accuracy: 0.9481 - val_loss: 0.1777 - val_sparse_categorical_accuracy: 0.9472 Epoch 3/20 40000/40000 [==============================] - 2s 43us/sample - loss: 0.1276 - sparse_categorical_accuracy: 0.9624 - val_loss: 0.1595 - val_sparse_categorical_accuracy: 0.9520 Epoch 4/20 40000/40000 [==============================] - 2s 44us/sample - loss: 0.1009 - sparse_categorical_accuracy: 0.9694 - val_loss: 0.1451 - val_sparse_categorical_accuracy: 0.9598 Epoch 5/20 40000/40000 [==============================] - 2s 44us/sample - loss: 0.0826 - sparse_categorical_accuracy: 0.9748 - val_loss: 0.1361 - val_sparse_categorical_accuracy: 0.9607 Epoch 6/20 40000/40000 [==============================] - 2s 44us/sample - loss: 0.0709 - sparse_categorical_accuracy: 0.9786 - val_loss: 0.1339 - val_sparse_categorical_accuracy: 0.9622 Epoch 7/20 40000/40000 [==============================] - 2s 43us/sample - loss: 0.0603 - sparse_categorical_accuracy: 0.9815 - val_loss: 0.1459 - val_sparse_categorical_accuracy: 0.9599 Epoch 8/20 40000/40000 [==============================] - 2s 44us/sample - loss: 0.0525 - sparse_categorical_accuracy: 0.9844 - val_loss: 0.1366 - val_sparse_categorical_accuracy: 0.9657 Epoch 00008: early stopping <tensorflow.python.keras.callbacks.History at 0x7f36f40f3c88>
多くの組み込み callbacks が利用可能です
- ModelCheckpoint: 定期的にモデルをセーブする。
- EarlyStopping: 訓練がもはや検証メトリクスを改善しないときに訓練を停止する。
- TensorBoard: TensorBoard で可視化できるモデルログを定期的に書く (セクション「可視化」で更なる詳細)。
- CSVLogger: 損失とメトリクス・データを CSV ファイルにストリームする。
- etc.
貴方自身の callback を書く
基底クラス keras.callbacks.Callback を拡張することでカスタム callback を作成できます。callback はクラス・プロパティ self.model を通してその関連するモデルへのアクセスを持ちます。
ここに訓練の間にバッチ毎損失値のリストをセーブする単純な例があります :
class LossHistory(keras.callbacks.Callback): def on_train_begin(self, logs): self.losses = [] def on_batch_end(self, batch, logs): self.losses.append(logs.get('loss'))
モデルをチェックポイントする
比較的巨大なデータセット上でモデルを訓練しているとき、貴方のモデルのチェックポイントをしばしばセーブすることは重要です。
これを成すための最も容易な方法は ModelCheckpoint callback によるものです :
model = get_compiled_model() callbacks = [ keras.callbacks.ModelCheckpoint( filepath='mymodel_{epoch}.h5', # Path where to save the model # The two parameters below mean that we will overwrite # the current checkpoint if and only if # the `val_loss` score has improved. save_best_only=True, monitor='val_loss', verbose=1) ] model.fit(x_train, y_train, epochs=3, batch_size=64, callbacks=callbacks, validation_split=0.2)
Train on 40000 samples, validate on 10000 samples Epoch 1/3 39872/40000 [============================>.] - ETA: 0s - loss: 0.3715 - sparse_categorical_accuracy: 0.8971 Epoch 00001: val_loss improved from inf to 0.22463, saving model to mymodel_1.h5 40000/40000 [==============================] - 2s 55us/sample - loss: 0.3713 - sparse_categorical_accuracy: 0.8971 - val_loss: 0.2246 - val_sparse_categorical_accuracy: 0.9329 Epoch 2/3 38592/40000 [===========================>..] - ETA: 0s - loss: 0.1751 - sparse_categorical_accuracy: 0.9485 Epoch 00002: val_loss improved from 0.22463 to 0.19152, saving model to mymodel_2.h5 40000/40000 [==============================] - 2s 44us/sample - loss: 0.1743 - sparse_categorical_accuracy: 0.9490 - val_loss: 0.1915 - val_sparse_categorical_accuracy: 0.9436 Epoch 3/3 38592/40000 [===========================>..] - ETA: 0s - loss: 0.1279 - sparse_categorical_accuracy: 0.9621 Epoch 00003: val_loss improved from 0.19152 to 0.15396, saving model to mymodel_3.h5 40000/40000 [==============================] - 2s 44us/sample - loss: 0.1279 - sparse_categorical_accuracy: 0.9620 - val_loss: 0.1540 - val_sparse_categorical_accuracy: 0.9558 <tensorflow.python.keras.callbacks.History at 0x7f36ec1ba550>
モデルをセーブしてリストアするための貴方自身の callback を書くこともできます。
シリアライゼーションとセービングについての完全なガイドは、Guide to Saving and Serializing Models を見てください。
学習率スケジュールを使用する
深層学習モデルを訓練するときの共通のパターンは訓練が進むにつれて学習率を徐々に減じることです。これは一般に「学習率減衰 (= decay)」として知られています。
学習率減衰は静的 (現在のエポックか現在のバッチインデックスの関数として、前もって固定) でも動的 (モデルの現在の動作に呼応、特に検証損失) でもあり得るでしょう。
スケジュールを optimizer に渡す
スケジュール・オブジェクトを optimizer の learning_rate 引数として渡すことにより静的学習率減衰スケジュールは容易に使用できます :
initial_learning_rate = 0.1 lr_schedule = keras.optimizers.schedules.ExponentialDecay( initial_learning_rate, decay_steps=100000, decay_rate=0.96, staircase=True) optimizer = keras.optimizers.RMSprop(learning_rate=lr_schedule)
幾つかの組込みスケジュールが利用可能です : ExponentialDecay, PiecewiseConstantDecay, PolynomialDecay, and InverseTimeDecay.
動的学習率スケジュールを実装するために callback を使用する
動的学習率スケジュール (例えば、検証損失がもはや改善しないときに学習率を減じます) はこれらのスケジュール・オブジェクトでは達成できません、何故ならば optimizer は検証メトリクスへのアクセスを持たないからです。
けれども、callback は検証メトリクスを含む、総てのメトリクスへのアクセスを持ちます!こうして optimizer の現在の学習率を変更する callback を使用してこのパターンを達成できます。実際に、これは ReduceLROnPlateau callback として組み込みでさえあります。
訓練の間に損失とメトリクスを可視化する
訓練の間に貴方のモデルを監視する最善の方法は TensorBoard を使用することです、これは以下を提供する、貴方がローカルで実行できるブラウザ・ベースのアプリケーションです :
- 訓練と評価のための損失とメトリクスのライブ・プロット
- (オプションで) 層活性のヒストグラムの可視化
- (オプションで) Embedding 層で学習された埋め込み空間の 3D 可視化
TensorFlow を pip でインストールしたのであれば、以下のコマンドラインから TensorBoard を起動できるはずです :
tensorboard --logdir=/full_path_to_your_logs
TensorBoard callback を使用する
Keras モデルと fit メソッドで TensorBoard を使用する最も容易な方法は TensorBoard callback です。
最も単純なケースでは、callback にログを書くことを望むところを単に指定します、それで十分です :
tensorboard_cbk = keras.callbacks.TensorBoard(log_dir='/full_path_to_your_logs') model.fit(dataset, epochs=10, callbacks=[tensorboard_cbk])
TensorBoard callback は、embeddings, histograms をロギングするか否か、そしてどのくらいの頻度でログを書くかを含む、多くの有用なオプションを持ちます :
keras.callbacks.TensorBoard( log_dir='/full_path_to_your_logs', histogram_freq=0, # How often to log histogram visualizations embeddings_freq=0, # How often to log embedding visualizations update_freq='epoch') # How often to write logs (default: once per epoch)
Part II: スクラッチから貴方自身の訓練 & 評価ループを書く
貴方の訓練 & 評価ループに渡り fit() と evaluate() が提供するものよりもより低位を望む場合には、貴方自身のものを書くべきです。それは実際には非常に単純です!しかし貴方自身のものの上でより多くのデバッグを行なう準備をすべきです。
GradientTape を使用する: 最初の end-to-end サンプル
GradientTape スコープの内側でモデルを呼び出すことは損失値に関する層の訓練可能な重みの勾配を取得することを可能にします。optimizer インスタンスを使用して、これらの変数 (それらは model.trainable_variables を使用して取得できます) を更新するためにこれらの勾配を使用できます。
Part I から私達の初期 MNIST モデルを再利用しましょう、そしてそれをカスタム訓練ループでミニバッチ勾配を使用して訓練しましょう。
# Get the model. inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs) # Instantiate an optimizer. optimizer = keras.optimizers.SGD(learning_rate=1e-3) # Instantiate a loss function. loss_fn = keras.losses.SparseCategoricalCrossentropy() # Prepare the training dataset. batch_size = 64 train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(batch_size) # Iterate over epochs. epochs = 3 for epoch in range(epochs): print('Start of epoch %d' % (epoch,)) # Iterate over the batches of the dataset. for step, (x_batch_train, y_batch_train) in enumerate(train_dataset): # Open a GradientTape to record the operations run # during the forward pass, which enables autodifferentiation. with tf.GradientTape() as tape: # Run the forward pass of the layer. # The operations that the layer applies # to its inputs are going to be recorded # on the GradientTape. logits = model(x_batch_train) # Logits for this minibatch # Compute the loss value for this minibatch. loss_value = loss_fn(y_batch_train, logits) # Use the gradient tape to automatically retrieve # the gradients of the trainable variables with respect to the loss. grads = tape.gradient(loss_value, model.trainable_weights) # Run one step of gradient descent by updating # the value of the variables to minimize the loss. optimizer.apply_gradients(zip(grads, model.trainable_weights)) # Log every 200 batches. if step % 200 == 0: print('Training loss (for one batch) at step %s: %s' % (step, float(loss_value))) print('Seen so far: %s samples' % ((step + 1) * 64))
Start of epoch 0 Training loss (for one batch) at step 0: 2.3747615814208984 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.264816999435425 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.1977667808532715 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.085158586502075 Seen so far: 38464 samples Start of epoch 1 Training loss (for one batch) at step 0: 2.0625901222229004 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.97736656665802 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.9285550117492676 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.7810806035995483 Seen so far: 38464 samples Start of epoch 2 Training loss (for one batch) at step 0: 1.7103501558303833 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.4607808589935303 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.5318548679351807 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.3345484733581543 Seen so far: 38464 samples
メトリクスの低位処理
Let’s add metrics to the mix. スクラッチから書かれたそのような訓練ループで組み込みメトリクス (または貴方が書いたカスタムなもの) を容易に再利用できます。ここにフローがあります :
- ループの最初にメトリックをインスタンス化する
- 各バッチ後に metric.update_state() を呼び出す
- メトリックの現在の値を表示する必要があるとき metric.result() を呼び出す
- メトリックの状態をクリアする必要があるとき metric.reset_states() を呼び出す (典型的にはエポックの最後)
各エポックの最後に検証データ上で SparseCategoricalAccuracy を計算するためにこの知識を使用しましょう :
# Get model inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs) # Instantiate an optimizer to train the model. optimizer = keras.optimizers.SGD(learning_rate=1e-3) # Instantiate a loss function. loss_fn = keras.losses.SparseCategoricalCrossentropy() # Prepare the metrics. train_acc_metric = keras.metrics.SparseCategoricalAccuracy() val_acc_metric = keras.metrics.SparseCategoricalAccuracy() # Prepare the training dataset. batch_size = 64 train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(batch_size) # Prepare the validation dataset. val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val)) val_dataset = val_dataset.batch(64) # Iterate over epochs. epochs = 3 for epoch in range(epochs): print('Start of epoch %d' % (epoch,)) # Iterate over the batches of the dataset. for step, (x_batch_train, y_batch_train) in enumerate(train_dataset): with tf.GradientTape() as tape: logits = model(x_batch_train) loss_value = loss_fn(y_batch_train, logits) grads = tape.gradient(loss_value, model.trainable_weights) optimizer.apply_gradients(zip(grads, model.trainable_weights)) # Update training metric. train_acc_metric(y_batch_train, logits) # Log every 200 batches. if step % 200 == 0: print('Training loss (for one batch) at step %s: %s' % (step, float(loss_value))) print('Seen so far: %s samples' % ((step + 1) * 64)) # Display metrics at the end of each epoch. train_acc = train_acc_metric.result() print('Training acc over epoch: %s' % (float(train_acc),)) # Reset training metrics at the end of each epoch train_acc_metric.reset_states() # Run a validation loop at the end of each epoch. for x_batch_val, y_batch_val in val_dataset: val_logits = model(x_batch_val) # Update val metrics val_acc_metric(y_batch_val, val_logits) val_acc = val_acc_metric.result() val_acc_metric.reset_states() print('Validation acc: %s' % (float(val_acc),))
Start of epoch 0 Training loss (for one batch) at step 0: 2.32742977142334 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.27957820892334 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.223424196243286 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.1545217037200928 Seen so far: 38464 samples Training acc over epoch: 0.22378000617027283 Validation acc: 0.3995000123977661 Start of epoch 1 Training loss (for one batch) at step 0: 2.0469183921813965 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.9954742193222046 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.8717031478881836 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.8559406995773315 Seen so far: 38464 samples Training acc over epoch: 0.5212399959564209 Validation acc: 0.6148999929428101 Start of epoch 2 Training loss (for one batch) at step 0: 1.8021643161773682 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.7000391483306885 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.4835299253463745 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.3361830711364746 Seen so far: 38464 samples Training acc over epoch: 0.6601999998092651 Validation acc: 0.7210999727249146
extra 損失の低位処理
前のセクションで、層により call メソッドで self.add_loss(value) を呼び出して正則化損失を追加できることを見ました。
一般的なケースでは、貴方のカスタム訓練ループでこれらの損失を考慮することを望むでしょう (貴方がモデルを自身で書いてそれがそのような損失を作成しないことを既に知っている場合でなければ)。
前のセクションからのこのサンプルを思い出してください、正則化損失を作成する層にフィーチャーしています :
class ActivityRegularizationLayer(layers.Layer): def call(self, inputs): self.add_loss(1e-2 * tf.reduce_sum(inputs)) return inputs inputs = keras.Input(shape=(784,), name='digits') x = layers.Dense(64, activation='relu', name='dense_1')(inputs) # Insert activity regularization as a layer x = ActivityRegularizationLayer()(x) x = layers.Dense(64, activation='relu', name='dense_2')(x) outputs = layers.Dense(10, activation='softmax', name='predictions')(x) model = keras.Model(inputs=inputs, outputs=outputs)
モデルを呼び出すとき、このようにします :
logits = model(x_train)
forward パスでそれが作成した損失は model.losses 属性に追加されます :
logits = model(x_train[:64]) print(model.losses)
[<tf.Tensor: id=624847, shape=(), dtype=float32, numpy=7.6811996>]
追跡された損失はまず model __call__ の最初でクリアされますので、この 1 つの forward パスの間に作成された損失だけを見るでしょう。例えば、model を繰り返し呼び出して、そしてそれから損失の問い合わせは (最後の呼び出しの間に作成された) 最新の損失を表示するだけです :
logits = model(x_train[:64]) logits = model(x_train[64: 128]) logits = model(x_train[128: 192]) print(model.losses)
[<tf.Tensor: id=624907, shape=(), dtype=float32, numpy=7.5797887>]
訓練の間にこれらの損失を考慮するには、貴方が行なわなければならない総てのことは貴方の訓練ループをトータル損失に sum(model.losses) を追加するように変更することです :
optimizer = keras.optimizers.SGD(learning_rate=1e-3) epochs = 3 for epoch in range(epochs): print('Start of epoch %d' % (epoch,)) for step, (x_batch_train, y_batch_train) in enumerate(train_dataset): with tf.GradientTape() as tape: logits = model(x_batch_train) loss_value = loss_fn(y_batch_train, logits) # Add extra losses created during this forward pass: loss_value += sum(model.losses) grads = tape.gradient(loss_value, model.trainable_weights) optimizer.apply_gradients(zip(grads, model.trainable_weights)) # Log every 200 batches. if step % 200 == 0: print('Training loss (for one batch) at step %s: %s' % (step, float(loss_value))) print('Seen so far: %s samples' % ((step + 1) * 64))
Start of epoch 0 Training loss (for one batch) at step 0: 10.064319610595703 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.5281362533569336 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.400449275970459 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.380073308944702 Seen so far: 38464 samples Start of epoch 1 Training loss (for one batch) at step 0: 2.3233108520507812 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.325932025909424 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.326887845993042 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.3155736923217773 Seen so far: 38464 samples Start of epoch 2 Training loss (for one batch) at step 0: 2.3195061683654785 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.316711187362671 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.3118293285369873 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.311530828475952 Seen so far: 38464 samples
以上