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()