TensorFlow 2.4 : ガイド : 基本 – 基本的な訓練ループ (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 12/27/2020
* 本ページは、TensorFlow org サイトの Guide – TensorFlow Basics の以下のページを翻訳した上で
適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。 |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
ガイド : 基本 – 基本的な訓練ループ
前のガイドでは、tensor、変数、勾配テープそしてモジュールについて学習しました。このガイドでは、モデルを訓練するためにこれら総てを適合させます。
TensorFlow はまたボイラープレートを削減する有用な抽象を提供する高位ニューラルネットワーク API、tf.Keras API も含みます。けれども、このガイドでは、基本的なクラスを使います。
セットアップ
import tensorflow as tf
機械学習問題を解く
機械学習問題を解くことは通常は以下のステップから成ります :
- 訓練データを得る。
- モデルを定義する。
- 損失関数を定義する。
- 訓練データを通して実行し、理想的な値からの損失を計算する。
- その損失のための勾配を計算してそしてデータに適合させるために変数を調整するために optimizer を利用する。
- 結果を評価する。
例示目的で、このガイドでは単純な線形モデル $f(x) = x * W + b$ を開発します、これは 2 つの変数 : $W$ (重み) と $b$ (バイアス) を持ちます。
これは機械学習問題の最も基本です : $x$ と $y$ が与えられたとき、単純な線形回帰 を通して線 (= line) の傾きとオフセットを見つけようとします。
データ
教師あり学習は入力 (通常は x として記されます) と出力 (y として記され、しばしばラベルと呼ばれます) を使用します。目標は入力から出力の値を予測できるようにペアの入力と出力から学習することです。
データの各入力は、TensorFlow では、殆ど常に tensor で表されて、そしてそれはしばしばベクトルです。教師あり学習では、出力 (or 貴方が予測したい値) もまた tensor です。
ここに線に沿った点にガウス (正規) ノイズを追加することにより合成された幾つかのデータがあります。
# The actual line TRUE_W = 3.0 TRUE_B = 2.0 NUM_EXAMPLES = 1000 # A vector of random x values x = tf.random.normal(shape=[NUM_EXAMPLES]) # Generate some noise noise = tf.random.normal(shape=[NUM_EXAMPLES]) # Calculate y y = x * TRUE_W + TRUE_B + noise
# Plot all the data import matplotlib.pyplot as plt plt.scatter(x, y, c="b") plt.show()
tensor は通常はバッチ、あるいは一緒にスタックされた入力と出力のグループにまとめて集められます。バッチ処理は幾つかの訓練の恩恵を与えてアクセラレータとベクトル化計算で上手く動作します。このデータセットがどれほど小さいと仮定しても、データセット全体を単一バッチとして扱うことができます。
モデルを定義する
モデルの総ての重みを表すために tf.Variable を使用します。tf.Variable は値をストアしてこれを必要に応じて tensor 形式で提供します。より詳細は 変数ガイド を見てください。
変数と計算をカプセル化するために tf.Module を使用します。任意の Python オブジェクトを使用できたでしょうけれども、このようにしてそれは容易にセーブされます。
ここでは、変数として w と b を定義します。
class MyModel(tf.Module): def __init__(self, **kwargs): super().__init__(**kwargs) # Initialize the weights to `5.0` and the bias to `0.0` # In practice, these should be randomly initialized self.w = tf.Variable(5.0) self.b = tf.Variable(0.0) def __call__(self, x): return self.w * x + self.b model = MyModel() # List the variables tf.modules's built-in variable aggregation. print("Variables:", model.variables) # Verify the model works assert model(3.0).numpy() == 15.0
Variables: (<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>, <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=5.0>)
初期変数はここでは固定されたやり方で設定されますが、Keras の残りを伴ってもそうでなくても、Keras は利用可能な多くの initializer のどれかを装備します。
損失関数を定義する
損失関数は与えられた入力のためのモデルの出力がターゲット出力にどのくらい上手く一致しているかを測定します。目標は訓練の間にこの差を最小化することです。標準的な L2 損失を定義します、「平均二乗」誤差としても知られています :
# This computes a single loss value for an entire batch def loss(target_y, predicted_y): return tf.reduce_mean(tf.square(target_y - predicted_y))
モデルを訓練する前に、モデルの予測を赤色でそして訓練データを青色でプロットすることにより損失値を可視化できます :
plt.scatter(x, y, c="b") plt.scatter(x, model(x), c="r") plt.show() print("Current loss: %1.6f" % loss(model(x), y).numpy())
Current loss: 8.901840
訓練ループを定義する
訓練ループは 3 つのタスクを順番に反復して行なうことから成ります :
- 出力を生成するために入力のバッチをモデルに送る
- 出力を出力 (or ラベル) と比較することにより損失を計算します
- 勾配を見つけるために勾配テープを使用します
- それらの勾配で変数を最適化します
このサンプルについて、勾配降下 を使用してモデルを訓練できます。
tf.keras.optimizers で捕捉されている勾配降下スキームの多くの変種があります。しかし最初の原理から構築する精神で、ここでは基本的な数学を自動微分のための tf.GradientTape と値をデクリメントする tf.assign_sub (これは tf.assign と tf.sub を結合します) の手助けにより貴方自身で実装します :
# Given a callable model, inputs, outputs, and a learning rate... def train(model, x, y, learning_rate): with tf.GradientTape() as t: # Trainable variables are automatically tracked by GradientTape current_loss = loss(y, model(x)) # Use GradientTape to calculate the gradients with respect to W and b dw, db = t.gradient(current_loss, [model.w, model.b]) # Subtract the gradient scaled by the learning rate model.w.assign_sub(learning_rate * dw) model.b.assign_sub(learning_rate * db)
訓練を見ている間に、訓練ループを通して x と y の同じを送り、そして W
と b
がどのように進化するかを見ることができます。
model = MyModel() # Collect the history of W-values and b-values to plot later Ws, bs = [], [] epochs = range(10) # Define a training loop def training_loop(model, x, y): for epoch in epochs: # Update the model with the single giant batch train(model, x, y, learning_rate=0.1) # Track this before I update Ws.append(model.w.numpy()) bs.append(model.b.numpy()) current_loss = loss(y, model(x)) print("Epoch %2d: W=%1.2f b=%1.2f, loss=%2.5f" % (epoch, Ws[-1], bs[-1], current_loss))
print("Starting: W=%1.2f b=%1.2f, loss=%2.5f" % (model.w, model.b, loss(y, model(x)))) # Do the training training_loop(model, x, y) # Plot it plt.plot(epochs, Ws, "r", epochs, bs, "b") plt.plot([TRUE_W] * len(epochs), "r--", [TRUE_B] * len(epochs), "b--") plt.legend(["W", "b", "True W", "True b"]) plt.show()
Starting: W=5.00 b=0.00, loss=8.55563 Epoch 0: W=4.63 b=0.38, loss=5.97707 Epoch 1: W=4.33 b=0.69, loss=4.28069 Epoch 2: W=4.08 b=0.95, loss=3.16458 Epoch 3: W=3.88 b=1.15, loss=2.43017 Epoch 4: W=3.72 b=1.31, loss=1.94688 Epoch 5: W=3.59 b=1.44, loss=1.62882 Epoch 6: W=3.48 b=1.55, loss=1.41948 Epoch 7: W=3.39 b=1.64, loss=1.28169 Epoch 8: W=3.32 b=1.70, loss=1.19098 Epoch 9: W=3.26 b=1.76, loss=1.13127
# Visualize how the trained model performs plt.scatter(x, y, c="b") plt.scatter(x, model(x), c="r") plt.show() print("Current loss: %1.6f" % loss(model(x), y).numpy())
Current loss: 1.131265
同じ解法、しかし Keras で
上のコードを Keras の同値と対比することは有用です。
モデルを定義することは tf.keras.Model をサブクラス化する場合正確に同じに見えます。Keras モデルは究極的にはモジュールから継承することを覚えていてください。
class MyModelKeras(tf.keras.Model): def __init__(self, **kwargs): super().__init__(**kwargs) # Initialize the weights to `5.0` and the bias to `0.0` # In practice, these should be randomly initialized self.w = tf.Variable(5.0) self.b = tf.Variable(0.0) def __call__(self, x, **kwargs): return self.w * x + self.b keras_model = MyModelKeras() # Reuse the training loop with a Keras model training_loop(keras_model, x, y) # You can also save a checkpoint using Keras's built-in support keras_model.save_weights("my_checkpoint")
Epoch 0: W=4.63 b=0.38, loss=5.97707 Epoch 1: W=4.33 b=0.69, loss=4.28069 Epoch 2: W=4.08 b=0.95, loss=3.16458 Epoch 3: W=3.88 b=1.15, loss=2.43017 Epoch 4: W=3.72 b=1.31, loss=1.94688 Epoch 5: W=3.59 b=1.44, loss=1.62882 Epoch 6: W=3.48 b=1.55, loss=1.41948 Epoch 7: W=3.39 b=1.64, loss=1.28169 Epoch 8: W=3.32 b=1.70, loss=1.19098 Epoch 9: W=3.26 b=1.76, loss=1.13127
モデルを作成するたびに新しい訓練ループを書くのではなく、ショートカットとして Keras の組込み特徴を利用することができます。Python 訓練ループを書いたりデバッグすることを望まないときに有用であり得ます。
そうする場合、パラメータを設定するために model.compile() を、そして訓練するために model.fit() を使用する必要があります。再度ショートカットとして、L2 損失と勾配降下の Keras 実装を使用することはより少ないコードであり得ます。Keras 損失と optimizer はこれらの便利な関数の外でもまた利用できて、前のサンプルはそれらを利用できたでしょう。
keras_model = MyModelKeras() # compile sets the training paramaeters keras_model.compile( # By default, fit() uses tf.function(). You can # turn that off for debugging, but it is on now. run_eagerly=False, # Using a built-in optimizer, configuring as an object optimizer=tf.keras.optimizers.SGD(learning_rate=0.1), # Keras comes with built-in MSE error # However, you could use the loss function # defined above loss=tf.keras.losses.mean_squared_error, )
Keras fit はバッチ化データや完全なデータセットを NumPy 配列として想定します。NumPy 配列はバッチに切り刻まれて (= chop) 32 のバッチサイズがデフォルトとなります。
この場合、手書きループの動作に合わせるため、x
をサイズ 1000 の単一バッチとして渡すべきです。
print(x.shape[0]) keras_model.fit(x, y, epochs=10, batch_size=1000)
1000 Epoch 1/10 1/1 [==============================] - 0s 248ms/step - loss: 8.5556 Epoch 2/10 1/1 [==============================] - 0s 2ms/step - loss: 5.9771 Epoch 3/10 1/1 [==============================] - 0s 4ms/step - loss: 4.2807 Epoch 4/10 1/1 [==============================] - 0s 4ms/step - loss: 3.1646 Epoch 5/10 1/1 [==============================] - 0s 3ms/step - loss: 2.4302 Epoch 6/10 1/1 [==============================] - 0s 3ms/step - loss: 1.9469 Epoch 7/10 1/1 [==============================] - 0s 3ms/step - loss: 1.6288 Epoch 8/10 1/1 [==============================] - 0s 3ms/step - loss: 1.4195 Epoch 9/10 1/1 [==============================] - 0s 3ms/step - loss: 1.2817 Epoch 10/10 1/1 [==============================] - 0s 3ms/step - loss: 1.1910 <tensorflow.python.keras.callbacks.History at 0x7f4756125710>
Keras は訓練の前ではなく、訓練後に損失をプリントアウトするので、最初の損失がより低く見えますが、そうでなければこれは本質的には同じ訓練パフォーマンスを示すことに注意してください。
以上