TensorFlow 2.0 : 上級 Tutorials : カスタマイズ :- カスタム訓練: 基本 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/28/2019
* 本ページは、TensorFlow org サイトの TF 2.0 – Advanced Tutorials – Customization の以下のページを
翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
カスタマイズ :- カスタム訓練: 基本
前のチュートリアルでは、自動微分のための TensorFlow API をカバーしました — 機械学習のための基本的なビルディングブロックです。このチュートリアルでは前のチュートリアルで紹介された TensorFlow プリミティブを使用してある単純な機械学習を行ないます。
TensorFlow はまた tf.keras を含みます — 高位ニューラルネットワーク API で、これはボイラープレートを削減して柔軟性とパフォーマンスを犠牲にすることなく使用するために TensorFlow を容易にする有用な抽象を提供します。私達は開発のために tf.Keras API を強く推奨します。けれども、この短いチュートリアルでは最初の原理から強固な基礎を築くまでニューラルネットワークをどのように訓練するかを学習します。
Setup
from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf
Variable
TensorFlow の Tensor はイミュータブルでステートレスなオブジェクトです。けれども機械学習モデルは変化する状態を持たなければなりません : モデルの訓練につれて、予測を計算する同じコードが時間とともに異なる動作をするはずです (願わくばより小さい損失で!)。計算の進行に渡り変化する必要があるこの状態を表わすために、貴方は Python はステートフルなプログラミング言語であるという事実に頼ることを選択できます :
# Using Python state x = tf.zeros([10, 10]) x += 2 # This is equivalent to x = x + 2, which does not mutate the original # value of x print(x)
tf.Tensor( [[2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.] [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.]], shape=(10, 10), dtype=float32)
TensorFlow はステートフルな組み込み演算を持ち、これらは貴方の状態のための低位 Python 表現を使用するよりもしばしば容易です。モデルの重みを表現するために tf.Variable を使用します。
tf.Variable オブジェクトは値をストアしてそして暗黙的にこのストアされた値から読みます。TensorFlow variable にストアされた値を操作する演算 (tf.assign_sub, tf.scatter_update, etc) があります。
v = tf.Variable(1.0) # Use Python's `assert` as a debugging statement to test the condition assert v.numpy() == 1.0 # Reassign the value `v` v.assign(3.0) assert v.numpy() == 3.0 # Use `v` in a TensorFlow `tf.square()` operation and reassign v.assign(tf.square(v)) assert v.numpy() == 9.0
tf.Variable を使用する計算は勾配を計算するとき自動的に追跡されます。埋め込みを表わす variable については、TensorFlow はデフォルトでスパース更新を行ない、これはより計算及びメモリ効率的です。
tf.Variable の使用はまた貴方のコードの読み手に状態のピースがミュータブルであることを示す方法でもあります。
線形モデルをフィットさせる
ここまでに学習した概念を使用しましょう — Tensor, Variable と GradientTape — 単純なモデルを構築して訓練するためにです。これは典型的には幾つかのステップを伴います :
- モデルを定義する。
- 損失関数を定義する。
- 訓練データを取得する。
- 訓練データを通して実行してデータにフィットするように variable を調整するために “optimizer” を使用します。
ここで、単純な線形モデル, f(x) = x * W + b, を作成します、これは 2 つの variable: W (重み) と b (バイアス) を持ちます。上手く訓練されたモデルが W = 3.0 と b = 2.0 を持つようにデータを合成します。
モデルを定義する
variable と計算をカプセル化するために単純なクラスを定義しましょう :
class Model(object): def __init__(self): # Initialize the weights to `5.0` and the bias to `0.0` # In practice, these should be initialized to random values (for example, with `tf.random.normal`) self.W = tf.Variable(5.0) self.b = tf.Variable(0.0) def __call__(self, x): return self.W * x + self.b model = Model() assert model(3.0).numpy() == 15.0
損失関数を定義する
損失関数は与えられた入力に対するモデル出力がどのくらい上手くターゲット出力に適合しているかを測定します。ゴールは訓練の間にこの差を最小化することです。最小二乗エラーとしても知られる、標準的な L2 損失を使用しましょう :
def loss(predicted_y, target_y): return tf.reduce_mean(tf.square(predicted_y - target_y))
訓練データを得る
最初に、入力にランダム Gaussian (正規) ノイズを追加することにより訓練データを合成します :
TRUE_W = 3.0 TRUE_b = 2.0 NUM_EXAMPLES = 1000 inputs = tf.random.normal(shape=[NUM_EXAMPLES]) noise = tf.random.normal(shape=[NUM_EXAMPLES]) outputs = inputs * TRUE_W + TRUE_b + noise
モデルを訓練する前に、モデルの予測を赤色で訓練データを青色でプロットすることにより損失値を可視化します :
import matplotlib.pyplot as plt plt.scatter(inputs, outputs, c='b') plt.scatter(inputs, model(inputs), c='r') plt.show() print('Current loss: %1.6f' % loss(model(inputs), outputs).numpy())
<igure size 640x480 with 1 Axes> Current loss: 9.023272
訓練ループを定義する
ネットワークと訓練データで、損失を減少させるために重み変数 (W) とバイアス変数 (b) を更新するために 勾配降下 を使用してモデルを訓練します。tf.train.Optimizer で取り入れられた勾配降下スキームの多くの変種があります — 推奨される実装です。しかし最初の原理から構築するという考えで、ここでは自動微分のための tf.GradientTape と値を減らすために tf.assign_sub (これは tf.assign と tf.sub を組み合わせています) の助けを得て基本的な数学を貴方自身で実装します :
def train(model, inputs, outputs, learning_rate): with tf.GradientTape() as t: current_loss = loss(model(inputs), outputs) dW, db = t.gradient(current_loss, [model.W, model.b]) model.W.assign_sub(learning_rate * dW) model.b.assign_sub(learning_rate * db)
最後に、訓練データを通して繰り返し実行して W と b がどのように展開するか見てみましょう。
model = Model() # Collect the history of W-values and b-values to plot later Ws, bs = [], [] epochs = range(10) for epoch in epochs: Ws.append(model.W.numpy()) bs.append(model.b.numpy()) current_loss = loss(model(inputs), outputs) train(model, inputs, outputs, learning_rate=0.1) print('Epoch %2d: W=%1.2f b=%1.2f, loss=%2.5f' % (epoch, Ws[-1], bs[-1], current_loss)) # Let's plot it all 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()
Epoch 0: W=5.00 b=0.00, loss=9.02327 Epoch 1: W=4.57 b=0.39, loss=6.03162 Epoch 2: W=4.24 b=0.70, loss=4.14960 Epoch 3: W=3.98 b=0.96, loss=2.96514 Epoch 4: W=3.77 b=1.16, loss=2.21940 Epoch 5: W=3.61 b=1.32, loss=1.74968 Epoch 6: W=3.48 b=1.45, loss=1.45370 Epoch 7: W=3.38 b=1.55, loss=1.26711 Epoch 8: W=3.30 b=1.64, loss=1.14945 Epoch 9: W=3.24 b=1.70, loss=1.07522
以上