TensorFlowで2次曲線を予測してみる

チュートリアルでは TensorFlow で 1 次関数を予測していたので,試しに 2 次関数もできるのかやってみました.

1 次関数

Get Started の Introduction には,テキトーに与えられた値から直線を推測するモデルが載っています.

$$ y=0.1x+0.3 $$

このチュートリアルでは,最終的にこの式の傾きと切片を求めています.

ソースコード

import tensorflow as tf
import numpy as np

# x 座標をランダムに 100 個生成
x_data = np.random.rand(100).astype(np.float32)
# y = 0.1 * x + 0.3 に従うように,上で生成した x 座標から y 座標を生成
y_data = x_data * 0.1 + 0.3

# y_data = W * x_data + b の W, b を TensorFlow の学習により求めることを考える
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))
y = W * x_data + b

# 誤差の二乗を最小化することを考える
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)

# 最初に初期化する
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

# 学習する
for step in range(201):
    sess.run(train)
    if step % 20 == 0:
        print(step, sess.run(W), sess.run(b))

TensorFlow のページから引っ張ってきて英語のコメントをそれっぽく書き直しただけです.

201 回の繰り返しの中で,20 回実行するごとに Weight と bias の値を表示します.

実行結果

(0, array([-0.07949391], dtype=float32), array([ 0.54611921], dtype=float32))
(20, array([ 0.04311038], dtype=float32), array([ 0.33041847], dtype=float32))
(40, array([ 0.08662225], dtype=float32), array([ 0.30715299], dtype=float32))
(60, array([ 0.09685419], dtype=float32), array([ 0.30168205], dtype=float32))
(80, array([ 0.09926026], dtype=float32), array([ 0.3039555], dtype=float32))
(100, array([ 0.09982605], dtype=float32), array([ 0.0009302], dtype=float32))
(120, array([ 0.0999591], dtype=float32), array([ 0.30002189], dtype=float32))
(140, array([ 0.09999041], dtype=float32), array([ 0.30000514], dtype=float32))
(160, array([ 0.09999776], dtype=float32), array([ 0.3000012], dtype=float32))
(180, array([ 0.09999947], dtype=float32), array([ 0.30000031], dtype=float32))
(200, array([ 0.09999989], dtype=float32), array([ 0.30000007], dtype=float32))

step が増えるにつれて値が近くなっていくのが分かります.

200step 終えたところで,W = 0.09999989 ≒ 0.1, b = 0.30000007 ≒ 0.3 となり,かなり近い値に収束しています.

2 次関数

1 次関数がそれなりに求められることが分かったので,次は 2 次関数にしてみます.

求める 2 次関数の式は,次のように定めました.

$$y=0.4x^2+0.3x+0.1$$

ソースコード

import tensorflow as tf
import numpy as np

x_data = np.random.rand(100).astype(np.float32)
y_data = 0.4 * x_data * x_data + 0.3 * x_data + 0.1

W2 = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
W1 = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))
y = W2 * x_data * x_data + W1 * x_data + b

loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)

init = tf.initialize_all_variables()

sess = tf.Session()
sess.run(init)

for step in range(5001):
    sess.run(train)
    if step % 50 == 0:
        print(step, sess.run(W2), sess.run(W1), sess.run(b))

内容は 1 次式のものを 2 次式にしただけです.

繰り返し回数を 5001 回まで増やしました.

実行結果

2 次関数になると 200step では全然学習できていないので,ソースコードでは 5001 としていますが,4500step まで行いました.

(0, array([-0.29304981], dtype=float32), array([ 0.20357311], dtype=float32), array([ 0.84688079], dtype=float32))
(100, array([ 0.24236193], dtype=float32), array([ 0.46816367], dtype=float32), array([ 0.06746498], dtype=float32))
(200, array([ 0.27572295], dtype=float32), array([ 0.43257871], dtype=float32), array([ 0.07434835], dtype=float32))
  ...
(4300, array([ 0.39999321], dtype=float32), array([ 0.30000728], dtype=float32), array([ 0.09999858], dtype=float32))
(4400, array([ 0.39999443], dtype=float32), array([ 0.300006], dtype=float32), array([ 0.09999884], dtype=float32))
(4500, array([ 0.39999443], dtype=float32), array([ 0.300006], dtype=float32), array([ 0.09999884], dtype=float32))

W2 = 0.39999443 ≒ 0.4, W1 = 0.300006 ≒ 0.3, b = 0.09999884 ≒ 0.1 となり,かなり近い値が求められています.

まとめ

ある関数に従っている座標の値を与えることで,学習を用いて係数を求めることができる.