
ch = 16
class PolicyNetwork(Chain):
def __init__(self,n_class=10):
super(PolicyNetwork, self).__init__()
with self.init_scope():
self.l1=L.Convolution2D(in_channels = None, out_channels = ch, ksize = 3, pad = 1)
self.l2=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l3=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l4=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l5=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l6=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l7=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l8=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l9=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l10=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l11=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l12=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1)
self.l13=L.Convolution2D(in_channels = ch, out_channels = 10, ksize = 3, pad = 1)
self.fc1 = L.Linear(None, 512)
self.fc2 = L.Linear(512, n_class)
self.l13_bias=L.Bias(shape=(10))
def __call__(self, x):
h1 = F.relu(self.l1(x))
h2 = F.relu(self.l2(h1))
h3 = F.relu(self.l3(h2))
h4 = F.relu(self.l4(h3))
h5 = F.relu(self.l5(h4))
h6 = F.relu(self.l6(h5))
h7 = F.relu(self.l7(h6))
h8 = F.relu(self.l8(h7))
h9 = F.relu(self.l9(h8))
h10 = F.relu(self.l10(h9))
h11 = F.relu(self.l11(h10))
h12 = F.relu(self.l12(h11))
h = F.relu(self.l13(h12))
h = F.spatial_pyramid_pooling_2d(h, 3, F.MaxPooling2D)
h=self.fc1(h)
h=self.fc2(h)
return self.l13_bias(F.reshape(h, (-1, 10)))
動きはしたが、一向に収束に向かわない。。。ずっとaccuracy=0.1のままでした。
たぶん、パラメータ調整ができずにh = F.spatial_pyramid_pooling_2d(h, 3, F.MaxPooling2D)
でごまかした所為なのかもしれませんが、いずれにしても失敗。
ここは仕方なく、今回はあきらめました。
###(3)VGGモデルを変えて、Cifar10のフィッティング精度を見る
ということで、VGGLikeモデルを少し変更して以下の三種類をやってみました。
import chainer
import chainer.functions as F
import chainer.links as L
class VGG(chainer.Chain):
def __init__(self, n_class=10):
super(VGG, self).__init__()
with self.init_scope():
self.conv1_1 = L.Convolution2D(None, 64, 3, pad=1)
self.bn1_1 = L.BatchNormalization(64)
self.conv1_2 = L.Convolution2D(64, 64, 3, pad=1)
self.bn1_2 = L.BatchNormalization(64)
self.conv2_1 = L.Convolution2D(64, 128, 3, pad=1)
self.bn2_1 = L.BatchNormalization(128)
self.conv2_2 = L.Convolution2D(128, 128, 3, pad=1)
self.bn2_2 = L.BatchNormalization(128)
self.conv3_1 = L.Convolution2D(128, 256, 3, pad=1)
self.bn3_1 = L.BatchNormalization(256)
self.conv3_2 = L.Convolution2D(256, 256, 3, pad=1)
self.bn3_2 = L.BatchNormalization(256)
self.conv3_3 = L.Convolution2D(256, 256, 3, pad=1)
self.bn3_3 = L.BatchNormalization(256)
self.conv3_4 = L.Convolution2D(256, 256, 3, pad=1)
self.bn3_4 = L.BatchNormalization(256)
self.fc4 = L.Linear(None, 1024)
self.fc5 = L.Linear(1024, 1024)
self.fc6 = L.Linear(1024, n_class)
def __call__(self, x):
h = F.relu(self.bn1_1(self.conv1_1(x)))
h = F.relu(self.bn1_2(self.conv1_2(h)))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.relu(self.bn2_1(self.conv2_1(h)))
h = F.relu(self.bn2_2(self.conv2_2(h)))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.relu(self.bn3_1(self.conv3_1(h)))
h = F.relu(self.bn3_2(self.conv3_2(h)))
h = F.relu(self.bn3_3(self.conv3_3(h)))
h = F.relu(self.bn3_4(self.conv3_4(h)))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.dropout(F.relu(self.fc4(h)), ratio=0.5)
h = F.dropout(F.relu(self.fc5(h)), ratio=0.5)
h = self.fc6(h)
return h
少しNetworkの層を減らした以下のモデルでやってみました。
class VGG_tiny(chainer.Chain):
def __init__(self, n_class=10):
super(VGG_tiny, self).__init__()
with self.init_scope():
self.conv1_1 = L.Convolution2D(None, 64, 3, pad=1)
self.bn1_1 = L.BatchNormalization(64)
self.conv1_2 = L.Convolution2D(64, 64, 3, pad=1)
self.bn1_2 = L.BatchNormalization(64)
self.conv2_1 = L.Convolution2D(64, 128, 3, pad=1)
self.bn2_1 = L.BatchNormalization(128)
self.conv2_2 = L.Convolution2D(128, 128, 3, pad=1)
self.bn2_2 = L.BatchNormalization(128)
self.conv3_1 = L.Convolution2D(128, 256, 3, pad=1)
self.bn3_1 = L.BatchNormalization(256)
self.conv3_2 = L.Convolution2D(256, 256, 3, pad=1)
self.bn3_2 = L.BatchNormalization(256)
self.fc4 = L.Linear(None, 1024)
self.fc5 = L.Linear(1024, 1024)
self.fc6 = L.Linear(1024, n_class)
def __call__(self, x):
h = F.relu(self.bn1_1(self.conv1_1(x)))
h = F.relu(self.bn1_2(self.conv1_2(h)))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.relu(self.bn2_1(self.conv2_1(h)))
h = F.relu(self.bn2_2(self.conv2_2(h)))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.relu(self.bn3_1(self.conv3_1(h)))
h = F.relu(self.bn3_2(self.conv3_2(h)))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.dropout(F.relu(self.fc4(h)), ratio=0.5)
h = F.dropout(F.relu(self.fc5(h)), ratio=0.5)
h = self.fc6(h)
return h
そして、やはりBatchNormalizationが気持ち悪いということで削除する。
※Dropoutは単純に利用するパラメータをランダムにその割合で利用するように調整して、過学習を避ける工夫だが、BNは入力を再規格化してより収束しやすくしているのである意味入力調整というのがウワンはあまり好きになれない手法です。
以下では、結合が必要な入力と出力でNoneを使い、入力に応じて適切な値が入るように、そして出力も同じようにしました。また中間層の層を調整できるように変数としました。
ch=64
class VGG_tiny_nBn(chainer.Chain):
def __init__(self, n_class=10):
super(VGG_tiny_nBn, self).__init__()
with self.init_scope():
self.conv1_1 = L.Convolution2D(None, ch, 3, pad=1)
self.conv1_2 = L.Convolution2D(ch, ch, 3, pad=1)
self.conv2_1 = L.Convolution2D(ch, ch*2, 3, pad=1)
self.conv2_2 = L.Convolution2D(ch*2, ch*2, 3, pad=1)
self.conv3_1 = L.Convolution2D(ch*2, ch*4, 3, pad=1)
self.conv3_2 = L.Convolution2D(ch*4, ch*4, 3,pad=1)
self.fc4 = L.Linear(None, 1024)
self.fc5 = L.Linear(1024, 1024)
self.fc6 = L.Linear(1024, n_class)
def __call__(self, x):
h = F.relu(self.conv1_1(x))
h = F.relu(self.conv1_2(h))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.relu(self.conv2_1(h))
h = F.relu(self.conv2_2(h))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.relu(self.conv3_1(h))
h = F.relu(self.conv3_2(h))
h = F.max_pooling_2d(h, 2, 2)
h = F.dropout(h, ratio=0.25)
h = F.dropout(F.relu(self.fc4(h)), ratio=0.5)
h = F.dropout(F.relu(self.fc5(h)), ratio=0.5)
h = self.fc6(h)
return h
これら3つを比較するとほぼ似たような精度でよくフィッティング出来ていると思います。
model | train/loss | train/accuracy | val/loss | val/accuracy |
---|---|---|---|---|
VGG | 0.023532 | 0.99244 | 0.31353 | 0.9296875 |
VGG_tiny | 0.090028 | 0.96992 | 0.24947 | 0.93008 |
VGG_tiny_nBn | 0.11527 | 0.96155 | 0.25098 | 0.925435 |
やはりこのモデルはもともとBatchNormalizationが提案される前からのモデルであり、実際にも行った先(収束した状態)は、その有無であまり異ならないようだ。 | ||||
###まとめ | ||||
・Chainerの基本としてCifar10のフィッティングをおさらいした | ||||
・VGGLikeモデルについて、Networkモデルの違いによるフィッティング精度を見た | ||||
・将棋AIで使っているモデルでCifar10のフィッティングができるかどうか試みたが失敗した |
・次回は、いよいよVGGモデルで将棋AIを作ってみようと思う