ローリングコンバットピッチなう!

AIとか仮想化とかペーパークラフトとか

chainerお試し継続中(chainerでDCGAN)

[technology]DCGAN+chainerを試してたらこんな画像が出来た

そこそこchainer動かすのも慣れたのでDCGANを試したいと思い、色々サンプルソースを勉強。

以下のサイトとか、他にも色々参考にしつつ試行錯誤してみました。
blog.rystylee.com

class Disc(Chain):
    def __init__(self):
        super(Disc, self).__init__(
            conv1 = L.Convolution2D(in_channels=1, out_channels=16, ksize=5, stride=2, pad=2),
            conv2 = L.Convolution2D(in_channels=16, out_channels=64, ksize=5, stride=2, pad=2),
            conv3 = L.Convolution2D(in_channels=64, out_channels=128, ksize=5, stride=2, pad=2),
            conv4 = L.Convolution2D(in_channels=128, out_channels=256, ksize=5, stride=2, pad=2),            
            bn1 = L.BatchNormalization(16),
            bn2 = L.BatchNormalization(64),
            bn3 = L.BatchNormalization(128),
            bn4 = L.BatchNormalization(256),

            l3 = L.Linear(None, 1)
        )
    def forward(self, x,ratio=0.5):
        h = F.reshape(x,(len(x),1,64,64))
        h = F.dropout(F.leaky_relu(self.bn1(self.conv1(h))),ratio=ratio)
        h = F.dropout(F.leaky_relu(self.bn2(self.conv2(h))),ratio=ratio)
        h = F.dropout(F.leaky_relu(self.bn3(self.conv3(h))),ratio=ratio)
        h = F.dropout(F.leaky_relu(self.bn4(self.conv4(h))),ratio=ratio)
        h = self.l3(h)
        return h

class Gen3(Chain):
    def __init__(self):
        super(Gen3, self).__init__(
            l0 = L.Linear(None,256 * 4 * 4),
            deconv1 = L.Deconvolution2D(in_channels=256,out_channels=128,ksize=5,stride=2,pad=1),
            deconv2 = L.Deconvolution2D(in_channels=128,out_channels=64,ksize=5,stride=2,pad=2),
            deconv3 = L.Deconvolution2D(in_channels=64,out_channels=32 ,ksize=5,stride=2,pad=2),
            deconv4 = L.Deconvolution2D(in_channels=32 ,out_channels=1  ,ksize=5,stride=2,pad=2),
            bn0 = L.BatchNormalization(256 * 4 * 4),
            bn1 = L.BatchNormalization(128),
            bn2 = L.BatchNormalization(64),
            bn3 = L.BatchNormalization(32)
        )
    def forward(self, x,ratio=0.5): # x.shape = (n,512,4,4)
        h = F.dropout(F.leaky_relu(self.bn0(self.l0(x))),ratio=0.5)
        h = F.reshape(h,(len(h),256,4,4))
        h = F.dropout(F.leaky_relu(self.bn1(self.deconv1(h))),ratio=ratio)
        h = F.dropout(F.leaky_relu(self.bn2(self.deconv2(h))),ratio=ratio)
        h = F.dropout(F.leaky_relu(self.bn3(self.deconv3(h))),ratio=ratio)
        h = F.tanh(self.deconv4(h))
        h = h[:,:,:-1,:-1]
        h = F.reshape(h,(len(h),4096))
        return h

DiscriminatorとGeneratorの定義は上記の通りでメモリ量とか節約のためにかなりチャンネル数は抑さえ気味です。

コードの全容はそのうちGithubとかに上げようと思いますが、__call__じゃなくてforwardとか書いている様にDとGの相互の学習とかの制御も自分で組みました。

なかなか安定した画像が作れていないですが、某アイドルグループメンバーの写真を素材に学習させつつ、途中経過で出来の良いものだけ集めたのが以下の画像です。

学習が足りていないのか(それは間違いない..お化けみたいな画像もたくさん生成されている)、チャンネル数が足りないのか、写真風の画像が出ることを期待したのですが、イラストっぽい仕上がりに。
これはこれで良い気がしますが、同じネットワークを継続トレーニング中です。
そのうち写真っぽい画像が出るでしょうか?

2018/10/14追記: nVIDIA GTX1050でアクセラレーション出来る様になったので、がんがん学習させてみましたが、ある程度進むとモード崩壊に陥ってしまいました。絶対的に学習データ量が不足している気がします。



おまけ
DCGAN学習中に偶然出来た金爆さんっぽい画像。学習データに金爆さんは含まれておりません。

2018/10/28追記: 学習用データを200枚x2(左右フリップ)に増強、10000エポック回して作ったもの。
良いものだけ集めています。顔の崩れたものも多数生成。何度か試したのですが、これ以上回しても20000エポックくらいで必ずモード崩壊に至ります。ハイパーパラメーターを工夫すればモード崩壊に至らないのか、もっとデータを増やす必要があるのかは良く判らないです。
一応、Dにノイズ入れるとか、巷の情報に載っているテクニックは可能な限り入れているのですが。手が空いた時に学習用データを増やしていきたいと思います。自分がやったものだと、GTX1050で3Hくらいで10000エポック回せます。(同じ画像が2枚入っているのは画像連結時のミスです)

# 明らかに秋元真夏ちゃんっぽい顔が(笑)