【将棋AI】「将棋AIで学ぶディープラーニング」を読む♪～Networkモデルの拡張；モデュレーション

<img width="200" style="float: left;" alt="将棋AIで学ぶディープラーニング" src="https://qiita-image-store.s3.amazonaws.com/0/233744/ded117b9-37c7-1b41-033d-960e63ca5fe1.jpeg">
第十八夜は、少しモデルをいじってみた。
###やったこと
（１）今までのモデルで総当たり戦をやってみた
（２）Resnetの繰り返しを２層から３層にしてみた
（３）さらなるNetworkモデルの拡張できるように層をモデュレートしてみた
###（１）今までのモデルで総当たり戦をやってみた
Networkモデルとして、Resnetの２３層と１３層を追加しました。これでResnetにおける層の深さの比較ができます。今回の記事全体のモデルは以下のとおりです。

| 名称 | loss | 一致率（方策） | 一致率（価値） |備考|
|:-:|:-:|:-:|:-:|:-:|
| [policy](https://github.com/MuAuan/dlShogi-kai/blob/master/Network/Policy/policy.py) |1.682677|0.4226734| -  |方策ネットワークのみ|
| [Policy_Value;Layer13](https://github.com/MuAuan/dlShogi-kai/blob/master/Network/Policy/policy_value.py)| 2.016|0.4204578|0.67033803|１３層の方策・価値ネットワークでMCTS|
| [ResnetSimple40※](https://github.com/MuAuan/dlShogi-kai/blob/master/Network/ResnetSimple/policy_value_resnetSimple.py)|2.29075|0.4325099|0.6906338|Resnet２０block４３層|
| [ResnetSimple20](ー)　|2.308355|0.4326057|0.6941468|Resnet１０block２３層|
| [ResnetSimple10](ー)|2.360802|0.42507267|0.6948055|Resnet５block１３層|
| [ResnetTry30](https://github.com/MuAuan/dlShogi-kai/blob/master/Network/ResnetTry/policy_value_resnetTry30.py)|2.27104|0.43431032|0.6986858|ResnetTri10block３３層|
| [ResnetVGGLike5](https://github.com/MuAuan/dlShogi-kai/blob/master/Network/VGGLike/policy_value_VGGNet.py)|2.279315|0.43526843|0.69514084|ResnetVGGLike５block１９層|
※前回の対戦と使用したパラメータが異なっています

下二つのモデルを除く結果は以下のようになりました。つまり、ここまでは層が深いほどよさそうです。が、Resnet無しが頑張っています。
![S102040MctsPolLkai.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/3fb3fbd7-1943-1985-1d36-3fcdeccc8984.jpeg)

###（２）Resnetの繰り返しを２層から３層にしてみた
モデルは以下のとおり、今までBlockとして二層ずつ追加したものを三層ずつ追加するように変更してみました。

```py
class Block(Chain):
    def __init__(self):
        super(Block, self).__init__()
        with self.init_scope():
            self.conv1 = L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
            self.conv2 = L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
            self.conv3 = L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)

    def __call__(self, x):
        h1 = F.relu(self.conv1(x))
        h2 = self.conv2(h1)
        h3 = self.conv3(h2)
        return F.relu(x+h3)
```
１０Blockにしたので、モデルは全部で３３層になります。
上記の結果もあるので、効果としてResnetとNormalとの中間の効果が出るといいなぁ～という程度です。
一致率等は上記の表のとおりです。
そして、結果は以下のようになりました。
※記事書いていて気が付いたけど、これ`h2 = F.relu(self.conv2(h1))`のミスですね
![Try3sen.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/69cb2b23-4ac2-f72d-07a6-01a43ba24090.jpeg)
![Try3sen2.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/4fbb74a6-30fa-2467-9b05-82ce38611cce.jpeg)
ミスはあったが、とりあえず、層の深さに依存して強さの順位となりました。

###（３）さらなるNetworkモデルの拡張できるように層をモデュレートしてみた
これらの延長として簡単にできるNetworkモデルの拡張をやってみた。本当はVGGNetに近づけたいが、テンソル計算の辻褄をつけるのが難しいのでとりあえずの拡張です。
【参考】
・[Chainerにおけるグラフ構造をループで書いてみる。](http://nonbiri-tereka.hatenablog.com/entry/2016/02/26/001608)

```py
ch = 192
fcl = 256
class RoopBlock(Chain):
    def __init__(self,n_in,n_out,stride=1):
        super(RoopBlock,self).__init__()
        with self.init_scope():
            self.conv1 = L.Convolution2D(in_channels = n_in, out_channels = n_out, ksize = 3, pad = 1)
            self.conv2 = L.Convolution2D(in_channels = n_out, out_channels = n_out, ksize = 3, pad = 1)
            self.conv3 = L.Convolution2D(in_channels = n_out, out_channels = n_in, ksize = 3, pad = 1)
    def __call__(self,x):
        h = F.relu(self.conv1(x))
        h = F.relu(self.conv2(h))
        h = F.relu(self.conv3(h)+x)
        return h    
 
class PolicyValueResnet(Chain):
    def __init__(self, blocks = 5):
        super(PolicyValueResnet, self).__init__()
        self.blocks = blocks
        with self.init_scope():
            self.l1=L.Convolution2D(in_channels = 104, out_channels = ch, ksize = 3, pad = 1)
            links = [("root0",RoopBlock(ch,ch))]
            n_in = ch
            n_out = 256
            for index in range(1,5,1):
                links += [("root{}".format(index),RoopBlock(n_in,n_out))]
                n_in *= 1
                n_out *= 1
            for link in links:
                self.add_link(*link)
            self.forward = links    
            # policy network
            self.policy=L.Convolution2D(in_channels = n_in, out_channels = MOVE_DIRECTION_LABEL_NUM, ksize = 1, nobias = True)
            self.policy_bias=L.Bias(shape=(9*9*MOVE_DIRECTION_LABEL_NUM))
            # value network
            self.value1=L.Convolution2D(in_channels = n_in, out_channels = MOVE_DIRECTION_LABEL_NUM, ksize = 1)
            self.value2=L.Linear(9*9*MOVE_DIRECTION_LABEL_NUM, fcl)
            self.value3=L.Linear(fcl, 1)

    def __call__(self, x):
        x = F.relu(self.l1(x))
        for name,func in self.forward:
            x = func(x)
        # policy network
        u_policy = self.policy(x)
        u_policy = self.policy_bias(F.reshape(u_policy, (-1, 9*9*MOVE_DIRECTION_LABEL_NUM)))
        # value network
        h_value = F.relu(self.value1(x))
        h_value = F.relu(self.value2(h_value))
        u_value = self.value3(h_value)
        return u_policy, u_value
```
そして、強さは以下のようにResnetS40と４：１：５とほぼ互角という結果であった。
![VGGvsS40.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/1f92e361-3e0e-2096-dc42-ae7b18128e49.jpeg)
このモデルは層も１９層であり、それほど深くもなく、かつ１epoch当たりの時間は、以下のとおり予測どおりである。

| model | time/epoch |層|
|:-:|:-:|:-:|
|S43| 57：10 |４３層|
|VGGL19| 45：19|１９層|
|S23| 37：59|２３層|
|S13| 30：30|１３層|
###まとめ
・層は深いほど強い
・同じ層を重ねるより、モデュレーションをかけた方が強くなる可能性がある

・まだまだNetworkモデルを工夫できる可能性がある