Denoising Autoencoder の実験をしてみる (5)
Denoising Autoencoder の実験をしてみる (4) - まんぼう日記 のつづき.今度は convolution / transposed convolution 使ってみました.
実験
これまで同様,MNISTの画像にごま塩とランダム平行移動のノイズを加えて denoising させます.
データの作り方等の詳細は前々回( Denoising Autoencoder の実験をしてみる (3) - まんぼう日記 )参照.プログラムはこちら: https://gist.github.com/takatakamanbou/01a529f38ac40f39a343c2bf619dccb6.TensorFlow 1.3 使ってます.
ネットワークの構成は次の通り.convX, convY_Tには Batch Normalization 組み込みました(conv6_Tを除く).
layer | type | output shape | 備考 |
---|---|---|---|
conv1 | convolution | 28 x 28 x 32 | kernel:4x4, stride:1, ReLU |
pool1 | max-pooling | 14 x 14 x 32 | kernel:2x2, stride:2 |
conv2 | convolution | 14 x 14 x 64 | kernel:4x4, stride:1, ReLU |
pool2 | max-pooling | 7 x 7 x 64 | kernel:2x2, stride:2 |
conv3 | convolution | 7 x 7 x 128 | kernel:4x4, stride:1, ReLU |
pool3 | max-pooling | 4 x 4 x 128 | kernel:2x2, stride:2 |
conv4_T | transposed-conv. | 7 x 7 x 64 | kernel:4x4, stride:2, ReLU |
conv5_T | transposed-conv. | 14 x 14 x 32 | kernel:4x4, stride:2, ReLU |
conv6_T | transposed-conv. | 28 x 28 x 1 | kernel:4x4, stride:2, linear |
で,結果はこんなん.CNN と書いてある行が今回の結果,MLP は前回の.sqeL は学習データで測った誤差(出力とノイズなしの教師との間の二乗誤差),sqeT はテストデータの誤差です.
ノイズを加えたテスト画像 | |
元の画像(正解) | |
CNN (sqeL = 9.72, sqeT = 11.67) | |
MLP (sqeL = 12.74, sqeT = 21.73) |
学習にかかった時間は,NVIDIA GeForce GTX 1080 使って3分ほど.CPUだけだと約35分でした.
いろいろ
Transposed Convolution 関係
今回一番苦労したのは,TensorFlow で Transposed Convolution(転置畳み込み,以下TC)を実装するとこでした. tf.nn.conv2d_transpose | TensorFlow 使うだけなんですが,引数の設定にいろいろ落とし穴がありまして.詳しくはソースを見てもらうとして,はまりそうなとこはこんな感じ:
- 第2引数
filter
の値の順序.[height, width, output_channels, in_channels]
となっていて, tf.nn.conv2d | TensorFlow とチャンネル数の順序が逆. - 第3引数
output_shape
を指定しないといけない.かつ… - output_shape[0](バッチサイズ)を指定しないといけない
- output_shape[1],[2] の決め方がよくわからない
たかたかは特に output_shape 周りの問題を解決するのにえらい時間食ってまいました.興味のある方はこの辺をどうぞ.
- conv2d_transpose cannot be used in network with variable batch size · Issue #833 · tensorflow/tensorflow · GitHub
- Default for tf.nn.conv2d_transpose output_shape · Issue #2118 · tensorflow/tensorflow · GitHub
- conv2d_transpose output shape more undefined than input shape · Issue #8972 · tensorflow/tensorflow · GitHub
-
tensorflow/convolutional.py at r1.3 · tensorflow/tensorflow · GitHub で deconv_output_length を検索 & tensorflow/utils.py at r1.3 · tensorflow/tensorflow · GitHub
output_shape の幅と高さについては結局上記を見ても解決しなくて,値を決め打ちするださださなプログラムでごまかしてしまいました.
Batch Normalization 関係
まんぼう日記には書いてませんが,昨日,TensorFlow で MLP と CNN (2) - まんぼう日記 のプログラムを Batch Normalization (以下BN) 使うように改造してみたので,今回も BN 使ってみました.そのときのプログラムはこちら: https://gist.github.com/takatakamanbou/ffba1efa4900971b5be3a1986a1149ed.BN は昔 Theano で自分で書いたことがある(Batch Normalization を実装する - まんぼう日記)けど,いまどき TensorFlow では簡単に組み込めます.今回は tf.nn.batch_normalization | TensorFlow 使ってます.
ただ,BN 使ってはみたものの,今回のネットワーク構成では特に恩恵は感じられませんでした.バイアス項使って BN しないプログラムも動かしてみたけど,普通に学習進むし速さもほとんど変わらへんかったし.
んでこれは余談ですが,BN を ReLU の前に入れるか後に入れるかは議論の余地があるようですね.元の論文では前に入れるべしと言うてるんやけど,後の方がいい結果が出ると言ってるひともいたりして.
- https://github.com/ducha-aiki/caffenet-benchmark/blob/master/batchnorm.md
- [D] Batch Normalization before or after ReLU? : MachineLearning
理論的にどちらがよいと言う話はまだなさそうなので,後がいいっちう結果もたまたまその実験条件ではそうなったって話にしか見えへんけど.
そんなことより,BN して ReLU やとどのユニットもだいたい半分は 0 を出力することになると思うんやけど,適当にオフセットさせて 0 の割合を変えたらどうなるかって,誰か調べてみーへんかな.特徴表現のスパースネス(もどき)をコントロールすることになるような….
Convolution だけにしたらどうなる?
上記の実験では前半に convolution + pooling の層,後半に transposed convolution の層を並べた素直な encoder-decoder 型の構成にしましたが,よく考えたら別にこの構成にしばられる理由ないですよね.ちうわけで,全部 conv 層にしたらどうなるかも試してみました.C32-C64-C128-C128-C128-C1 と 6 つの conv層を連ねる形です.カーネルは全部 4x4.padding = 'SAME'
なので,出力マップは最初から最後まで 28 x 28 のまま.結果は,sqeL = 18.87, sqeT = 21.16 となりました.とりあえず encoder-decoder 型の方がよさげ.