TensorFlowチュートリアルをやってみた　第2回


[TensorFlowの公式チュートリアル](https://www.tensorflow.org/get_started/get_started)をやってみました
[TensorFlowチュートリアルをやってみた　第1回](http://qiita.com/taigamikami/items/1bda03d20928bf98f36e)の続き

## TensorFlow入門

### tf.trainAPI
TensorFlowには損失関数を最小限に抑えるために各変数をゆっくりと変更するオプティマイザが用意されている。

オプティマイザの設定はこんな感じ。

```python
>>>optimizer = tf.train.GradientDescentOptimizer(0.01)
>>>train = optimizer.minimize(loss)
```

とりあえず1000回学習させてみる。

```python
>>>sess.run(init) # reset values to incorrect defaults.
>>>for i in range(1000):
>>>  sess.run(train, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]})
>>>print(sess.run([W, b]))
```

そうすると最終的なモデルパラメータが得られる。

```python:printの出力
[array([-0.9999969], dtype=float32), array([ 0.99999082], dtype=float32)]
```


#### 完全なプログラム
インタプリタでやってきたことをまとめたソースコード
やっていることとしては簡単な回帰問題

```python
import tensorflow as tf

# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)

# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)

# training data
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x: x_train, y: y_train})
  
  # 学習の過程を見たいので追加
  if i%100 == 0:
      curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
      print("%d回 W: %s b: %s loss: %s"%(i,curr_W, curr_b, curr_loss))

# evaluate training accuracy
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
```

実行すると

```
0回 W: [-0.21999997] b: [-0.456] loss: 4.01814
100回 W: [-0.84270465] b: [ 0.53753263] loss: 0.14288
200回 W: [-0.95284992] b: [ 0.86137295] loss: 0.0128382
300回 W: [-0.98586655] b: [ 0.95844597] loss: 0.00115355
400回 W: [-0.99576342] b: [ 0.98754394] loss: 0.000103651
500回 W: [-0.99873012] b: [ 0.99626648] loss: 9.3124e-06

600回 W: [-0.99961936] b: [ 0.99888098] loss: 8.36456e-07
700回 W: [-0.99988592] b: [ 0.9996646] loss: 7.51492e-08
800回 W: [-0.99996579] b: [ 0.99989945] loss: 6.75391e-09
900回 W: [-0.99998969] b: [ 0.99996972] loss: 6.12733e-10
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
```

学習できていることがわかる。300回くらいでほとんど誤差が出ていない。


### tf.estimator
`tf.estimator`は以下のような機械学習の仕組みを簡素化するためのTensorFlowライブラリである。

- トレーニングループの実行
- 評価ループの実行
- データセットの管理

#### 基本的な使用方法
先程の線形回帰プログラムが簡素化されます。

```python
import tensorflow as tf
# NumPyは、データのロード、操作、および前処理によく使用されます。
import numpy as np

# 機能のリストを宣言する。 1つの数値機能しかありません。 より複雑で有用な他の多くのタイプの列があります。
feature_columns = [tf.feature_column.numeric_column("x", shape=[1])]

# 推定子は、トレーニング（フィッティング）と評価（推論）を呼び出すためのフロントエンドです。 線形回帰、線形分類、多くのニューラルネットワーク分類器および回帰子のような多くの事前定義型があります。次のコードは、線形回帰を行う推定器を提供します。
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)

# TensorFlowには、データセットを読み込んで設定するための多くのヘルパーメソッドが用意されています。
# ここでは、トレーニング用と評価用の2つのデータセットを使用します
# 私たちが望むデータのバッチ数（num_epochs）と各バッチの大きさを関数に伝えなければなりません。
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# このメソッドを呼び出してトレーニングデータセットを渡すことで、1000のトレーニングステップを呼び出すことができます。
estimator.train(input_fn=input_fn, steps=1000)

# モデルの評価
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)
```

出力

```
train metrics: {'loss': 1.2712867e-09, 'global_step': 1000}
eval metrics: {'loss': 0.0025279333, 'global_step': 1000}
```

#### カスタムモデル
ニューラルネットワークモデルを自分で作成する場合のestimatorの使い方

```python
import numpy as np
import tensorflow as tf

# 特徴のリストを宣言すると、実際の特徴は1つだけです
def model_fn(features, labels, mode):
  # 線形モデルを構築し、値を予測する
  W = tf.get_variable("W", [1], dtype=tf.float64)
  b = tf.get_variable("b", [1], dtype=tf.float64)
  y = W * features['x'] + b
  # Loss sub-graph
  loss = tf.reduce_sum(tf.square(y - labels))
  # Training sub-graph
  global_step = tf.train.get_global_step()
  optimizer = tf.train.GradientDescentOptimizer(0.01)
  train = tf.group(optimizer.minimize(loss),
                   tf.assign_add(global_step, 1))
  # EstimatorSpecは、作成したサブグラフを適切な機能に接続します。
  return tf.estimator.EstimatorSpec(
      mode=mode,
      predictions=y,
      loss=loss,
      train_op=train)

estimator = tf.estimator.Estimator(model_fn=model_fn)
# define our data sets
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# train
estimator.train(input_fn=input_fn, steps=1000)
# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)
```

出力

```
train metrics: {'loss': 1.227995e-11, 'global_step': 1000}
eval metrics: {'loss': 0.01010036, 'global_step': 1000}
```