C++でTensorFlow

# 今回
前回と前々回はチュートリアルしかやって来なかったので、ここからは少し生産的な内容になればと思います…。

## **C++で学習させる**
前回は、Computation Graphの定義と実行の仕方をまとめました。
今回は、そのComputation Graphを繰り返し実行して学習を進めることを考えます。
***
tensorflow/cc/tutorials/example_trainer.cc
というexampleがあります。

このプログラムは、
A = [3 2; -1 0]
x = rand(2, 1)
として以下の計算を繰り返します。
x = y / y_norm
y = A * x
ではまずこの計算を行う、Computation Graphを作成する関数から確認しましょう。

```cpp
GraphDef CreateGraphDef() {                                                                         
  GraphDefBuilder b;
  using namespace ::tensorflow::ops;  // NOLINT(build/namespaces)                                                                            
  // Store rows [3, 2] and [-1, 0] in row major format.                                                                                      
  Node* a = Const({3.f, 2.f, -1.f, 0.f}, {2, 2}, b.opts());
  // x is from the feed.                                                                                                                     
  Node* x = Const({0.f}, {2, 1}, b.opts().WithName("x"));
  // y = A * x                                                                                                                               
  Node* y = MatMul(a, x, b.opts().WithName("y"));
  // y2 = y.^2                                                                                                                               
  Node* y2 = Square(y, b.opts());
  // y2_sum = sum(y2)                                                                                                                        
  Node* y2_sum = Sum(y2, Const(0, b.opts()), b.opts());
  // y_norm = sqrt(y2_sum)                                                                                                                   
  Node* y_norm = Sqrt(y2_sum, b.opts());
  // y_normalized = y ./ y_norm                                                                                                              
  Div(y, y_norm, b.opts().WithName("y_normalized"));
  GraphDef def;
  TF_CHECK_OK(b.ToGraphDef(&def));
  return def;
}
```
ここまでは前回までの内容で、説明不要でしょう。
(GraphDefBuilderに各ノードを追加してGraphDefを作成しています。)

さて、このグラフをn回*Mステップ実行しますが、example_trainere.ccではこれをMスレッドに分配してしています。
今回は簡単のため、1スレッドで実行するようなものを実装してみます。

```cpp
void Steps() {
  // Session作成                                                                                                         
  SessionOptions options;
  std::unique_ptr<Session> session(NewSession(options));
  GraphDef def = CreateGraphDef();
  session->Create(def);

  // Mステップ
  for (int step = 0; step < M; ++step) {
    // inputを乱数で初期化                                                                                                      
    Tensor x(DT_FLOAT, TensorShape({2, 1}));
    x.flat<float>().setRandom();

    // 各ステップはnum_iterations回計算する                                                                                                                
    std::vector<Tensor> outputs;
    for (int iter = 0; iter < n; ++iter) {
      outputs.clear();

      // 上で定義したComputation Graphを実行する。出力のTensorはoutputs
      session->Run({{"x", x}}, {"y:0", "y_normalized:0"}, {}, &outputs)
      CHECK_EQ(size_t{2}, outputs.size());

      const Tensor& y = outputs[0];
      const Tensor& y_norm = outputs[1];
      // Print out lambda, x, and y.                                                                                                       
      std::printf("%06d %s\n", step,
                  DebugString(x, y).c_str());
      // Copies y_normalized to x.                                                                                                         
      x = y_norm;
    }
  }

  session->Close();
}
```
Sessionを実行して、その結果を使用して更新、再び実行するというのを繰り返しているだけです。

また、オリジナルのexample_trainer.ccではこのMステップを更にN個の並列Sessionで行います。
ですがここでは簡単のため単一Sessionで行います。

```cpp
int main(int argc, char* argv[]) {
  // TensorFlowのセットアップ
  tensorflow::port::InitMain(argv[0], &argc, &argv);

  Steps();
}
```

これだけです！！

### tensorflow::Session::Runの引数
これは、[ここ](https://www.tensorflow.org/versions/r0.7/api_docs/cc/ClassSession.html#class-tensorflow-session)に記載されています。

```cpp
tensorflow::Session::Run(
  const std::vector< std::pair< string, Tensor > > &inputs,
  const std::vector< string > &output_tensor_names,
  const std::vector< string > &target_node_names,
  std::vector< Tensor > *outputs
)
```
例えば、

```cpp
session->Run({{"x", x}}, {"y:0", "y_normalized:0"}, {}, &outputs)
```
の場合、WithName("x")としたノードにxが入力として渡され、
WithName("y")とWithName("y_normalized")としたノードからの出力が、この順で、
outputsに入るのだと思います。
target_node_namesは…何だろう…

### **実行**
とりあえず、10ステップ50イテレーションで実行してみしょう。

```sh
$ bazel build tensorflow/my_work/...
$ bazel-bin/tensorflow/my_work/my_work
000009 lambda = 5.219631 x = [0.227381 0.252351] y = [1.186847 -0.227381]
000009 lambda = 2.616831 x = [0.982138 -0.188162] y = [2.570089 -0.982138]
000009 lambda = 2.235717 x = [0.934118 -0.356965] y = [2.088423 -0.934118]
000009 lambda = 2.105432 x = [0.912847 -0.408302] y = [1.921937 -0.912847]
000009 lambda = 2.050076 x = [0.903291 -0.429029] y = [1.851815 -0.903291]
000009 lambda = 2.024426 x = [0.898775 -0.438410] y = [1.819504 -0.898775]
000009 lambda = 2.012066 x = [0.896580 -0.442881] y = [1.803979 -0.896580]
000009 lambda = 2.005997 x = [0.895499 -0.445064] y = [1.796367 -0.895499]
000009 lambda = 2.002990 x = [0.894962 -0.446143] y = [1.792599 -0.894962]
000009 lambda = 2.001493 x = [0.894694 -0.446679] y = [1.790724 -0.894694]
000009 lambda = 2.000746 x = [0.894561 -0.446947] y = [1.789788 -0.894561]
(略)
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
000009 lambda = 2.000000 x = [0.894427 -0.447214] y = [1.788854 -0.894427]
```

行列[3 2; -1 0]の最大固有値2に収束しているので、きっと正解

(bazel is 何状態なのでそのうち調べたいです…)

この例は、機械学習というか数値計算的（出力が次の入力になるだけ）なものだったので、
じゃあBack Propagationとかどうやんの！
とか言われたらまだわからないですね…