TensorFlow 2.0 Alpha : ガイド : Keras : TensorFlow Keras による訓練と評価 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 03/18/2019
* 本ページは、TensorFlow の本家サイトの TF 2.0 Alpha の以下のページを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、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 で構築されたモデルそしてモデル・サブクラス化でスクラッチから書かれたモデル — に渡り厳密に同じように動作します。
このガイドは分散訓練はカバーしません。
セットアップ
!pip install -q pydot !apt-get install graphviz
Requirement already satisfied: pydot in /usr/local/lib/python3.6/dist-packages (1.3.0) Requirement already satisfied: pyparsing>=2.1.4 in /usr/local/lib/python3.6/dist-packages (from pydot) (2.3.1) Reading package lists... Done Building dependency tree Reading state information... Done graphviz is already the newest version (2.40.1-2). 0 upgraded, 0 newly installed, 0 to remove and 10 not upgraded.
from __future__ import absolute_import, division, print_function !pip install -q tensorflow-gpu==2.0.0-alpha0 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)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 11493376/11490434 [==============================] - 0s 0us/step # Fit model on training data Train on 50000 samples, validate on 10000 samples Epoch 1/3 50000/50000 [==============================] - 5s 110us/sample - loss: 0.3377 - sparse_categorical_accuracy: 0.9053 - val_loss: 0.2020 - val_sparse_categorical_accuracy: 0.9402 Epoch 2/3 50000/50000 [==============================] - 5s 107us/sample - loss: 0.1576 - sparse_categorical_accuracy: 0.9528 - val_loss: 0.1379 - val_sparse_categorical_accuracy: 0.9616 Epoch 3/3 50000/50000 [==============================] - 5s 106us/sample - loss: 0.1143 - sparse_categorical_accuracy: 0.9650 - val_loss: 0.1128 - val_sparse_categorical_accuracy: 0.9681 history dict: {'loss': [0.33772996835231783, 0.15758442388363184, 0.11431736122608185], 'sparse_categorical_accuracy': [0.90532, 0.95276, 0.96504], 'val_loss': [0.2019659897595644, 0.13788076196610927, 0.1128087827205658], 'val_sparse_categorical_accuracy': [0.9402, 0.9616, 0.9681]} # Evaluate on test data 10000/10000 [==============================] - 0s 36us/sample - loss: 0.1238 - sparse_categorical_accuracy: 0.9606 test loss, test acc: [0.12378974738866091, 0.9606] # Generate predictions for 3 samples predictions shape: (3, 10)
損失、メトリクスと optimizer を指定する
それでモデルを訓練するためには、損失関数、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='binary_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) return self.true_positives.assign_add(tf.reduce_sum(values)) # TODO: fix def result(self): return tf.identity(self.true_positives) # TODO: fix 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)
Epoch 1/3 50000/50000 [==============================] - 4s 76us/sample - loss: 0.0917 - binary_true_positives: 7792.0000 Epoch 2/3 50000/50000 [==============================] - 3s 67us/sample - loss: 0.0756 - binary_true_positives: 8026.0000 Epoch 3/3 50000/50000 [==============================] - 4s 70us/sample - loss: 0.0647 - binary_true_positives: 8459.0000
標準的なシグネチャに当てはまらない損失とメトリクスを処理する
損失とメトリクスの圧倒的な多数は 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)
50000/50000 [==============================] - 4s 75us/sample - loss: 2.5322 <tensorflow.python.keras.callbacks.History at 0x7f6051a72e10>
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)
50000/50000 [==============================] - 4s 76us/sample - loss: 0.3366 - std_of_activation: 0.9773 <tensorflow.python.keras.callbacks.History at 0x7f6051543e48>
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)
50000/50000 [==============================] - 4s 80us/sample - loss: 2.5158 - std_of_activation: 0.0020 <tensorflow.python.keras.callbacks.History at 0x7f605103ad30>
自動的に検証取り置き (= 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 [==============================] - 3s 82us/sample - loss: 0.3735 - sparse_categorical_accuracy: 0.8951 - val_loss: 0.2413 - val_sparse_categorical_accuracy: 0.9272 Epoch 2/3 40000/40000 [==============================] - 3s 82us/sample - loss: 0.1688 - sparse_categorical_accuracy: 0.9499 - val_loss: 0.1781 - val_sparse_categorical_accuracy: 0.9468 Epoch 3/3 40000/40000 [==============================] - 3s 79us/sample - loss: 0.1232 - sparse_categorical_accuracy: 0.9638 - val_loss: 0.1518 - val_sparse_categorical_accuracy: 0.9539 <tensorflow.python.keras.callbacks.History at 0x7f6050904f28>
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 [==============================] - 5s 7ms/step - loss: 0.3250 - sparse_categorical_accuracy: 0.9074 Epoch 2/3 782/782 [==============================] - 4s 6ms/step - loss: 0.1484 - sparse_categorical_accuracy: 0.9559 Epoch 3/3 782/782 [==============================] - 4s 5ms/step - loss: 0.1074 - sparse_categorical_accuracy: 0.9685 # Evaluate 157/157 [==============================] - 1s 3ms/step - loss: 0.1137 - sparse_categorical_accuracy: 0.9665 [0.11368312350931062, 0.9665]
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, epochs=3, steps_per_epoch=100)
Epoch 1/3 100/100 [==============================] - 1s 11ms/step - loss: 0.7733 - sparse_categorical_accuracy: 0.8067 Epoch 2/3 100/100 [==============================] - 0s 5ms/step - loss: 0.3706 - sparse_categorical_accuracy: 0.8922 Epoch 3/3 100/100 [==============================] - 1s 5ms/step - loss: 0.3379 - sparse_categorical_accuracy: 0.9011 <tensorflow.python.keras.callbacks.History at 0x7f60504173c8>
検証 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 [==============================] - 7s 8ms/step - loss: 0.3440 - sparse_categorical_accuracy: 0.9020 - val_loss: 0.1838 - val_sparse_categorical_accuracy: 0.9490 Epoch 2/3 782/782 [==============================] - 7s 9ms/step - loss: 0.1649 - sparse_categorical_accuracy: 0.9515 - val_loss: 0.1391 - val_sparse_categorical_accuracy: 0.9603 Epoch 3/3 782/782 [==============================] - 8s 10ms/step - loss: 0.1216 - sparse_categorical_accuracy: 0.9645 - val_loss: 0.1208 - val_sparse_categorical_accuracy: 0.9672 <tensorflow.python.keras.callbacks.History at 0x7f6050417908>
各エポックの最後に、モデルは検証 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 [==============================] - 9s 12ms/step - loss: 0.3359 - sparse_categorical_accuracy: 0.9053 - val_loss: 0.3095 - val_sparse_categorical_accuracy: 0.9187 Epoch 2/3 782/782 [==============================] - 7s 9ms/step - loss: 0.1593 - sparse_categorical_accuracy: 0.9528 - val_loss: 0.2196 - val_sparse_categorical_accuracy: 0.9438 Epoch 3/3 782/782 [==============================] - 7s 9ms/step - loss: 0.1158 - sparse_categorical_accuracy: 0.9661 - val_loss: 0.1840 - val_sparse_categorical_accuracy: 0.9469 <tensorflow.python.keras.callbacks.History at 0x7f604fe7da90>
検証 Dataset は各使用の後にリセットされることに注意してください (その結果エポックからエポックへ同じサンプル上で常に評価しています)。
Dataset オブジェクトから訓練するときには (訓練データから取り置いたセットを生成する) 引数 validation_split はサポートされません、何故ならばこの機能は (Dataset API では一般に可能ではない) dataset のサンプルをインデックスする能力を必要とするからです。
サポートされる他の入力フォーマット
Numpy 配列と TensorFlow Datasets の他にも、Pandas dataframe を使用したりバッチを yield する Python ジェネレータから Keras モデルを訓練することが可能です。
一般に、貴方のデータが小さくてメモリに収まるのであれば Numpy 入力データを使用し、そうでなければ Datsets を使用することを勧めます。
サンプル重み付けとクラス重み付けを使用する
入力データとターゲットデータの他にも、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)
Epoch 1/4 50000/50000 [==============================] - 4s 89us/sample - loss: 0.1040 - sparse_categorical_accuracy: 0.9715 Epoch 2/4 50000/50000 [==============================] - 4s 83us/sample - loss: 0.0872 - sparse_categorical_accuracy: 0.9751 Epoch 3/4 50000/50000 [==============================] - 4s 85us/sample - loss: 0.0734 - sparse_categorical_accuracy: 0.9789 Epoch 4/4 50000/50000 [==============================] - 4s 81us/sample - loss: 0.0657 - sparse_categorical_accuracy: 0.9818 Epoch 1/4 50000/50000 [==============================] - 4s 87us/sample - loss: 0.3647 - sparse_categorical_accuracy: 0.9063 Epoch 2/4 50000/50000 [==============================] - 5s 91us/sample - loss: 0.1703 - sparse_categorical_accuracy: 0.9525 Epoch 3/4 50000/50000 [==============================] - 4s 81us/sample - loss: 0.1276 - sparse_categorical_accuracy: 0.9647 Epoch 4/4 50000/50000 [==============================] - 4s 83us/sample - loss: 0.1016 - sparse_categorical_accuracy: 0.9719 <tensorflow.python.keras.callbacks.History at 0x7f604e5e2f98>
ここに適合している 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 [==============================] - 9s 11ms/step - loss: 0.3666 - sparse_categorical_accuracy: 0.9046 Epoch 2/3 782/782 [==============================] - 7s 9ms/step - loss: 0.1646 - sparse_categorical_accuracy: 0.9539 Epoch 3/3 782/782 [==============================] - 7s 9ms/step - loss: 0.1178 - sparse_categorical_accuracy: 0.9677 <tensorflow.python.keras.callbacks.History at 0x7f604edb7208>
データをマルチ入力、マルチ出力モデルに渡す
前の例では、単一の入力 (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()})
WARNING: Logging before flag parsing goes to stderr. W0305 23:50:32.918388 140053718652800 training_utils.py:1152] 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)
Epoch 1/3 100/100 [==============================] - 1s 6ms/sample - loss: 7.6847 - score_output_loss: 0.7406 - class_output_loss: 6.9441 Epoch 2/3 100/100 [==============================] - 0s 1ms/sample - loss: 7.0638 - score_output_loss: 0.3140 - class_output_loss: 6.7499 Epoch 3/3 100/100 [==============================] - 0s 1ms/sample - loss: 6.7368 - score_output_loss: 0.1928 - class_output_loss: 6.5440 Epoch 1/3 100/100 [==============================] - 0s 4ms/sample - loss: 6.4485 - score_output_loss: 0.1420 - class_output_loss: 6.3065 Epoch 2/3 100/100 [==============================] - 0s 4ms/sample - loss: 6.1095 - score_output_loss: 0.1428 - class_output_loss: 5.9667 Epoch 3/3 100/100 [==============================] - 0s 4ms/sample - loss: 5.8362 - score_output_loss: 0.1219 - class_output_loss: 5.7143 <tensorflow.python.keras.callbacks.History at 0x7f6051289128>
ここに 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 152ms/step - loss: 5.6598 - score_output_loss: 0.1304 - class_output_loss: 5.5127 Epoch 2/3 2/2 [==============================] - 0s 107ms/step - loss: 5.5597 - score_output_loss: 0.1229 - class_output_loss: 5.4204 Epoch 3/3 2/2 [==============================] - 0s 145ms/step - loss: 5.4660 - score_output_loss: 0.1176 - class_output_loss: 5.3324 <tensorflow.python.keras.callbacks.History at 0x7f6050417fd0>
コールバックを使用する
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 [==============================] - 4s 102us/sample - loss: 0.3712 - sparse_categorical_accuracy: 0.8955 - val_loss: 0.2237 - val_sparse_categorical_accuracy: 0.9325 Epoch 2/20 40000/40000 [==============================] - 4s 93us/sample - loss: 0.1754 - sparse_categorical_accuracy: 0.9483 - val_loss: 0.1784 - val_sparse_categorical_accuracy: 0.9440 Epoch 3/20 40000/40000 [==============================] - 3s 84us/sample - loss: 0.1255 - sparse_categorical_accuracy: 0.9619 - val_loss: 0.1583 - val_sparse_categorical_accuracy: 0.9514 Epoch 4/20 40000/40000 [==============================] - 4s 90us/sample - loss: 0.1003 - sparse_categorical_accuracy: 0.9703 - val_loss: 0.1404 - val_sparse_categorical_accuracy: 0.9587 Epoch 5/20 40000/40000 [==============================] - 4s 88us/sample - loss: 0.0829 - sparse_categorical_accuracy: 0.9757 - val_loss: 0.1332 - val_sparse_categorical_accuracy: 0.9617 Epoch 6/20 40000/40000 [==============================] - 4s 97us/sample - loss: 0.0705 - sparse_categorical_accuracy: 0.9789 - val_loss: 0.1341 - val_sparse_categorical_accuracy: 0.9641 Epoch 00006: early stopping <tensorflow.python.keras.callbacks.History at 0x7f604c45ff60>
多くの組み込み 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 39936/40000 [============================>.] - ETA: 0s - loss: 0.3635 - sparse_categorical_accuracy: 0.8971 Epoch 00001: val_loss improved from inf to 0.21655, saving model to mymodel_1.h5 40000/40000 [==============================] - 4s 108us/sample - loss: 0.3631 - sparse_categorical_accuracy: 0.8972 - val_loss: 0.2166 - val_sparse_categorical_accuracy: 0.9347 Epoch 2/3 39360/40000 [============================>.] - ETA: 0s - loss: 0.1669 - sparse_categorical_accuracy: 0.9506 Epoch 00002: val_loss improved from 0.21655 to 0.17676, saving model to mymodel_2.h5 40000/40000 [==============================] - 4s 97us/sample - loss: 0.1669 - sparse_categorical_accuracy: 0.9505 - val_loss: 0.1768 - val_sparse_categorical_accuracy: 0.9456 Epoch 3/3 39424/40000 [============================>.] - ETA: 0s - loss: 0.1232 - sparse_categorical_accuracy: 0.9624 Epoch 00003: val_loss improved from 0.17676 to 0.15663, saving model to mymodel_3.h5 40000/40000 [==============================] - 4s 99us/sample - loss: 0.1236 - sparse_categorical_accuracy: 0.9624 - val_loss: 0.1566 - val_sparse_categorical_accuracy: 0.9536 <tensorflow.python.keras.callbacks.History at 0x7f604bfdfe80>
モデルをセーブしてリストアするための貴方自身の 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 そして 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 モデルを再利用しましょう、そしてそれをカスタム訓練ループでミニバッチ勾配を使用して訓練しましょう。
# モデルを得ます。 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) # optimizer をインスタンス化します。 optimizer = keras.optimizers.SGD(learning_rate=1e-3) # 損失関数をインスタンス化します。 loss_fn = keras.losses.SparseCategoricalCrossentropy() # 訓練 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) # epochs に渡り iterate します。 for epoch in range(3): print('Start of epoch %d' % (epoch,)) # dataset のバッチに渡り iteratre します。 for step, (x_batch_train, y_batch_train) in enumerate(train_dataset): # forward パスの間に実行される演算を記録するために GradientTape をオープンします、 # これは自動微分を可能にします。 with tf.GradientTape() as tape: # 層の forward パスを実行します。 # 層がその入力に適用する演算は GradientTape 上で記録されていきます。 logits = model(x_batch_train) # Logits for this minibatch # このミニバッチに対する損失値を計算します。 loss_value = loss_fn(y_batch_train, logits) # 損失に関する訓練可能な重みの勾配を自動的に取得するために勾配テープを使用します。 grads = tape.gradient(loss_value, model.trainable_variables) # 損失を最小化するために重みの値を更新することにより勾配降下の 1 ステップを実行します。 optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 200 バッチ毎にログ記録します。 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.295337200164795 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.267664909362793 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.1268270015716553 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.0609934329986572 Seen so far: 38464 samples Start of epoch 1 Training loss (for one batch) at step 0: 1.9627395868301392 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.9132888317108154 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.7715450525283813 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.680647611618042 Seen so far: 38464 samples Start of epoch 2 Training loss (for one batch) at step 0: 1.554194450378418 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.5058209896087646 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.3611259460449219 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.2863078117370605 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_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 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.3286547660827637 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.297130823135376 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.168592929840088 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.037825107574463 Seen so far: 38464 samples Training acc over epoch: 0.2502399981021881 Validation acc: 0.4449000060558319 Start of epoch 1 Training loss (for one batch) at step 0: 1.9728939533233643 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.9893989562988281 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.7468760013580322 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.6020689010620117 Seen so far: 38464 samples Training acc over epoch: 0.5704200267791748 Validation acc: 0.6780999898910522 Start of epoch 2 Training loss (for one batch) at step 0: 1.476192831993103 Seen so far: 64 samples Training loss (for one batch) at step 200: 1.558509349822998 Seen so far: 12864 samples Training loss (for one batch) at step 400: 1.267077922821045 Seen so far: 25664 samples Training loss (for one batch) at step 600: 1.1969627141952515 Seen so far: 38464 samples Training acc over epoch: 0.7189000248908997 Validation acc: 0.7734000086784363
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=999790, shape=(), dtype=float32, numpy=6.8533154>]
追跡された損失はまず 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=999851, shape=(), dtype=float32, numpy=6.88884>]
訓練の間にこれらの損失を考慮するには、貴方が行なわなければならない総てのことは貴方の訓練ループを貴方のトータル損失に 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_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 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.747203826904297 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.5395843982696533 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.427178144454956 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.324587821960449 Seen so far: 38464 samples Start of epoch 1 Training loss (for one batch) at step 0: 2.322904586791992 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.334357976913452 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.3377459049224854 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.3055613040924072 Seen so far: 38464 samples Start of epoch 2 Training loss (for one batch) at step 0: 2.3104405403137207 Seen so far: 64 samples Training loss (for one batch) at step 200: 2.317152261734009 Seen so far: 12864 samples Training loss (for one batch) at step 400: 2.319432020187378 Seen so far: 25664 samples Training loss (for one batch) at step 600: 2.303823471069336 Seen so far: 38464 samples
以上