TensorFlow 2.0 Beta : ガイド : Keras : TensorFlow Keras による訓練と評価 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/17/2019
* 本ページは、TensorFlow の本家サイトの TF 2.0 Beta の以下のページを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
ガイド : Keras : TensorFlow Keras による訓練と評価
このガイドは 2 つの広範な状況における TensorFlow 2.0 の訓練、評価そして予測 (推論) モデルをカバーします :
- (model.fit(), model.evaluate(), model.predict() のような) 訓練 & 検証のための組み込み API を使用するとき。これは「Part I: 組み込み訓練 & 評価ループを使用する」のセクションでカバーされます。
- eager execution と GradientTape オブジェクトを使用してカスタム・ループをスクラッチから書くとき。これは「Part II: スクラッチから貴方自身の訓練 & 評価ループを書く」のセクションでカバーされます。
一般に、組み込みのループを使用していようが貴方自身のものを書いていようが、モデル訓練 & 評価は総ての種類の Keras モデル — Sequential モデル、Functional API で構築されたモデルそしてモデル・サブクラス化でスクラッチから書かれたモデル — に渡り厳密に同じように動作します。
このガイドは分散訓練はカバーしません。
セットアップ
from __future__ import absolute_import, division, print_function, unicode_literals !pip install -q tensorflow-gpu==2.0.0-beta0 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 # 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 momentum) – RMSprop() – Adam() – etc.
損失: – MeanSquaredError() – KLDivergence() – CosineSimilarity() – etc.
メトリクス: – AUC() – Precision() – Recall() – etc.
カスタム損失とメトリクスを書く
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 CatgoricalTruePositives(keras.metrics.Metric): def __init__(self, name='categorical_true_positives', **kwargs): super(CatgoricalTruePositives, 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.argmax(y_pred) values = tf.equal(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=[CatgoricalTruePositives()]) model.fit(x_train, y_train, batch_size=64, epochs=3)
Train on 50000 samples Epoch 1/3 50000/50000 [==============================] - 3s 51us/sample - loss: 0.0930 - categorical_true_positives: 7860.0000 Epoch 2/3 50000/50000 [==============================] - 2s 47us/sample - loss: 0.0775 - categorical_true_positives: 7764.0000 Epoch 3/3 50000/50000 [==============================] - 2s 48us/sample - loss: 0.0666 - categorical_true_positives: 8242.0000 <tensorflow.python.keras.callbacks.History at 0x7f1cb440e908>
標準的なシグネチャに当てはまらない損失とメトリクスを処理する
損失とメトリクスの圧倒的な多数は 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 40us/sample - loss: 2.4795 <tensorflow.python.keras.callbacks.History at 0x7f1cf01f2780>
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 43us/sample - loss: 0.3561 - std_of_activation: 0.9541 <tensorflow.python.keras.callbacks.History at 0x7f1cac5bcb00>
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 53us/sample - loss: 2.4790 - std_of_activation: 0.0018 <tensorflow.python.keras.callbacks.History at 0x7f1cac1957b8>
自動的に検証取り置き (= 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=3)
Train on 40000 samples, validate on 10000 samples Epoch 1/3 40000/40000 [==============================] - 2s 52us/sample - loss: 0.3724 - sparse_categorical_accuracy: 0.8943 - val_loss: 0.2273 - val_sparse_categorical_accuracy: 0.9327 Epoch 2/3 40000/40000 [==============================] - 2s 50us/sample - loss: 0.1716 - sparse_categorical_accuracy: 0.9486 - val_loss: 0.1749 - val_sparse_categorical_accuracy: 0.9457 Epoch 3/3 40000/40000 [==============================] - 2s 50us/sample - loss: 0.1237 - sparse_categorical_accuracy: 0.9633 - val_loss: 0.1500 - val_sparse_categorical_accuracy: 0.9556 <tensorflow.python.keras.callbacks.History at 0x7f1c584cf9e8>
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.3400 - sparse_categorical_accuracy: 0.9023 Epoch 2/3 782/782 [==============================] - 3s 4ms/step - loss: 0.1644 - sparse_categorical_accuracy: 0.9515 Epoch 3/3 782/782 [==============================] - 3s 4ms/step - loss: 0.1206 - sparse_categorical_accuracy: 0.9645 # Evaluate 157/157 [==============================] - 1s 4ms/step - loss: 0.1214 - sparse_categorical_accuracy: 0.9633 [0.12137069313410243, 0.9633]
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 9ms/step - loss: 0.8020 - sparse_categorical_accuracy: 0.7997 Epoch 2/3 100/100 [==============================] - 0s 4ms/step - loss: 0.3257 - sparse_categorical_accuracy: 0.9117 Epoch 3/3 100/100 [==============================] - 0s 4ms/step - loss: 0.2444 - sparse_categorical_accuracy: 0.9320 <tensorflow.python.keras.callbacks.History at 0x7f6ee4188978>
検証 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 6ms/step - loss: 0.3349 - sparse_categorical_accuracy: 0.9059 - val_loss: 0.1803 - val_sparse_categorical_accuracy: 0.9458 Epoch 2/3 782/782 [==============================] - 4s 5ms/step - loss: 0.1626 - sparse_categorical_accuracy: 0.9517 - val_loss: 0.1378 - val_sparse_categorical_accuracy: 0.9588 Epoch 3/3 782/782 [==============================] - 4s 5ms/step - loss: 0.1207 - sparse_categorical_accuracy: 0.9645 - val_loss: 0.1209 - val_sparse_categorical_accuracy: 0.9636 <tensorflow.python.keras.callbacks.History at 0x7f6ee4247630>
各エポックの最後に、モデルは検証 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.3368 - sparse_categorical_accuracy: 0.9046 - val_loss: 0.3341 - val_sparse_categorical_accuracy: 0.9062 Epoch 2/3 782/782 [==============================] - 3s 4ms/step - loss: 0.1596 - sparse_categorical_accuracy: 0.9518 - val_loss: 0.2450 - val_sparse_categorical_accuracy: 0.9344 Epoch 3/3 782/782 [==============================] - 3s 4ms/step - loss: 0.1163 - sparse_categorical_accuracy: 0.9658 - val_loss: 0.1822 - val_sparse_categorical_accuracy: 0.9516 <tensorflow.python.keras.callbacks.History at 0x7f6f737ca160>
検証 Dataset は各使用の後にリセットされることに注意してください (その結果エポックからエポックへ同じサンプル上で常に評価しています)。
Dataset オブジェクトから訓練するときには (訓練データから取り置いたセットを生成する) 引数 validation_split はサポートされません、何故ならばこの機能は (Dataset API では一般に可能ではない) dataset のサンプルをインデックスする機能を必要とするからです。
サポートされる他の入力フォーマット
Numpy 配列と TensorFlow Datasets の他にも、Pandas dataframe を使用したりバッチを yield する Python ジェネレータから Keras モデルを訓練することが可能です。
一般に、貴方のデータが小さくてメモリに収まるのであれば Numpy 入力データを使用し、そうでなければ Datset を使用することを勧めます。
サンプル重み付けとクラス重み付けを使用する
入力データとターゲットデータの他にも、fit を使用するときモデルに sample weights や class weights を渡すことも可能です :
- Numpy データから訓練するとき: sample_weight と class_weight arguments を通して。
- 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.} 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. model = get_compiled_model() model.fit(x_train, y_train, sample_weight=sample_weight, batch_size=64, epochs=4)
Train on 50000 samples Epoch 1/4 50000/50000 [==============================] - 3s 57us/sample - loss: 0.1040 - sparse_categorical_accuracy: 0.9710 Epoch 2/4 50000/50000 [==============================] - 3s 53us/sample - loss: 0.0843 - sparse_categorical_accuracy: 0.9763 Epoch 3/4 50000/50000 [==============================] - 3s 52us/sample - loss: 0.0733 - sparse_categorical_accuracy: 0.9794 Epoch 4/4 50000/50000 [==============================] - 3s 54us/sample - loss: 0.0622 - sparse_categorical_accuracy: 0.9825 Train on 50000 samples Epoch 1/4 50000/50000 [==============================] - 3s 58us/sample - loss: 0.3711 - sparse_categorical_accuracy: 0.9032 Epoch 2/4 50000/50000 [==============================] - 3s 56us/sample - loss: 0.1727 - sparse_categorical_accuracy: 0.9515 Epoch 3/4 50000/50000 [==============================] - 3s 55us/sample - loss: 0.1274 - sparse_categorical_accuracy: 0.9640 Epoch 4/4 50000/50000 [==============================] - 3s 53us/sample - loss: 0.1022 - sparse_categorical_accuracy: 0.9707 <tensorflow.python.keras.callbacks.History at 0x7f6e94442d30>
ここに適合している 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.3670 - sparse_categorical_accuracy: 0.9041 Epoch 2/3 782/782 [==============================] - 4s 5ms/step - loss: 0.1702 - sparse_categorical_accuracy: 0.9531 Epoch 3/3 782/782 [==============================] - 4s 5ms/step - loss: 0.1235 - sparse_categorical_accuracy: 0.9655 <tensorflow.python.keras.callbacks.History at 0x7f6e800e4198>
データをマルチ入力、マルチ出力モデルに渡す
前の例では、単一の入力 (shape (764,) の tensor) と単一の出力 (shape (10,) の予測 tensor) を持つモデルを考えていました。しかしマルチ入力か出力を持つモデルについてはどうでしょう?
次のモデルを考えます、それは shape (32, 32, 3) (それは (高さ、幅、チャネル)) の画像入力と shape (None, 10) (それは (時間ステップ, 特徴)) の時系列入力を持ちます。私達のモデルはこれらの入力の組み合わせから計算された 2 つの出力を持ちます : (shape (1,) の) 「スコア」と (shape (10,) の) 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 引数を使用して、異なる重みを異なる出力固有の損失に与えることもできます (例えば、ある人は私達の例の「スコア」損失にクラス損失の 2x の重要性を与えることにより、特権を与えることを望むかもしれません) :
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_weight={'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()})
W0614 15:24:50.742312 140118631720704 training_utils.py:1237] 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) # Alernatively, 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 [==============================] - 2s 19ms/sample - loss: 5.8944 - score_output_loss: 0.4273 - class_output_loss: 5.2204 Epoch 2/3 100/100 [==============================] - 0s 220us/sample - loss: 5.4873 - score_output_loss: 0.2532 - class_output_loss: 5.3883 Epoch 3/3 100/100 [==============================] - 0s 218us/sample - loss: 5.2755 - score_output_loss: 0.1834 - class_output_loss: 4.9630 Train on 100 samples Epoch 1/3 100/100 [==============================] - 0s 223us/sample - loss: 5.1277 - score_output_loss: 0.1491 - class_output_loss: 4.7050 Epoch 2/3 100/100 [==============================] - 0s 202us/sample - loss: 5.0121 - score_output_loss: 0.1738 - class_output_loss: 4.9349 Epoch 3/3 100/100 [==============================] - 0s 185us/sample - loss: 4.8906 - score_output_loss: 0.1341 - class_output_loss: 4.5652 <tensorflow.python.keras.callbacks.History at 0x7f6fc4f7ad30>
ここに 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 158ms/step - loss: 4.8489 - score_output_loss: 0.1605 - class_output_loss: 4.7043 Epoch 2/3 2/2 [==============================] - 0s 8ms/step - loss: 4.7991 - score_output_loss: 0.1543 - class_output_loss: 4.6607 Epoch 3/3 2/2 [==============================] - 0s 8ms/step - loss: 4.7527 - score_output_loss: 0.1506 - class_output_loss: 4.6180 <tensorflow.python.keras.callbacks.History at 0x7f6edc587c50>
コールバックを使用する
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 [==============================] - 2s 58us/sample - loss: 0.3607 - sparse_categorical_accuracy: 0.8988 - val_loss: 0.2391 - val_sparse_categorical_accuracy: 0.9283 Epoch 2/20 40000/40000 [==============================] - 2s 54us/sample - loss: 0.1734 - sparse_categorical_accuracy: 0.9487 - val_loss: 0.1696 - val_sparse_categorical_accuracy: 0.9481 Epoch 3/20 40000/40000 [==============================] - 2s 52us/sample - loss: 0.1302 - sparse_categorical_accuracy: 0.9609 - val_loss: 0.1531 - val_sparse_categorical_accuracy: 0.9543 Epoch 4/20 40000/40000 [==============================] - 2s 52us/sample - loss: 0.1032 - sparse_categorical_accuracy: 0.9690 - val_loss: 0.1516 - val_sparse_categorical_accuracy: 0.9530 Epoch 5/20 40000/40000 [==============================] - 2s 55us/sample - loss: 0.0856 - sparse_categorical_accuracy: 0.9743 - val_loss: 0.1376 - val_sparse_categorical_accuracy: 0.9587 Epoch 6/20 40000/40000 [==============================] - 2s 57us/sample - loss: 0.0728 - sparse_categorical_accuracy: 0.9778 - val_loss: 0.1300 - val_sparse_categorical_accuracy: 0.9608 Epoch 7/20 40000/40000 [==============================] - 2s 57us/sample - loss: 0.0619 - sparse_categorical_accuracy: 0.9811 - val_loss: 0.1254 - val_sparse_categorical_accuracy: 0.9622 Epoch 8/20 40000/40000 [==============================] - 2s 56us/sample - loss: 0.0532 - sparse_categorical_accuracy: 0.9833 - val_loss: 0.1409 - val_sparse_categorical_accuracy: 0.9611 Epoch 9/20 40000/40000 [==============================] - 2s 56us/sample - loss: 0.0465 - sparse_categorical_accuracy: 0.9856 - val_loss: 0.1430 - val_sparse_categorical_accuracy: 0.9613 Epoch 00009: early stopping <tensorflow.python.keras.callbacks.History at 0x7f6fc5319fd0>
多くの組み込み 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 39296/40000 [============================>.] - ETA: 0s - loss: 0.3841 - sparse_categorical_accuracy: 0.8929 Epoch 00001: val_loss improved from inf to 0.24046, saving model to mymodel_1.h5 40000/40000 [==============================] - 2s 62us/sample - loss: 0.3820 - sparse_categorical_accuracy: 0.8936 - val_loss: 0.2405 - val_sparse_categorical_accuracy: 0.9275 Epoch 2/3 39168/40000 [============================>.] - ETA: 0s - loss: 0.1763 - sparse_categorical_accuracy: 0.9483 Epoch 00002: val_loss improved from 0.24046 to 0.18944, saving model to mymodel_2.h5 40000/40000 [==============================] - 2s 54us/sample - loss: 0.1757 - sparse_categorical_accuracy: 0.9485 - val_loss: 0.1894 - val_sparse_categorical_accuracy: 0.9416 Epoch 3/3 39168/40000 [============================>.] - ETA: 0s - loss: 0.1276 - sparse_categorical_accuracy: 0.9628 Epoch 00003: val_loss improved from 0.18944 to 0.16058, saving model to mymodel_3.h5 40000/40000 [==============================] - 2s 56us/sample - loss: 0.1279 - sparse_categorical_accuracy: 0.9626 - val_loss: 0.1606 - val_sparse_categorical_accuracy: 0.9525 <tensorflow.python.keras.callbacks.History at 0x7f6fc4a6d438>
モデルをセーブしてリストアするための貴方自身の 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)
動的学習率スケジュールを実装するために 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. for epoch in range(3): 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.3184189796447754 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.3199896812438965 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.1944358348846436 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.114534378051758 Seen so far: 38464 samples Start of epoch 1 Training loss (for one batch) at step 0: 2.0546462535858154 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.9779424667358398 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.8572919368743896 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.7629480361938477 Seen so far: 38464 samples Start of epoch 2 Training loss (for one batch) at step 0: 1.7149815559387207 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.5529119968414307 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.44472336769104 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.3457978963851929 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. for epoch in range(3): 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.274200439453125 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.1641573905944824 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.9997265338897705 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.912804365158081 Seen so far: 38464 samples Training acc over epoch: 0.3887999951839447 Validation acc: 0.5658000111579895 Start of epoch 1 Training loss (for one batch) at step 0: 1.8960016965866089 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.7283663749694824 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.597784161567688 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.488420009613037 Seen so far: 38464 samples Training acc over epoch: 0.6281200051307678 Validation acc: 0.6930000185966492 Start of epoch 2 Training loss (for one batch) at step 0: 1.4787451028823853 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.3541656732559204 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.2644202709197998 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.1630260944366455 Seen so far: 38464 samples Training acc over epoch: 0.7215399742126465 Validation acc: 0.7721999883651733
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=843639, shape=(), dtype=float32, numpy=7.3508925>]
追跡された損失はまず 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=843700, shape=(), dtype=float32, numpy=7.0926685>]
訓練の間にこれらの損失を考慮するには、貴方が行なわなければならない総てのことは貴方の訓練ループを貴方のトータル損失に sum(model.losses) を追加するように変更することです :
optimizer = keras.optimizers.SGD(learning_rate=1e-3) for epoch in range(3): 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: 9.404867172241211 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.515528678894043 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.382564067840576 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.3394205570220947 Seen so far: 38464 samples Start of epoch 1 Training loss (for one batch) at step 0: 2.344683885574341 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.3267478942871094 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.3213391304016113 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.316208600997925 Seen so far: 38464 samples Start of epoch 2 Training loss (for one batch) at step 0: 2.325348138809204 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.3166375160217285 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.3118178844451904 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.3112611770629883 Seen so far: 38464 samples
以上