TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

ChainerでAlphaGoのSL policy networkを定義

AlphaGoのSL policy networkをとりあえず定義だけ作ってみました。

AlphaGoの論文から、SL policy networkは以下のようになると理解しています。

  • layer1は、5*5のフィルターk枚、ReLU関数
  • layer2~12は、3*3のフィルターk枚、ReLU関数
  • layer13は1*1のフィルター1枚で位置ごとに異なるバイアス
  • softmaxで出力

Chainerでは、畳み込みニューラルネットワークはConvolution2Dを使って定義できます。

layer13の位置ごとに異なるバイアスをどうすればいいか悩みましたが、
layer13にadd_paramでバイアスのパラメータを追加して、layer13の出力に追加したバイアスのパラメータを足してsoftmaxに入力するようにしてみました。

softmaxは1次元の関数しかないため、入力前にreshapeで1次元に変換しています。

特徴数をとりあえず1にして、適当な値で確認してみました。
とりあえず動いているようです。(あっているか自信なし)

次は、棋譜からデータを大量に生成して試してみるつもりです。

Pythonコード

GPUで実行する場合はコメントを外す(入れ替える)。

import numpy as np
import chainer
from chainer import Function, Variable, optimizers
#from chainer import cuda
from chainer import Link, Chain
import chainer.functions as F
import chainer.links as L

feature_num = 1
k = 192
model = Chain(
    layer1=L.Convolution2D(in_channels = feature_num, out_channels = k, ksize = 5, pad = 2),
    layer2=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer3=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer4=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer5=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer6=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer7=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer8=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer9=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer10=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer11=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer12=L.Convolution2D(in_channels = k, out_channels = k, ksize = 3, pad = 1),
    layer13=L.Convolution2D(in_channels = k, out_channels = 1, ksize = 1, nobias = True))

model.layer13.add_param('bias', (1, 19*19))
model.layer13.bias.data.fill(0)
#model.to_gpu()

optimizer = optimizers.SGD()
optimizer.setup(model)

board_data = np.array(
    [[[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]], dtype=np.float32)

board = Variable(board_data) # CPUの場合
#board = Variable(cuda.to_gpu(board_data))

t = Variable(np.array([5])) # CPUの場合
#t = Variable(cuda.to_gpu(np.array([5])))

def forward_backward(x, t):
    z1 = F.relu(model.layer1(x))
    z2 = F.relu(model.layer2(z1))
    z3 = F.relu(model.layer3(z2))
    z4 = F.relu(model.layer4(z3))
    z5 = F.relu(model.layer5(z4))
    z6 = F.relu(model.layer6(z5))
    z7 = F.relu(model.layer7(z6))
    z8 = F.relu(model.layer8(z7))
    z9 = F.relu(model.layer9(z8))
    z10 = F.relu(model.layer10(z9))
    z11 = F.relu(model.layer11(z10))
    z12 = F.relu(model.layer12(z11))
    u13 = model.layer13(z12)

    u13_1d = F.reshape(u13, (1, 19*19)) + model.layer13.bias

    loss = F.softmax_cross_entropy(u13_1d, t)
    print(loss.data)

    loss.backward()

for i in range(10):
    optimizer.zero_grads()
    forward_backward(board, t)
    optimizer.update()