Skip to content

toona note

Transposed Convolution の直観的理解

はじめに

PyTorch の ConvTranspose についての挙動を確認します。
簡単のために 1 次元データについて示します。
ちなみに、1 次元データとは音声信号などです。

Transposed Convolution とは

Transposed Convolution は Convolution の逆の操作のことを指します。
PyTorch のソースによると、ほかにも、fractionally-strided convolution や、deconvolution と呼ばれるとのこのとです。
ただし、deconvolution は厳密には別の処理を示す単語なので注意が必要。

Transposed Convolution の挙動確認

PyTorch の ConvTranspose1d のカーネルを[1, 1, 3]に設定して、引数や入力を変えた時の出力を確かめます。
変換のカーネルを[1, 1, 3]とした理由ですが、[1, 2, 3]とすると出力された[3]が 3= 1 + 2 の 3 なのか 3=1 * 3 の 3 なのかが判然としないからです。

以降のプログラムでは先に必要なモジュールが import されていることとします。

まずは一番簡単な例として [1]を入力したときの Transposed Convolution の出力を確認。

[1, 1, 3]が出力されました。 これは感覚通りです。
イメージは下の図です。

ConvTranspose_001

以降、stride を考慮せずにカーネルから出力されたそのままの数値をカーネル出力とします。
私が勝手にカーネル出力と呼んでいるだけですのでご注意ください。

Stride の確認

次は stride 引数について確認します。

入力は [1, 1] とします。
最初に stride=1 のとき。

[1, 2, 4, 3] が出力されました。
イメージは下のようになります。

ConvTranspose_002

次に stride=4 のとき。

出力は[1, 1, 3, 0, 1, 1, 3]となりました。

イメージは下のようになります。

ConvTranspose_004

stride=4 では、各カーネルの出力の始まる位置が 4 つずれることに相当します。
図では、ストライドを灰色の矢印で、出力の下に示しました。
カーネルのサイズが 3 かつ、stride=4 では、重なり合わない部分ができて、0 で埋められます。

この挙動は、入力が 0 で埋められていると解釈することもできます。
次のように、入力を[1, 0, 0, 0, 1] stride=1 とすると、

予想通りに、入力[1, 1]、stride=4 と同じ出力が得られました。
このときのイメージはつぎのようになります。

ConvTranspose_005

図では、0 埋めした部分の出力を薄い色にしました。

Padding の確認

次に padding を確認します。
入力[1, 1] stride=4, padding=1 とします。

出力は[1, 3, 0, 1, 1, ] です。
つまり、両端が削られた出力となっています。
イメージは次のようになります。

ConvTranspose_006

convolution のときに padding=1 とすると、両端が 0 で埋められる。
Transposed Convolution は convolution の逆の動きをするように、引数もそろえてあります。

上の図の挙動は、padding した convolution の出力を padding した Transposed Convolution にかけることをイメージするとわかりやすいです。
Transposed Convolution の出力の両端は、本来存在しなかった信号であり、無意味なので削るイメージです。

Output_padding の確認

最後に output_padding を確認。

先ほどのプログラムに、output_padding=1 を加ます。

出力は [1, 3, 0, 1, 1, 3] でした。
イメージは次のようになります。

ConvTranspose_007

padding 引数により削除した信号の一部が復活する。
PyTorch のソースには、output_padding は 0 埋めとは違うから注意するようにと書かれていました。

では、padding で消し去った信号以上の数値を output_padding した時はどうなるのでしょうか?

出力は、[1, 3, 0, 1, 1, 3, 0, 0] です。
復活する信号は片側のみで、消し去った信号以上の信号を得るときは 0 で埋められています。

この output_padding は何に使うのでしょうか?
convolution は出力のサイズ計算に床関数が入っています。
つまり、stride=1 以外の時は、Convolution と同一の引数を用いた Transposed Convolution では完全には同一のサイズを復元できないことがあります。
この時に、output_padding を用いると、サイズを調整することができます。

おわりに

これで、https://github.com/slundberg/shap の Gif を見てもしっくりこなかったものが、すんなりと入ってくるようになりました。

参考