TensorFlow : Tutorials : Eager : カスタム訓練: 基本 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/18/2018
* TensorFlow 1.9 でドキュメント構成が変わり新規にチュートリアル・ページも追加されました。
* 本ページは、TensorFlow 本家サイトの Tutorials – Research and Experimentation – Custom training: basics を翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、適宜、追加改変している場合もあります。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
前のチュートリアルでは自動微分のための TensorFlow API をカバーしました、機械学習のための基本的なビルディングブロックです。このチュートリアルでは前のチュートリアルで紹介された TensorFlow プリミティブを使用して何某かの単純な機械学習を行ないます。
TensorFlow はまた高位ニューラルネットワーク API (tf.keras) を含み、これはボイラープレートを削減するために有用な抽象を提供します。ニューラルネットワークで作業する人々のためにこれらの高位 API を強く推奨します。けれども、この短いチュートリアルでは最初の原理から強固な基礎を築くまでのニューラルネットワーク訓練をカバーします。
セットアップ
import tensorflow as tf tfe = tf.contrib.eager # Shorthand for some symbols tf.enable_eager_execution()
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)
Out:
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 = tfe.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 = tfe.Variable(5.0) self.b = tfe.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())
訓練ループを定義する
今、ネットワークと訓練データを持ちました。それを訓練しましょう、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()
以上