Python(基本的なこと010: Tensorflow1.15_勾配降下法_簡単な方程式_試作)
■勾配降下法について、簡単な方程式で考えてみる。
前回までで、mnistのデータ、ソフトマックス関数や交差エントロピーについて見てきた。それぞれの部分で何をやっているかイメージがつかめてきたけど、下のコードの部分で何をやっているのかいまいちよく分からない。
def training(cost, global_step):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(cost, global_step=global_step)
return train_op
tf.train.GradientDescentOptimizer()から、勾配降下法(誤差(損失)が小さい方向に少しずつ移動して最小の値を探すもの)を使用しているはずだけど、mnistのサンプルではここの挙動がよく分からない。そのため、もっと簡単なデータでできないか試してみた。
使用したのは、下の方程式。最小となる点(x=0, y=5, z=10)から、xやyが大きくなる又は小さくなるに従ってzが大きくなる。
この式を使って、x, yをそれぞれ-49から50まで動かし、zの値を得る。(xの整数値)100×(yの整数値)100で10000の値が得られるので、その値から1000個分を訓練用としてピックアップする。データはExcelで作成。
次に、pythonのサンプルコードを下のように作成してみた。データ部分は省略。
import tensorflow as tf
import numpy as np
learning_rate = 0.1
training_epochs = 100
batch_size = 5
display_step = 1
batch_set = [[-21, 37], [-27, 27], ...(略)... , [-19, 26], [-47, -45]]
Excel_data = [[1475], [1223], ...(略)... , [812], [4719]]
def inference(x):
init = tf.constant_initializer(value=0)
W = tf.get_variable("W", [2, 1], initializer=init)
output = tf.matmul(x, W)
return output
def loss(output, y):
loss = tf.reduce_sum(y - output)
return loss
def training(cost, global_step):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(cost, global_step=global_step)
return train_op
with tf.Graph().as_default():
x = tf.placeholder("float", [None, 2])
y = tf.placeholder("float", [None, 1])
output = inference(x)
cost = loss(output, y)
global_step = tf.Variable(1, name="global_step", trainable=False)
train_op = training(cost, global_step)
init_op = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init_op)
for epoch in range(training_epochs):
avg_cost = 0
total_batch = int(len(batch_set) / batch_size)
for i in range(0, total_batch, batch_size):
minibatch_x = np.array(batch_set[i:i + batch_size])
minibatch_y = np.array(Excel_data[i:i + batch_size])
sess.run(train_op, feed_dict={x: minibatch_x, y: minibatch_y})
avg_cost += sess.run(
cost, feed_dict={x: minibatch_x, y: minibatch_y}
)
if epoch % display_step == 0:
print("Epoch: {:04d} cost: {:.9f}".format(epoch + 1, avg_cost))
result = sess.run(output, feed_dict={x: [[0, 5]]})
print("result", result)
print("Optimization Finished!")
ここで、 batch_setは(x, y)のセット、Excel_dataは方程式から求めたzの値としている。
inference(x)で、batch_setを入力して、zの推定の値outputを求める(output = w1 * x + w2 * y)。その後、 loss(output, y)で、そのoutputの値とExcel_data(zの真値)との差異を求める。さらに、その差異が小さくなるように training(cost, global_step)の勾配降下法を動かしていく。こんな形で学習して、最終的にはいい感じのW(w1, w2)が得られると思っていたけど、実際に動かした結果が下の画像。
学習が終わった後のSessionを使って最小部分(x=0, y=5)の値を求めれば、最小の10に近いものが得られるかと期待したけど、実際は11350.034。しかも、学習を繰り返すごとに値が大きくなってしまっている。
データの数が不十分なのか、差異を求めるところがおかしいのか、いろいろと見ていくところはありそう。