TensorFlow 2.0 Alpha : 上級 Tutorials : カスタマイズ :- カスタム訓練: 基本 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 04/06/2019
* 本ページは、TensorFlow の本家サイトの TF 2.0 Alpha – Advanced Tutorials – Customization の以下のページを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
カスタマイズ :- カスタム訓練: 基本
前のチュートリアルでは自動微分のための TensorFlow API をカバーしました、機械学習のための基本的なビルディングブロックです。このチュートリアルでは前のチュートリアルで紹介された TensorFlow プリミティブを使用してある単純な機械学習を行ないます。
TensorFlow はまた高位ニューラルネットワーク API (tf.keras) を含み、これはボイラープレートを削減するために有用な抽象を提供します。ニューラルネットワークで作業する人々のためにこれらの高位 API を強く推奨します。けれども、この短いチュートリアルでは最初の原理から強固な基礎を築くまでのニューラルネットワーク訓練をカバーします。
Setup
from __future__ import absolute_import, division, print_function !pip install -q tensorflow==2.0.0-alpha0 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 表現よりもしばしば使用するに快適です。例えばモデルの重みを表現するには、TensorFlow variable を使用するのがしばしば便利で効率的です。
Variable は値をストアするオブジェクトで、TensorFlow 計算で使用されるときはこのストアされた値から暗黙的に読みます。TensorFlow variable にストアされた値を操作する演算 (tf.assign_sub, tf.scatter_update, etc) があります。
v = tf.Variable(1.0) assert v.numpy() == 1.0 # Re-assign the value v.assign(3.0) assert v.numpy() == 3.0 # Use `v` in a TensorFlow operation like tf.square() and reassign v.assign(tf.square(v)) assert v.numpy() == 9.0
Variable を使用する計算は勾配を計算するとき自動的に追跡されます。埋め込みを表わす Variable については TensorFlow はデフォルトでスパース更新を行ない、これはより多くの計算がかかりメモリ効率的です。
Variable の使用はまた貴方のコードの読み手に状態のこのピースがミュータブルであることを速やかに知らせる方法でもあります。
例題: 線形モデルをフィットさせる
さてここまでに持った幾つかの概念を並べますと — Tensor, GradientTape, Variable — 単純なモデルを構築して訓練するためにです。これは典型的には幾つかのステップを伴います :
- モデルを定義する。
- 損失関数を定義する。
- 訓練データを取得する。
- 訓練データを通して実行してデータにフィットするように 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 variable to (5.0, 0.0) # In practice, these should be initialized to random values. 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, desired_y): return tf.reduce_mean(tf.square(predicted_y - desired_y))
訓練データを得る
何某かのノイズを持つ訓練データを合成しましょう。
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: '), print(loss(model(inputs), outputs).numpy())
<Figure size 640x480 with 1 Axes> Current loss: 8.362566
訓練ループを定義する
今、ネットワークと訓練データを持ちました。それを訓練しましょう、i.e. 勾配降下 を使用して損失が下がるようにモデルの variable (W と b) を更新するために訓練データを使用します。tf.train.Optimizer 実装で取り入れられた勾配降下スキームの多くの変種があります。それらの実装の使用を強く推奨しますが、最初の原理から構築するという精神で、この特別な例では基本的な数学を私達自身で実装します。
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=8.36257 Epoch 1: W=4.63 b=0.37, loss=5.89098 Epoch 2: W=4.34 b=0.68, loss=4.24996 Epoch 3: W=4.09 b=0.92, loss=3.16041 Epoch 4: W=3.90 b=1.12, loss=2.43699 Epoch 5: W=3.73 b=1.29, loss=1.95668 Epoch 6: W=3.60 b=1.42, loss=1.63777 Epoch 7: W=3.50 b=1.53, loss=1.42603 Epoch 8: W=3.41 b=1.62, loss=1.28545 Epoch 9: W=3.34 b=1.69, loss=1.19211
以上