日本ディープラーニング協会 E資格 JDLA認定プログラム受講記録（その６）

[ラビットチャレンジ](http://ai999.careers/rabbit/)のＥ資格講座、ディープラーニングのＤａｙ４（最後）です。
[![card.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/8e9be486-3440-a3d1-db0c-2b7866601b10.png)
](http://ai999.careers/rabbit/)


[日本ディープラーニング協会 E資格 JDLA認定プログラム受講記録（その１）](https://qiita.com/awasirom/items/6cce5ca6d9c446edb2a4)
[日本ディープラーニング協会 E資格 JDLA認定プログラム受講記録（その２）](https://qiita.com/awasirom/items/8a4e91d0cd024dff6df3)
[日本ディープラーニング協会 E資格 JDLA認定プログラム受講記録（その３）](https://qiita.com/awasirom/items/df745bc67a6ca3c24ce4)
[日本ディープラーニング協会 E資格 JDLA認定プログラム受講記録（その４）](https://qiita.com/awasirom/items/2c97f3186ffbe2466dd8)
[日本ディープラーニング協会 E資格 JDLA認定プログラム受講記録（その５）](https://qiita.com/awasirom/items/f8e9c0895f5d69fef3a2)

---

セクションの構成は以下の通り。

Section 1) TensorFlowの実装演習
Section 2) 強化学習
　2-1 強化学習とは
　2-2 強化学習の応用例
　2-3 探索と利用のトレードオフ
　2-4 強化学習のイメージ
　2-5 強化学習の差分
　2-6 行動価値関数
　2-7 方策関数
　2-8 方策勾配法

#Section 1. TensorFlowの実装演習

####Tensor Flow

[Tensor Flow](https://www.tensorflow.org/)はGoogleが開発した機＜械学習に用いられるライブラリ。

＜基礎＞

- 定数の設定  
  a = tf.constant(0)
- セッションを実行しないと変数の値は設定されない。  
　sess = tf.Session()
　sess.run(X)
- プレイスホルダーは後で値を設定する変数の入れもの
　x = tf.placeholder()
- 変数  
  x =tf.Variable(1)

＜線形回帰＞
データを作成する$noise$と基準となる直線の式$d$を変更して結果を確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/3bec610c-1573-cd3e-cd19-a66f3391496c.png)

＜非線形回帰＞
データを作成する$noise$と基準となる曲線の式$d$を変更して結果を確認する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/bbe60ac0-3854-1513-cb81-8a10088404f0.png)

[try] 
- 次の式をモデルとして回帰を行おう
　$y=30x^{2}+0.5x+0.2$　
- 誤差が収束するようiters_numやlearning_rateを調整しよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/e07bf2e4-6880-3c52-3a8d-b5c101c8e496.png)


＜分類１層（mnist）＞

[try] x：入力値, d：教師データ, W：重み, b：バイアス をそれぞれ定義しよう

正解は以下の通り。

```python
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

iters_num = 100
batch_size = 100
plot_interval = 1

# -------------- ここを補填 ------------------------
x = tf.placeholder(tf.float32, [None, 784])
d = tf.placeholder(tf.float32, [None, 10])
W = tf.Variable(tf.random_normal([784, 10], stddev=0.01))
b = tf.Variable(tf.zeros([10]))
# ------------------------------------------------------

y = tf.nn.softmax(tf.matmul(x, W) + b)
```

入力の数は画像のドット数 28×28＝784 個、出力は0～9の10分類なので、それぞれ該当の箇所に入れれば良い。Wは各入力値から出力値に対して値があるので[784, 10]となる。バイアスの初期値は０が一般的で、各入力値に対しては共通で、出力値の数[10]だけ設定すれば世。

この実行結果は以下のようになった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/5a42e7ef-a2d9-cfc5-88e5-716bb89d6014.png)

＜分類３層（mnist）＞

中間層のノード数を変更して実行した結果は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/4a84c586-82ac-cb33-d9c5-f9336a5f4ebc.png)

ノード数が増えるほど精度は高くなるが計算時間は長くなる。むしろ中間層が少なくても試行回数を増やした方が早く正解率が上がっていく。
ノード数100-100で30000回の場合は95％以上、30-20でも50000回行えば91％以上になる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/0abb74bf-9716-c8de-baf7-6adbf97d990f.png)

