scikit-learn、Spark.ml、TensorFlow で Perceptron〜（４）TensorFlow

TensorFlow はまだほとんど分かっていないので、[線形回帰](http://qiita.com/tud/items/58bd17b13f1cdf5ec12f)と同様、まだまだ見よう見まねです。
今回は簡単なニューラルネットなので、MNISTのtutorialを参考にしました。
mnist_softmax.py から今回使う部分を抜き出してみました。

```python:mnnist_softmax.py
import tensorflow as tf

# Create the model                                                                 
x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.matmul(x, W) + b

# Define loss and optimizer                                                        
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(
      tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
# Train                                                                            
for _ in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

# Test trained model                                                               
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images,
                                    y_: mnist.test.labels}))
```

# 4.1 学習データの準備
scikit-learn、spark.ml との違いは、label として数値ではなく、出力ノード数分の配列を用意し、対応するインデックスの値を 1、それ以外を 0 にすることです。
つまり、label が 0 or 1 の場合、scikit-learn、spark.ml では y = 0 or 1 と、y という変数を一つ用意しておけば良かったのですが、TensorFlow では、1 * 2 の行列を用意し、y=0 の時は [1, 0]、y=1 の時は [0, 1] という具合に値を設定しておく必要があります。 

```python:tfPC.py
# read train data                                                                    
import csv
def readArrayWithCSV(dataFile):
    features = []
    labels = []
    f = open(dataFile, 'r')
    reader = csv.reader(f)
    for row in reader:
        features.append([float(row[0]), float(row[1])])
        # row[2]==0 の時 [1,0]、row[2]==1 の時 [0,1] とする                          
        l = [0.0] * 2
        i = int(float(row[2]))
        l[i] = 1.0
        labels.append(l)
    return features,labels

trainFile = 'trainPC.csv'
train_features,train_labels = readArrayWithCSV(trainFile)
```

# 4.2 モデルの作成
ここは mint_softmax の入力ノード数と出力ノード数の変更のみです。
y_ はわかりにくくなりそうだったので、labに名前を変更しました。

```python:tfPC.py
import tensorflow as tf

# Create the model                                                                 
input_layer = 2
output_layer = 2
x = tf.placeholder(tf.float32, [None, input_layer])
W = tf.Variable(tf.zeros([input_layer, output_layer]))
b = tf.Variable(tf.zeros([output_layer]))
y = tf.matmul(x, W) + b

# Define loss and optimizer                                                          
lab = tf.placeholder(tf.float32, [None, output_layer])

cross_entropy = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(labels=lab, logits=y))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
```

sessionを開始して、学習させます。データは csv から読み込んだ値を numpy.array に変換してそのまま feed_dict で与えています。

```python:tfPC.py
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

# Train                                                                              
maxIter = 1000
for _ in range(maxIter):
    batch_xs = np.array(train_features)
    batch_labs = np.array(train_labels)
    sess.run(train_step, feed_dict={x: batch_xs, lab: batch_labs})
```

# 4.3 モデルを用いた予測
評価は、scikit-learn、spark.ml 同様、(0,0)〜(10,5)の 0.1単位のマトリックスに対する予測です。テストデータと共に正解データも作っておきます。

```python:tfPC.py
# (0, 0)-(10, 5)の範囲で 0.1 単位のマトリックスを作る                                
npax = np.arange(0.0, 10.0, 0.1)
npay = np.arange(0.0, 5.0, 0.1)
npx, npy = np.meshgrid(npax, npay)
npxy = np.c_[npx.ravel(), npy.ravel()]

# eval                                                                               
a = 0.4
b = 0.8
# a * npx + b < npy の時 [0,1]、そうでない時 [1,0] の配列=npz を作る                 
np1 = a * npx + b < npy
np0 = -np1
npz = np.c_[np0.ravel(), np1.ravel()].astype(np.float32)
```

mnistのサンプルでは出力が正解率のみですが、予測値も取得したいので、予測値の部分を predict = tf.argmax(y, 1) とし、run の第１引数を[predict, accuracy]のリストにして、リターン値をリストで取得するとうまく取れたようです。

```python:tfPC.py
predict = tf.argmax(y, 1)
correct_prediction = tf.equal(predict, tf.argmax(lab, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
npp, ac = sess.run([predict, accuracy], feed_dict={x: npxy, lab: npz})
npz = npp.reshape(npx.shape)

from plotPC import plotPC
title = "predPC_with_tensorflow"
plotPC(title, npx, npy, npz, a, b, maxIter, ac)
```

- argmax() は numpy.array.argmax() と同じく、行列の最大値のindexを取得します。学習データで y=0 → [1,0]、y=1 → [0,1] としましたが、逆をやってくれる関数になります。

```
>>> import numpy as np
>>> a = np.array([1,0])
>>> a.argmax()
0
>>> b = np.array([0,1])
>>> b.argmax()
1
>>> c = np.array([0,0,0,1])
>>> c.argmax()
3
```

繰り返し 100回と1000回の出力結果は以下です。100だとあまりいい結果にはなっていません。
![predPC_with_tensorflow_100.png](https://qiita-image-store.s3.amazonaws.com/0/175988/396346bd-e4fd-77f0-8d91-9dd07af9e5a5.png)
![predPC_with_tensorflow_1000.png](https://qiita-image-store.s3.amazonaws.com/0/175988/91c78954-6543-e458-7818-e75eed2ba424.png)

最後にプログラムの全体です。plotPCは、[scikit-learn編](http://qiita.com/tud/items/07059d77078b3e13b804)を参照ください。

```python:tfPC.py
import tensorflow as tf
import numpy as np

# read train data                                                                    
import csv
def readArrayWithCSV(dataFile):
    features = []
    labels = []
    f = open(dataFile, 'r')
    reader = csv.reader(f)
    for row in reader:
        features.append([float(row[0]), float(row[1])])
        # row[2]==0 の時 [1,0]、row[2]==1 の時 [0,1] とする                          
        l = [0.0] * 2
        i = int(float(row[2]))
        l[i] = 1.0
        labels.append(l)
    return features,labels

trainFile = 'trainPC.csv'
train_features,train_labels = readArrayWithCSV(trainFile)

# Create the model                                                                   
input_layer = 2
output_layer = 2
x = tf.placeholder(tf.float32, [None, input_layer])
W = tf.Variable(tf.zeros([input_layer, output_layer]))
b = tf.Variable(tf.zeros([output_layer]))
y = tf.matmul(x, W) + b

# Define loss and optimizer                                                          
lab = tf.placeholder(tf.float32, [None, output_layer])

cross_entropy = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(labels=lab, logits=y))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

# Train                                                                              
maxIter = 1000
for _ in range(maxIter):
    batch_xs = np.array(train_features)
    batch_labs = np.array(train_labels)
    sess.run(train_step, feed_dict={x: batch_xs, lab: batch_labs})

# (0, 0)-(10, 5)の範囲で 0.1 単位のマトリックスを作る                                
npax = np.arange(0.0, 10.0, 0.1)
npay = np.arange(0.0, 5.0, 0.1)
npx, npy = np.meshgrid(npax, npay)
npxy = np.c_[npx.ravel(), npy.ravel()]

# eval                                                                               
a = 0.4
b = 0.8
# a * npx + b < npy の時 [0,1]、そうでない時 [1,0] の配列=npz を作る                 
np1 = a * npx + b < npy
np0 = -np1
npz = np.c_[np0.ravel(), np1.ravel()].astype(np.float32)

predict = tf.argmax(y, 1)
correct_prediction = tf.equal(predict, tf.argmax(lab, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
npp, ac = sess.run([predict, accuracy], feed_dict={x: npxy, lab: npz})
npz = npp.reshape(npx.shape)

from plotPC import plotPC
title = "predPC_with_tensorflow"
plotPC(title, npx, npy, npz, a, b, maxIter, ac)
```