KiyuHub

メシと寝所と呼吸と

このエントリーをはてなブックマークに追加

Hello Autoencoder

最近,身内でDeep Learningを題材に含んだ勉強会を行なっている.

メインは専門である自然言語処理まわりだが, とりあえず実装(というよりnumpy)の導入になる上,結果を視覚化できることから, 画像データを利用したAutoencoderの実装について取り扱った.

軽い説明と共にコードと,色々な結果を

Autoencoder

Autoencoderとは,Neural Networkの特殊系で,基本的には

  • 入力層と出力層のユニット数が同じである.
  • 教師信号として入力そのものを与える.

という特徴を持つ.

../../../_images/autoencoder.png

入力と出力が共に4次元で,隠れ層が2次元なAutoencoderの図

Autoencoderは,入力の情報をを一度隠れ層の空間に写像(encode) したあと, 元の信号を復元(decode)するようなパラメータを学習する.

図のように,もしも隠れ層のユニットが入力層のものよりも少ない場合は, decodeの際,より少ない情報から元の信号を復元する必要がある. そのため,そのようなことが可能なパラメータが学習できれば, Autoencoderは非線形な次元圧縮器とみなすことができる.

具体的な計算式は以下で,パラメータとは \(W_1, W_2, b_1, b_2\).

\[\begin{split}hidden &= encode(input) &= f( W_1 input + b_1) \\ output &= decode(hidden) &= f( W_2 hidden + b_2)\end{split}\]

圧縮された表現(この場合4次元の入力が2次元に圧縮されている)は,元の情報から, 大切な情報だけをうまく抜き出したなんか良い感じのもの

Denoising Autoencoder

Autoencoderの派生系の一つにDenoising Autoencoderがある. 入力にノイズを付与し,そのノイズを取り除くようなencoderを学習しようというもの. 出力層で再構築する対象は,ノイズ付与前の入力なので,Denoising Auroencoderは,

  • 入力の情報を保持する良いencoderの学習

に加えて

  • 入力に加えられたノイズを除去する

ことも学習しなければならない.

以下の画像のように,N%の画素が欠落ことがノイズに相当する.(教師は常に左のオリジナル)

../../../_images/noising.png

Autoencoderを複数積み上げるStacked Autoencoderの構成要素にこれを採用することで, かなり性能が上がる .

実装

コードは こちらのGist に. 実行にはnumpy, PILが必要.

最初に,autoencoder.py冒頭のコメントにあるように,MNISTのデータセットをDLする.

これは,28*28の手書き数字画像(0~9)が大量に入ったデータベース. そのためautoencoderの入力,出力次元は784.

可視化

隠れ層の各ユニットにつながる重み(入力画像と同じ次元になる)を可視化 (参考は こちら ).

なので,隠れ層が100だったら,28*28の画像が100枚並んだものが出てくる. 白いと重みの値が大きく,黒いと小さい.

結果

いくつか条件を変えて学習されるパラメータ画像を見る.

感想は,画像を見て個人的に感じたことであって,ちゃんとした考察ではない. (可視化についてちゃんと調べていずれちゃんと書きたい)

Autoencoder

../../../_images/b20.bmp

隠れ層が100ユニットで,ノイズ付与なしのAutoencoder

python autoencoder.py 100

Denoising

ノイズの付与率によるパラメータの違い.

結果は以下

  • noise 20%
python autoencoder.py 100 -n 0.2
../../../_images/b20_n20.bmp
  • noise 50%
python autoencoder.py 100 -n 0.5
../../../_images/b20_n50.bmp
  • noise 80%
python autoencoder.py 100 -n 0.8
../../../_images/b20_n80.bmp

ノイズを載せたほうが,載せない( Autoencoder のとこの画像)よりもそれっぽい学習ができている隠れユニットが多い.

80%もノイズをのせると,情報がなさすぎるためか, 答えを丸暗記しているためそのまま数字が浮かび上がってしまっている?過学習? つまり,データに潜む本質的な情報を捉えることを放棄している? (要出展)

number of hidden units

隠れ層のサイズを784にしてみた時の様子. 入力層,出力層,隠れ層が同じなので,あまりうまく学習できないという噂. ※わりと時間かかります(一時間半から二時間くらい?)

visualize_weights()の最後二行のコメントアウトを外し,直前の二行をコメントアウトする必要あり. デフォルトだと,784枚中最初の100枚分しか出ません

python autoencoder.py 784
../../../_images/h784.bmp

たしかに,さぼっている(という表現で良いのか?)隠れユニットが多い.

ノイズを付与していくと...

  • noise 20%
python autoencoder.py 784 -n 0.2
../../../_images/h784_n20.bmp
  • noise 50%
python autoencoder.py 784 -n 0.5
../../../_images/h784_n50.bmp

全体的に学習しているっぽくなってる. Denoisingの80%と似たような感じになっている隠れユニットも存在する (そもそも悪いことなのかは分からないが)

てっとり早いのは,encodeされたcodeを入力とするsoftmax層を載せて, 実際に0~9の分類を行わせてスコアを見るのがよさそう(なのでそのうちやってみよう)

Tied vs. Untied weight

decoderとencoderが転置の関係にあるのがTied weight ( \(W_2 = W_1^T\) ).

逆にencoderとdecoderを別々に学習するのがUntied.

どっちが良いかはよくわからない.

とりあえず画像だけ.プログラムではuオプションをつけるとuntiedになる.

  • Untied な場合のencoder
../../../_images/W1_n50.bmp
  • Untied な場合のdecoder
../../../_images/W2_n50.bmp
  • Tied weightな場合のencoder (転置するとdecoder)
../../../_images/b20_n50.bmp

はじめの方はなんとなくuntiedなのの方が良いのかな?と思ってたけど, よく考えたらAutoencoderをStacked autoencoderに組み込む際は,decoderは使用しない. なので,decoderとencoderを別に学習するUntied weightなモデルは無駄が出てしまうかもしれない? (decoderの方が特徴っぽいのが大きく出ているし)

validation.pyについて

最後に,gistについてるvalidation.pyについて. back propagationにおける勾配計算の**コードが正しいか否か**を判別するための方法.j

back propagationはデバッグがしにくいが,これを使うと割と楽.

\[\frac{d}{d \theta} J(\theta) = \lim_{\varepsilon \to 0} \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}\]

を勾配の近似とし,計算した勾配の値と比べる. 二つの差分が十分小さくなれば,勾配の計算部分にバグはないという確認ができる.

参考は Gradient checking and advanced optimization など

この項目は最後の最後に書いてないの見つけて急いで書いたので,いずれ詳しくメモを書きたい.

このエントリーをはてなブックマークに追加