背景
通常の畳込み(convolution)は、入力された画像の解像度を下げるが、逆にこれを上げるものとして、transposed convolution(以前は deconvolution とも呼ばれていた)がある。TensorFlow だと tf.layers.conv2d_transpose 等でこれを行うが、動作の詳細がわからずもやもやしていた。
最もわかりやすい解説
【保存版】chainerのconvolutionとdeconvolution周りを理解する
これが一番わかりやすかった。具体例をあげて詳しく書いてあるので、もうこれだけ見てもらえれば十分。はい解散。
…というのもちょっと寂しいので、私は TensorFlow で検証してみた。わかりやすくするため、数値は思い切り単純なものにしてある。各自数字を変えて試してみるとよいかもしれない。もし間違いがあればご連絡ください。
検証コード
import tensorflow as tf
with tf.Session() as sess:
inputs = tf.ones([1, 3, 3, 1])
outputs = tf.layers.conv2d_transpose(inputs, 1, [2, 2],
strides=[1, 2], padding='valid',
kernel_initializer=tf.constant_initializer([[1, 0], [0, 0]]))
sess.run(tf.global_variables_initializer())
value = sess.run(outputs)
print(value)
実行結果
[[[[1.]
[0.]
[1.]
[0.]
[1.]
[0.]]
[[1.]
[0.]
[1.]
[0.]
[1.]
[0.]]
[[1.]
[0.]
[1.]
[0.]
[1.]
[0.]]
[[0.]
[0.]
[0.]
[0.]
[0.]
[0.]]]]
解説
確かに【保存版】chainerのconvolutionとdeconvolution周りを理解するの通りの動作になっている。
もともとの inputs が、
\begin{bmatrix}
1 & 1 & 1 \\
1 & 1 & 1 \\
1 & 1 & 1 \\
\end{bmatrix}
これに対して、
outputs = tf.layers.conv2d_transpose(inputs, 1, [2, 2],
strides=[1, 2], padding='valid',
kernel_initializer=tf.constant_initializer([[1, 0], [0, 0]]))
で指定される transposed convolution 操作を行う。
inputs の周辺には、まず幅1でゼロパディングが施され、その上 strides=[1, 2]
なので、幅方向に大きさ2のストライドを掛ける1。すると以下のように。
\begin{bmatrix}
0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 1 & 0 & 1 & 0 & 1 & 0 \\
0 & 1 & 0 & 1 & 0 & 1 & 0 \\
0 & 1 & 0 & 1 & 0 & 1 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 \\
\end{bmatrix}
\tag{1}
kernel_initializer=tf.constant_initializer([[1, 0], [0, 0]]))
で指定される行列は以下のもの。
\begin{bmatrix}
1 & 0 \\
0 & 0 \\
\end{bmatrix}
これについて、2つの対角線でそれぞれひっくり返した(transpose2)行列は以下の通り。
\begin{bmatrix}
0 & 0 \\
0 & 1 \\
\end{bmatrix}
\tag{2}
結局、行列(1)に対して、行列(2)で通常の convolution を掛ければよい。
答えは、
\begin{bmatrix}
0 & 1 & 0 & 1 & 0 & 1 \\
0 & 1 & 0 & 1 & 0 & 1 \\
0 & 1 & 0 & 1 & 0 & 1 \\
0 & 0 & 0 & 0 & 0 & 0 \\
\end{bmatrix}
となって上のプログラムの実行結果と一致する。