TensorFlowでsin関数近似をする

TensorFlowの使い方の勉強を兼ねて、sin関数近似をするプログラムを解説します。

学習モデル
--
###パラメータの定義
X(入力値)とt(教師データ)について。Placeholderにトレーニングセットのデータを保存する
例えば、[None,5]は[任意×5]の行列を表しています。
tは、データ数を任意に取れるように[None,1]としておきます。

ｗ(重み)について。最適化の対象となるVariableに相当するものなので、tf.Variableクラスのインスタンスとして定義します。
初期値０の５×１行列にします。

これらにより入力層１、中間層５、出力層１のネットワークを作ります。

```py
x=tf.placeholder(tf.float32,[None,5])
w=tf.Variable(tf.zeros([5,1]))
t=tf.placeholder(tf.float32,[None,1])
```
###計算式
y=Xwの式は以下のように表現されます。
```
y=tf.matmul(x,w)
```
tf.matmulは行列の掛け算を行う関数で、先に定義したplaceholder xとVariable wを用いています。まだ具体的な値は入っておらず、ｙも具体的には決まっていません。

###誤差関数
教師データｔと出力ｙの差を二乗和を表しています。この二乗誤差を最小化していくように学習していきます。この際の最適化のアルゴリズムも選択します。

```py
loss=tf.reduce_sum(tf.square(y-t))
train_step=tf.train.AdamOptimizer().minimize(loss)
```

トレーニングの実行
--
###セッションの用意
トレーニングアルゴリズムの実行環境となる「セッション」を用いてVariableに相当する変数を計算していきます。
まずは新しいセッションを用意して、Variableを初期化します。

```py
sess=tf.Session()
sess.run(tf.initialize_all_variables())
```

###トレーニングデータセットの代入
Placeholderにトレーニングセットのデータを代入していきます。
train_tは実際のデータです。

```py
train_t=np.array([np.sin(2.0*np.pi*i/11) for i in range(12)])
train_t=train_t.reshape([12,1])

train_x=np.zeros([12,5])
for row,m in enumerate(range(1,13)):
    for col,n in enumerate(range(0,5)):
        train_x[row][col]=m**n
```

###最適化の実施
定義したトレーニングアルゴリズムtrain_stepを実行して、重みを修正していきます。
この時、feed_dictでPlaceholderに具体的な値をセットしています。
また、loss_valのように、セッション内でlossを評価し、その時点の値を取り出すこともできます。
そして、トレーニングを打ち切った後（forループを抜けだした後）の時点でのパラメータの値を出力します。

```py
i=0
for _ in range(100000):
    i+=1
    sess.run(train_step,feed_dict={x:train_x,t:train_t})
    if i % 1000==0:
        loss_val=sess.run(loss,feed_dict={x:train_x,t:train_t})
        print ('Step:%d, Loss:%f'%(i,loss_val))

w_val=sess.run(w)
print w_val
```

テスト
--
以下のような式でテスト結果の曲線を出力します。
y(x)=w0+w1*x+w2*x^2+w3*x^3+w4*x^4

```py
def predict(x):
    result=0.0
    for n in range(0,5):
        result+=w_val[n][0]* x**n
    return result
```

結果
--
中間層５層、学習回数10000回の時
プロットからずれてはいますがだいたい近似できているかと思います。
<img src=https://qiita-image-store.s3.amazonaws.com/0/184212/34acf056-ee50-ea5c-a8c8-f22c0d3ff9fa.png width=50%>

試しに中間層の数を変えてみると・・
中間層６層：よりずれてしまいました。
<img src=https://qiita-image-store.s3.amazonaws.com/0/184212/86188554-c7d9-47ef-3882-ea1b6fdbff63.png width=50%>

中間層４層：５層よりも近似できています。
<img src=https://qiita-image-store.s3.amazonaws.com/0/184212/1c0da9b2-0e84-7256-aac2-fe6350749929.png width=50%>

適切な中間層の数(ハイパーパラメータ)を指定するのも大事ですね。。

コード全文
--
```py:sin.py
#-*- coding:utf-8 -*-
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

x=tf.placeholder(tf.float32,[None,5]) 
w=tf.Variable(tf.zeros([5,1]))

y=tf.matmul(x,w)

t=tf.placeholder(tf.float32,[None,1])
loss=tf.reduce_sum(tf.square(y-t))
train_step=tf.train.AdamOptimizer().minimize(loss)

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

train_t=np.array([np.sin(2.0*np.pi*i/11) for i in range(12)])
train_t=train_t.reshape([12,1])

train_x=np.zeros([12,5])
for row,m in enumerate(range(1,13)):
    for col,n in enumerate(range(0,5)):
        train_x[row][col]=m**n

i=0
for _ in range(100000):
    i+=1
    sess.run(train_step,feed_dict={x:train_x,t:train_t})
    if i % 1000==0:
        loss_val=sess.run(loss,feed_dict={x:train_x,t:train_t})
        print ('Step:%d, Loss:%f'%(i,loss_val))

w_val=sess.run(w)
print w_val

def predict(x):
    result=0.0
    for n in range(0,5):
        result+=w_val[n][0]* x**n
    return result

fig=plt.figure()
subplot=fig.add_subplot(1,1,1)
subplot.set_xlim(1,12)
subplot.scatter(range(1,13),train_t)
linex=np.linspace(1,12,100)
liney=predict(linex)
subplot.plot(linex,liney)
plt.show()
```