Optimizerを変更した結果。
適切なパラメータがわからなかったので正解を参照しました。この中ではRMSPropが最も良い結果となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/bb441da2-7301-0776-f199-f9964bedcd01.png)

＜分類CNN（mnist）＞

構成は以下のようになっています。
conv - relu - pool - conv - relu - pool - affin - relu - dropout - affin - softmax

GPUなしで実行すると時間が掛かったのですが、Google ColabでGPUありで実行したらすぐに終わったので学習回数を300から1000に増やして実行してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/ba84d580-c345-fe35-8fa9-72298538b729.png)

[try] ドロップアウト率を0に変更しよう

0だけでなく、drop out = 0、0.25、0.5、0.75、学習回数＝300、3000で比べてみました。結果は以下のようになりましたがはっきりした違いはわかりませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/3893e46b-48b1-e048-5108-c50f0962edb0.png)

####Keras

- Tensor Flowのラッパー。
- 簡易にコードが書ける。初心者向き。
- 柔軟性はなく細かいことはTensor Flowなどで補う。

```python
# モデルを作成
model = Sequential()
model.add(Dense(input_dim=1, output_dim=1))

# モデルを表示
model.summary()

# モデルのコンパイル
model.compile(loss='mse', optimizer='sgd')

# 学習
for ...:
    loss = model.train_on_batch(x, d)
```
こんな感じでさっと書けてしまう。

＜線形回帰＞

ソースの実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/be3ad190-f539-5605-fdca-b908716d2b2c.png)

＜単純パーセプトロン（OR回路）＞

[try]
- np.random.seed(0)をnp.random.seed(1)に変更
- エポック数を100に変更
- AND回路, XOR回路に変更
- OR回路にしてバッチサイズを10に変更
- エポック数を300に変更しよう

以下は実行結果です。上から順に前の設定を引き継ぎながら行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/91e5839b-0a8e-87a0-8680-e57eb1b7b0cd.png)

XOR回路は線形回帰では解けない問題です。
これは以下の図でどの直線を引いても、同じ側に違う色が混ざってしまうことと同じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/de35501f-4384-7b53-631c-1ca3f563fdab.png)

＜分類（iris）＞

ビデオでは取り扱いがなかったのですがやってみました。

[try]

- 中間層の活性関数をsigmoidに変更しよう
- SGDをimportしoptimizerをSGD(lr=0.1)に変更しよう

となっています。デフォルトではReLU、SGD(lr=0.01)となっています。

またtrain_test_splitのモジュールが変わっているので修正しました。

```python
# from sklearn.cross_validation import train_test_split
from sklearn.model_selection import train_test_split
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/17e7c323-6c62-eb70-ff65-9b7e0fe3b5bf.png)

rl=0.1の方が少し良いようです。

＜分類（mnist）＞

このソース教材ではdata\mnist.pyをインポートしているのですが、私はGPUを使いたいので、Google Colab上でやっている関係で少し準備が要りました。

1. dataフォルダを自分のGoogleドライブのJupyter Notebookファイルが置いてある場所にアップロードする。
2. 以下のコードを追加。

```python
from google.colab import drive
drive.mount('/content/gdrive')

