DCGANによる顔画像の生成
データセットはみんな使ってるこれ。
画像サイズを28x28x3(RGB)に整形して入力とする。
ポイントは、batch_normalizationを導入すること、らしい。 これは、ミニバッチ毎にデータを標準化する手法。
各レイヤーのLeakyReluへの入力タイミングでbatch_normalizationを適用する。
以下のようなイメージ。
Generator
with tf.variable_scope('generator', reuse=not is_train): x1 = tf.layers.dense(z, 4*4*512) x1 = tf.reshape(x1, (-1, 4, 4, 512)) x1 = tf.layers.batch_normalization(x1, training=is_train) x1 = tf.maximum(0.2 * x1, x1) x2 = tf.layers.conv2d_transpose(x1, 256, 5, strides=3, padding='same') x2 = tf.layers.batch_normalization(x2, training=is_train) x2 = tf.maximum(0.2 * x2, x2) x3 = tf.layers.conv2d_transpose(x2, 128, 5, strides=2, padding='same') x3 = tf.layers.batch_normalization(x3, training=is_train) x3 = tf.maximum(0.2 * x3, x3) logits = tf.layers.conv2d_transpose(x3, out_channel_dim, 5, strides=1, padding='valid') out = tf.multiply(tf.tanh(logits), 0.5) return out
Discriminator
with tf.variable_scope('discriminator', reuse=reuse): x1 = tf.layers.conv2d(images, 64, 5, strides=2, padding='same') relu1 = tf.maximum(0.2 * x1, x1) x2 = tf.layers.conv2d(relu1, 128, 5, strides=2, padding='same') bn2 = tf.layers.batch_normalization(x2, training=True) relu2 = tf.maximum(0.2 * bn2, bn2) x3 = tf.layers.conv2d(relu2, 256, 5, strides=2, padding='same') bn3 = tf.layers.batch_normalization(x3, training=True) relu3 = tf.maximum(0.2 * bn3, bn3) flat = tf.reshape(relu3, (-1, 4*4*256)) logits = tf.layers.dense(flat, 1) out = tf.sigmoid(logits) return out, logits
あとハマりどころがコレ↓
Note: when training, the moving_mean and moving_variance need to be updated. By default the update ops are placed in tf.GraphKeys.UPDATE_OPS, so they need to be added as a dependency to the train_op. Also, be sure to add any batch_normalization ops before getting the update_ops collection. Otherwise, update_ops will be empty, and training/inference will not work properly. For example:
(引用)tf.layers.batch_normalization | TensorFlow
ということでOptimizerではこんな感じで更新を明示します
with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
discriminator_optimizer = tf.train.AdamOptimizer(learning_rate, beta1=beta1).minimize(discriminator_loss, var_list=discriminator_vars)
generator_optimizer = tf.train.AdamOptimizer(learning_rate, beta1=beta1).minimize(generator_loss, var_list=generator_vars)
結果
最初はランダムノイズです。
学習途中
(ミニバッチのLoss)
Discriminator Loss: 0.0795...
Generator Loss: 3.1901...
ふええ・・
学習途中
徐々に色があって顔っぽくなってきた。まだホラー。
学習途中
Discriminator Loss > Generator Lossになってきた辺りで、 顔っぽくなってきた。
学習停止直前
人の顔っぽくなってきたので、学習を打ち止めました。
ホラー感がなくなりましたね。
Discriminator Loss: 2.1258...
Generator Loss: 0.2235...
Discriminator Loss: 2.2205...
Generator Loss: 0.2133....
次は、Conditional-GANで遊んでみたいなあ。(小並感)