目的
今更だけどtensorflow2.0あんま使ったことなかったのでお試しにいくつかやっていく予定。1.~と比較してnumpyの値がそのまま使用できたりSessionが無くなったり結構pytorchっぽくなった模様。
本記事では簡単な
y = 2x + 1
回帰の重みw = 2, b = 1を自動微分によってfittingする
事前準備
以下のパッケージが必要
- tensorflow (2.0以上)
- matplotlib
- numpy (多分tensorflowが入れば自動で入る)
データ作成
y = 2x + 1にちょこっとノイズを加えたdataset_y, dataset_yを作成する。
n_sample = 100
dataset_x = np.random.rand(n_sample)
dataset_y = 2 * dataset_x + 1 + np.random.normal(0, 0.05, n_sample) # ちょこっとノイズ加える
plot結果はこんな感じ
目的関数(重みパラメーター)の作成
傾きw, 切片bを定義。初期値はとりあえず0でいい。
w = tf.Variable(np.zeros([1,1]))
b = tf.Variable(np.zeros([1,1]))
これで入力xに対して目的関数を
y = w * x * b
で計算できる。pytorchと同じように普通に変数っぽく扱えてtensorの中身を確認できるのはめっちゃ便利になってる。
自動微分の計算
目的関数の傾きと切片を計算するためには計算したy(y = w * x + b)と真の値(datset_y)の誤差が最小になるようなw, bを探せば良いので
w, b = argmin (y_{dataset}- w \times x_{dataset} + b )^2
となれば良い。
loss = (y_{dataset}- w \times x_{dataset} + b )^2
に対して以下の微分
\frac{\delta loss }{\delta w} \\
\frac{\delta loss }{\delta b} \\
を計算して、lossが小さくなるようにw, bを更新していけば良い。
tensorflowでは自動微分ようにtf.GradientTapeというモジュールがある。
公式のドキュメントはここtf.GradientTape
今回は上記のlossに対しての微分なのでコードは以下のようになる
x = tf.constant(dataset_x)
with tf.GradientTape() as t:
t.watch(x) # tf.constantはwatachが必要らしい
y = w * x + b # object function
loss = tf.reduce_sum(tf.multiply(y - dataset_y, y - dataset_y)) # loss function
# 元の入力テンソル w, b に対する loss の微分
dloss_dparams = t.gradient(loss, [w, b]) # 自動微分
w = tf.Variable(tf.subtract(w, dloss_dparams[0] * 0.001)) # 値の更新
b = tf.Variable(tf.subtract(b, dloss_dparams[1] * 0.001)) # 値の更新
x, bに対する微分は同時にやってくれるっぽい。t.gradientの結果は普通にlistで微分結果のtensorが入っていた。
x = tf.constant(dataset_x)はdataset_xはnumpy.arrayなのでtf.GradientTapeで扱えるようにtf.constantに変換した。
※せっかくtf.Variableはmutableなのにミュータブルっぽくない書き方になってしまっている。そもそもtf.subtractはtf.Tensorを返すので上記のコードのように重みを更新する際は使用しないっぽい。
実際の重みパラメーターの更新はtensorflowでは普通はtf.optimizerを使用するので後述する。
learning_rate = 0.001で100回学習したコードはこちら
w = tf.Variable(np.zeros([1,1]))
b = tf.Variable(np.zeros([1,1]))
x = tf.constant(dataset_x)
loss_log = [] # lossの推移記録用
n_step = 100 # 学習回数
for i in range(n_step):
with tf.GradientTape() as t:
t.watch(x) # tf.constantはwatachが必要らしい
y = w * x + b # object function
loss = tf.reduce_sum(tf.multiply(y - dataset_y, y - dataset_y)) # loss function
# 元の入力テンソル w, b に対する loss の微分
dloss_dparams = t.gradient(loss, [w, b]) # 自動微分
w = tf.Variable(tf.subtract(w, dloss_dparams[0] * 0.001)) # 値の更新
b = tf.Variable(tf.subtract(b, dloss_dparams[1] * 0.001)) # 値の更新
loss_log.append(loss)
