Python(基本的なこと014: Tensorflow1.15と最小2乗法)
■サンプルデータに対してTensorflowを試す
まとめとして最小2乗法のサンプルデータに対してTensorflowを使ってみる。
データは下のようなもの。30人に対して100点を満点とする数学と国語のテストを行ったという想定。
番号 | 数学 | 国語 |
1 | 61 | 83 |
2 | 36 | 38 |
3 | 75 | 75 |
4 | 64 | 84 |
5 | 66 | 75 |
6 | 40 | 31 |
7 | 42 | 61 |
8 | 87 | 98 |
9 | 78 | 100 |
10 | 54 | 69 |
11 | 54 | 53 |
12 | 57 | 46 |
13 | 58 | 52 |
14 | 60 | 71 |
15 | 54 | 30 |
16 | 63 | 52 |
17 | 65 | 88 |
18 | 67 | 88 |
19 | 63 | 34 |
20 | 69 | 49 |
21 | 44 | 33 |
22 | 75 | 74 |
23 | 84 | 84 |
24 | 84 | 88 |
25 | 84 | 98 |
26 | 65 | 38 |
27 | 67 | 51 |
28 | 90 | 35 |
29 | 97 | 91 |
30 | 100 | 77 |
データ自体は、少し相関するように作成した。プロットしてみると下のような感じ(数学をx軸、国語をy軸とする)。
まず最小2乗法の推定の式を求める。
ExcelのINTERCEPT関数(切片)とSLOPE関数(傾き)が使用できそうなので、数学をx、国語をyとして上のデータを入れると次の式が得られる。
y = 0.824193751 * x + 9.837997239
この式を上の図にのせてみる(x = 3, 6, 9, 12 ~ 90とこれらの値を上の式に入れたときのyをプロットして線を引く)。点の傾向と直線を見るとそれらしい式と分かる。
また、最小2乗法は、この推定式と実際の点との差の合計(ここでは30人分の合計)を最小にするものであり、上の表と式から合計を求めると4995.302798となった(何となく合計を1/2しているけど)。これを求める式をtensorflowの損失関数とする。
では、tensorflowを使ってみる。コードは一番下に記載。
推定式、損失関数は下の通り。
損失関数が最も小さくなるように、学習率(learning_rate)の数値に応じて少しずつ、学習回数(training_epochs)の分だけ探っていく。learning_rate = 0.00001で実行すると、training_epochs 35万回あたりで損失関数の値が4995.303222656となり、それ以降は安定した。
tensorflowから得られたグラフは下の通り(オレンジ色)。
最小2乗法で得られたものと重なっていることが分かる。
損失関数の値はわずかに最小2乗法のものと異なるので、細かくみていけば(グラフ上では見えないぐらいの)若干のずれはあるだろうけど、tensorflowを使って最小2乗法を再現することができた。
今回までtensorflow v1.15を使用しているけど、すでにv2が出ており仕様も変わっているそう。v1.15についてはこれで一端終わりにする。いまだにlearning_rate, training_epochsの値はどうするのが適切なのかよく分からないけど、tensorflowのHelloworldレベルのものはできたと思う。
以下、コード。
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as mp
learning_rate = 0.00001
training_epochs = 500000
batch_size = 30
display_step = 1000
x_axis = [[3], [6], [9], [12], [15], [18], [21], [24], [27], [30], [33], [36], [39], [42], [45], [48], [51], [54], [57],
[60], [63], [66], [69], [72], [75], [78], [81], [84], [87], [90]]
# 最小2乗法で得た式に上のx_axisのデータを入れて得た値。x_axisとz_axi
y_axis_leastsqaure = [[12.31057849], [14.78315974], [17.255741], [19.72832225], [22.2009035], [24.67348475],
[27.14606601],
[29.61864726], [32.09122851], [34.56380976], [37.03639102], [39.50897227], [41.98155352],
[44.45413477],
[46.92671602], [49.39929728], [51.87187853], [54.34445978], [56.81704103], [59.28962229],
[61.76220354],
[64.23478479], [66.70736604], [69.1799473], [71.65252855], [74.1251098], [76.59769105],
[79.07027231],
[81.54285356], [84.01543481]]
y_axis_tf = []
# データ
math_point_data = [[61], [36], [75], [64], [66], [40], [42], [87], [78], [54], [54], [57], [58], [60], [54], [63], [65],
[67],
[63], [69], [44], [75], [84], [84], [84], [65], [67], [90], [97], [100]]
JapLang_point_data = [[83], [38], [75], [84], [75], [31], [61], [98], [100], [69], [53], [46], [52], [71], [30], [52],
[88],
[88], [34], [49], [33], [74], [84], [88], [98], [38], [51], [35], [91], [77]]
##############################################################################################################
##############################################################################################################
# tensorflowの部分
def inference(input_data):
init = tf.constant_initializer(value=0)
W = tf.get_variable("W", [1, 1], initializer=init)
b = tf.get_variable("b", [1, 1], initializer=init)
output = tf.matmul(input_data, W) + b
return output
def loss(output, actual_data):
loss = 1 / 2 * tf.reduce_sum(tf.math.square(actual_data - 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():
input_data = tf.placeholder("float", [None, 1])
actual_data = tf.placeholder("float", [None, 1])
output = inference(input_data)
cost = loss(output, actual_data)
global_step = tf.Variable(0, 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(math_point_data) / batch_size)
for i in range(0, total_batch, batch_size):
minibatch_xy = np.array(math_point_data[i:i + batch_size])
minibatch_z = np.array(JapLang_point_data[i:i + batch_size])
sess.run(train_op, feed_dict={input_data: minibatch_xy, actual_data: minibatch_z})
avg_cost += sess.run(
cost, feed_dict={input_data: minibatch_xy, actual_data: minibatch_z}
)
if epoch % display_step == 0:
print("Epoch: {:04d} cost: {:.9f}".format(epoch + 1, avg_cost))
print("Optimization Finished!")
for var in range(3, 91, 3):
result = sess.run(output, feed_dict={input_data: [[var]]})
y_axis_tf.append(result[0])
##############################################################################################################
##############################################################################################################
# 検証のためのプロット
mp.plot(x_axis, y_axis_leastsqaure, color="red")
mp.plot(x_axis, y_axis_tf, color="orange")
mp.scatter(math_point_data, JapLang_point_data, marker='.')
mp.grid()
mp.show()