import sys
sys.path.append('dgrive/My Drive/Colab Notebooks')
```
これで data\mnist.py からインポートできるようになりました。
実行したらURLが指定されるのでそこを開いて認証用のキーを取得し、元の画面に戻ってキーを入力し完了。

[try]

- load_mnistのone_hot_labelをFalseに変更しよう (error)
- 誤差関数をsparse_categorical_crossentropyに変更しよう
- Adamの引数の値を変更しよう

one_hot_label=Falseにした場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/d83380ff-e911-8276-2a3a-06500aafc94d.png)

誤差関数をsparse_categorical_crossentropyにしたら、以下のように動作しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/dffa80a0-612e-60a3-ade6-dcd73478b2a9.png)

Adamの学習率を変えて実行した結果は以下の通り。一番小さい0.0001が良いようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/af3ee633-b008-0a55-8156-d720265bae42.png)

＜CNN分類（mnist）＞

kerasではCNNも簡単に実装できる。
Conv2D, MaxPooling2D, Dropout, Flatten, Denseなどを並べていくだけで出来てしまう。

演習用ソースのモデルは以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/88777d4b-072e-fcbd-8a00-642a6004b668.png)
入力は、28×28×1チャネルの画像。Conv2dでサイズが28→26→24と減っているのはkernel_size=(3,3)でパディングなしのため。チャネルは1→32→64と増えている。最後は10分類してSoftmax関数を掛けている。実行結果は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/056ab2ae-489f-22ec-7566-28d1342efca1.png)

Conv2d関数にpadding='same'を指定するとサイズが減らないようにパディングしてくれる。以下はその結果。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/16aed9d0-a56d-78a0-1eea-67b89b23208c.png)

その他、講義ビデオではVGG16で実装しなおす方法も説明していました。keras.applicationsにモデルがあるのでそれを使えば簡単にできるとのこと。ただし入力サイズが48以上でなければならないので、48×48×3にリサイズしていました。チャネルは１チャネルを３つ繰り返し。他にもResNet50など色々ある。

＜cifar10＞

http://www.cs.toronto.edu/~kriz/cifar.html
データセット cifar10
32x32ピクセルのカラー画像データ
10種のラベル「飛行機、自動車、鳥、猫、鹿、犬、蛙、馬、船、トラック」
トレーニングデータ数:50000, テストデータ数:10000

このデータセットでCNN。model.summary()は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/a96598cb-44ac-5699-0f5b-9e25c5e52d28.png)

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/25aaf71c-79d9-6b44-bf5d-2b4b5c97acb6.png)

kerasではBatch Normalizationも簡単に実装できる。
from keras.layers.normalization import BatchNormalization
として、Conv2dの後ろに、
model.add(BatchNormalization())
とすればよい。
cifar10のCNNにBatchNormalizationを追加したmodel.summary()と実行結果は以下の通り。

model.summary()
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/71da0159-160c-78cf-257a-a50abeaa0b25.png)

実行結果


＜ＲＮＮ＞

Kerasには、シンプルRNN、GRU、LSTM、LSTM2Dなど色々と用意されている。
Keras RNNのドキュメント [https://keras.io/ja/layers/recurrent/#simplernn](https://keras.io/ja/layers/recurrent/#simplernn)

演習用ソースは、2進数足し算の予測。
桁から桁へと繰り上がりの情報が伝わっていくためRNNとしている。

[try]

- RNNの出力ノード数を128に変更・・・（１）
- RNNの出力活性化関数を sigmoid に変更・・・（２）
- RNNの出力活性化関数を tanh に変更・・・（３）
- 最適化方法をadamに変更・・・（４）
- RNNの入力 Dropout を0.5に設定・・・（５）
- RNNの再帰 Dropout を0.3に設定・・・（６）
- RNNのunrollをTrueに設定・・・（７）

実行結果は以下の通り。


- （２）やはり精度が落ちました。
- ベースの設定値と（１）、（３）、（４）は精度が高く10000回目には100％になってしまい違いが判りませんでした。10000回以下で比べる必要がありそうです。
- （５）は汎化性能を高めるはずが下がってしまいました。なお（５）からランタイムのタイプをGPUからTPUに変更しました。そうしたところ約３分の１の時間短縮になりました。
- （６）は結果が更に悪くなってしまいました。
- （７）のunrollを指定すると、kerasのネットワークを展開しメモリは消費するが速度が向上するというのも。これを指定したら７０％程度の時間で済みました。

SimpleRNN以外のモデルも簡単に構築出来て、GRUであれば、
$model.add(SimpleRNN(...))$
の部分を、
$model.add(GRU(...))$
とするだけ。

実行結果は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/c173c97e-5f45-231b-f3b5-a57e00de03c7.png)

最終結果は良いですが２万回目位まではベースの設定より学習が遅いです。

今回は思ったような結果になっていないものが多く調整が必要だと思います。またベースの設定で精度が良すぎるので、精度の低いものをベースにした方が比較できて良かったと思います。もう少し色々と試してみたいと思います。

#強化学習

##2-1. 強化学習とは

- 教師あり学習、教師なし学習とも異なる機械学習の一分野
- 長期的に報酬を最大化出来るよう、環境の中で行動を選択できるエージェントを作成するのが目標
- 行動の結果として与えられる報酬をもとに行動を改善

##2-2. 強化学習の応用例

**エージェント**：プロフィールと購入履歴に基づいてキャンペンメールを送る顧客を決めるソフトウエア。
**行動**：顧客毎に送信、非送信を選ぶ。
**報酬**：コスト（負の報酬）と売り上げの推測（正の報酬）

##2-3. 探索と利用のトレードオフ

####探索が足りない
過去データのベストだけ選択⇒他により良い行動があっても見つけられない

####利用が足りない
未知の行動のみ選択⇒過去データの経験が生かせない

**※探索と利用はトレードオフ**

##2-4. 強化学習のイメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318589/f5c6c59c-3940-413f-d231-c9870c733608.png)

①　方策関数に基づいて選択した方策により行動すると、
②　状態がSになったことが観測され、
③　行動価値関数で決まる報酬が受け取れる。

この報酬を最大化するよう学習しながら①～③を繰り返す。

##2-5. 強化学習の差分

**教師なし学習／教師あり学習**：データに含まれるパターンを見つけ、そのデータから予測することが目標
**強化学習**：優れた方策を見つけることが目標

フィードバックという観点から以下のように違いを書いてあるサイトもありました。
**教師なし学習**：フィードバックがない
**教師あり学習**：すぐにフィードバックがある
**強化学習**：遅れてフィードバック（報酬）がある

##2-6. 行動価値関数

テキストでは以下のように書かれていましたが良く理解できませんでした。

---
行動価値関数とは
・価値を表す関数としては、状態価値関数と行動価値関数の2 種類がある

ある状態の価値に注目する場合は、状態価値関数
状態と価値を組み合わせた価値に注目する場合は、行動価値関数

---

こう解釈しましたがどうでしょう？

価値関数
- 状態価値関数と行動価値関数がある
- 状態価値関数：ある状態の価値に注目する場合
- 行動価値関数：状態と行動を組み合わせた価値に注目する場合

##2-7. 方策関数

ある状態でどのような行動を採るかの確率を与える関数。

確率にしているのは、状態が決まったら行動が一意に決まるようにしてしまうと、探索しなくなってしまうからだと思います。

##2-8. 方策勾配法

**方策反復法**：方策をモデル化して最適化する方法。その中でも有用な方法として**方策勾配法**がある。

方策勾配法では以下のように方策を更新していく。

```math
\theta^{(t+1)}=\theta^{(t)}+\epsilon\nabla J(\theta)
```

$\theta$：モデルをパラメータと表したもの
$J$：モデルに対する期待収益関数
$\epsilon$：学習率

**期待収益関数の定義**
- 平均報酬：報酬全ての平均
- 割引報酬和：過去になるほど報酬を割り引いて加算したもの
がある。

**方策勾配定理**

```math
\nabla_{\theta}J(\theta)={\mathbb E}_{\pi_{\theta}}[(\nabla_{\theta}log \pi_{\theta}(a|s) Q^{\pi}(s,a))]
```
$Q(s,a)$：行動価値関数

以下の２式から導出される

- 状態価値関数　$v(s) = \sum_{a}(\pi(a|s)Q(s,a))$
- ベルマン方程式 $Q(s,a) = \sum_{s'}(P(s'|s,a)[r(s,a,s') + \gamma V(s')])$


#確認テスト

#####Q1. 強化学習羽州に応用できそうな事例を考え、環境・エージェント・行動・報酬を具体的に挙げよ。

#####A1. 最近やっていないですが、趣味にしていたので将棋を挙げておきます。

事例：将棋
環境：局面
エージェント：プレーヤー
行動：次の手を決める
報酬：指し手の評価、あるいは、その手を指した時の局面の評価