ニューラルネットワークの基礎知識 - 3

# 概要
今回はTensorflowを使って、１つの隠れ層を入れてネットワークを構築します。前回のベースにプログラムを書いているので、もし読んでいない場合は、まず
① [ニューラルネットワークの基礎知識 - 1](https://qiita.com/_dakc_/items/049ce4b43dd710dba945)
② [ニューラルネットワークの基礎知識 - 2](https://qiita.com/_dakc_/items/35e9db86296328f8c3fc)
を読むことをお勧めします。

# ネットワークを構成
今回作成するネットワークは、前回と同じく**入力層で３つのニューロン（ノード）**を持ち、**隠れ層で１つのニューロン**、そして**出力層でも１つのニューロン**を持ちます。

![](https://github.com/dakc/ai/blob/master/neural_network/with_single_hidden_layer.png?raw=true)
隠れ層のノードは簡単に増減できます。「ニューラルネットワークの基礎知識 - 2」で２つ以上のノードを入れる場合は、複雑なコードを書かなければならないが、Tensorflowを使う事で簡単にノードの増減ができます。また、LOSSを少なくするためにも数学の微分方程式を使っていましたが、そのあたりもTensorflowが私たちの代わりにやってくれますので、短いコードで読みやすいコードを書く事が出来ます。

# Let's Code
```python
# numpyのインポート
import numpy as np
# tensorflowのインポート
import tensorflow as tf
```

### 学習データの用意
```python
# ０：不合格、１：合格
# 合格状態のデータ
# 数学、英語、物理
inputs = np.array([
    [0,1,1],
    [1,0,0],
    [0,1,0],
    [1,0,1]]).astype(np.float32)

# ０：仕事見つからなかった、１：見つかった
# 仕事見つかった実績
outputs = np.array([
    [1],
    [1],
    [0],
    [1]]).astype(np.float32)
```

### 各パラメータの初期化
前回と同じくエポック数とlearning rateを設定します。

```python
# learning rateの初期化
lr = 0.1

# epochの初期化
epoch = 5000
```


Tensorflowを使って各層の処理を予め登録します。Tensorflowの基礎的な事については、ここはふれませんが、Tensorflowでは、先に処理を定義しておいて、そのあと実行するというイメージを持ってください。以下のようにまず処理を記述します。

```python
# 入力層のノードの数
input_feature = inputs.shape[1]

# 出力層のノードの数
# 自由に変えてOK
num_node = 1

# 入力層と隠れ層をつなぐ weightの初期化
weights_ih = tf.Variable( tf.random_uniform([input_feature,num_node] , minval=0.1 , maxval=0.9 , dtype=tf.float32))

# 入力層と隠れ層をつなぐbiasの初期化
bias_h = tf.Variable( tf.random_uniform( [num_node]   , minval=0.1 , maxval=0.9 , dtype=tf.float32  ))

# 隠れ層での予測
prediction_h  = tf.sigmoid( tf.matmul( inputs, weights_ih ) + bias_h )

# 隠れ層と出力層をつなぐweightの初期化
weights_ho = tf.Variable( tf.random_uniform( [num_node,1] , minval=0.1 , maxval=0.9 , dtype=tf.float32  ))

# 隠れ層と出力層をつなぐbiasの初期化
bias_o = tf.Variable( tf.random_uniform( [1]   , minval=0.1 , maxval=0.9 , dtype=tf.float32  ))

# 出力層での予測
prediction_o  = tf.sigmoid( tf.matmul( prediction_h, weights_ho ) + bias_o )

# lossの計算
loss = tf.reduce_sum( tf.square(outputs - prediction_o ) )

# gradient descentを使ってLossの最小化
train = tf.train.GradientDescentOptimizer(lr).minimize(loss)
```
以上で各プロセスの記述が終わりです。あとは実行するのみ。
### 学習実行
```python
with tf.Session() as sess:
  sess.run( tf.global_variables_initializer() )
  for step in range(epoch) :
    sess.run(train)

  weights_ih_f, bias_h_f, weights_ho_f, bias_o_f, error = sess.run([weights_ih, bias_h, weights_ho, bias_o, loss])

# 学習終了
print("Loss  : {:.8f}".format(error))
print("weight ih: ", weights_ih_f)
print("bias h : ", bias_h_f)
print("weights ho: ", weights_ho_f.T[0])
print("bias o : ", np.asscalar(bias_o_f))
```



### 評価
どのように学習したか評価します。

```python
# 結果を表示するための関数
def get_prediction(data):
    def activate(x):
        return 1/(1+np.exp(-x))
    pred_h = activate(np.dot(data, weights_ih_f) + bias_h_f)
    pred_o = activate(np.dot(pred_h, weights_ho_f) + bias_o_f)
    msg = "Hired" if round(np.asscalar(pred_o)) else "Not Hired"
    print(data, msg, np.asscalar(pred_o))

# 全科目合格の場合は、仕事見つかるか
get_prediction([1,1,1])

# 物理のみ不合格の場合は、仕事見つかるか
get_prediction([1,1,0])

# 全科目不合格の場合は、仕事見つかるか
get_prediction([0,0,0])
```

今回も、サンプルデータが少ない事とネットワークが単純すぎるから間違った答えがおおいかもしれませんが、基礎の理解という事でご許しください。


# Google Colab
直接Colabから実行することもできますので一度試してみてください。ちなみに、Colabのコメントはすべて英語です。
[using_tensorflow.ipynb](https://colab.research.google.com/github/dakc/ai/blob/master/neural_network/using_tensorflow.ipynb)

# 最後に
3つの記事を通してニューラルネットワークの基礎について説明しました。皆様の何かの参考になれば幸いです。もしミスや誤文字などがありましたらご指摘頂けたら修正します。