読者です 読者をやめる 読者になる 読者になる

まんぼう日記

takataka's diary

Denoising Autoencoder の実験をしてみる

これまでの話( Theano で GPU 使って Convolutional Neural Net - まんぼう日記 )から少しそれますが,Denoising Autoencoder の実験をしてみました.例によって余談付き….

 

 

瀬田川洗堰は全開放流中です

台風11号が琵琶湖周辺にたくさん雨を降らせたせいで(たぶん),瀬田川洗堰は全開放流を始めました.今日は仕事があったので,昼過ぎにX登校プチして様子を見に行ってきました.

 

f:id:takatakamanbou:20150719163936j:plain f:id:takatakamanbou:20150719163938j:plain

上流側から.左の写真の左の方,上部が煉瓦色になってる部分は流量調節用バイパスゲートですが,なんか緑色のんが見えるので,閉じてるみたいですね.近くに寄ってみると(右),ゲートの爪にひっかかった藻のもじゃっぷりがすごい気配.

 

f:id:takatakamanbou:20150719163940j:plain f:id:takatakamanbou:20150719163941j:plain

反対側にまわってみると,ご覧の通り見事なもじゃもじゃさんでした.前回( 全開放流をとるか授業をとるか - まんぼう日記 )とは比べもんになりませんな.

 

f:id:takatakamanbou:20150719163939j:plain f:id:takatakamanbou:20150719163943j:plain f:id:takatakamanbou:20150719163944j:plain

下流側の増水っぷりを表す写真.右はいつもの場所です.X登校プチ15km 波穂神社 源内道 - まんぼう日記 に水位が低い時の写真あります.

 

Denoising Autoencoder の実験をしてみる

Denoising Autoencoder とは

まずは Autoencoder から

出力層に入力次元数と同じ数の素子をもつ階層型ニューラルネットで,入力データ自身を出力の教師とする学習を行うものを autoencoder といいます.例えば「入力 - 隠れ層 - 出力層」という2層から成る場合,隠れ層の素子数を入力データの次元数より小さくしておくと,データを次元圧縮→再構成して元のデータを近似することになります.より多層の場合もだいたい同じことがいえます.そのため autoencoder は,データの本質的な特徴を抽出・分析するために用いられたりします.最近では,deepな,つまりたくさんの層から成る階層型ニューラルネットの事前学習にも使われたりします.deepなネットワークを丸ごと教師あり学習させるのは難しいので,層ごとに教師なし学習させたものを積み上げて,最後に教師あり学習で全体を微調整する方法をとることがあるんですが,その層ごとの学習を autoencoder でやる,と.

 

で,Denoising Autoencoder

denoising autoencoder は,2008年に Vincent らが提案したものです.

 

P. Vincent, H. Larochelle, Y. Bengio, P.-A. Manzagol, ``Extracting and Composing Robust Features with Denoising Autoencoders,'' in Proceedings of the 25-th International Conference on Machine Learning, Helsinki, Finland, 2008

 

autoencoder では,入力自身を出力教師として入力と出力が等しくなることを目指しますが,denoising autoencoder では,データにノイズを付加したものを入力して,ノイズを付加されていない元のデータを出力教師とすることで,データからノイズを除去する ( de-noising ) ことを目指します.

 

詳しくは原論文を参照してもらえばよい(し,たかたかも斜め読みしかしてない)のですが,このような学習を行うことで,deep なネットワークの事前学習に用いた場合の性能向上を図れるようです.一方,たかたか的には,このような方法をとることで,従来の autoencoder の欠点を解消/緩和できるのかが気になります.

 

その欠点というのは,「autoencoder では,無意味な恒等写像の学習になってしまわへんように,隠れ層の素子数をデータの次元数より小さくしなければならない」というものです.例えば,データが3次元で隠れ層の素子数も3あれば,入力→隠れ層→出力層の変換が \( 3 \times 3 \) 単位行列になってしまうことがあります.そうなってはわざわざ学習した意味がないので,隠れ層素子数を2以下にしないといけません.でも,そうなると,事前学習に使う場合,上の層ほど素子数の少ない構造にしか適用できなくて,使いにくいよなあ,と.ニューロン出力をスパースにする制約を入れるとか,そういう方向で解決する手もありますが….

 

で,denoising autoencoder にすればその点がなんとかなるかもしれへんということなのです.

 

3次元の人工データで実験

というわけで,実験.

実験条件

f:id:takatakamanbou:20150719163935p:plain f:id:takatakamanbou:20150719163934p:plain

3次元のデータなんやけど平面上に載ってるようなんを乱数で作り(左),それに等方な正規乱数のノイズを加えたものも用意しました(右).以下,ノイズを加える前のデータを \( X_{\rm org} \), ノイズを加えたデータを \( X_{\rm noisy} \) と表記することにします.  \( X_{\rm org} \) はあらかじめ平均が \( \mathbf{0} \) になるようにしてあります.

 

ここで注意.上述の Vincent らの論文では,Stochastic Gradient Descent を使うことを想定し,また,ノイズはちゃんと確率的に乗る(同じ学習データでもepochごとに異なるノイズが加わる)という前提で議論してます.でも,この記事の実験では,SGDではなく全学習データに対する勾配を用いて一括修正する方法を採用し,ノイズは一度作ってデータに加えたら,その後ずっと同じ値を使うようにしています.したがって,原論文の条件をちゃんと再現してるわけではありません.

 

学習するネットワークは,\( D \) 次元入力に対して隠れ層素子数 \( H \),出力層素子数 \( D \) の2層で,すべての素子の活性化関数は線形(恒等写像)としました.コスト関数は最小二乗誤差,学習則は慣性項付き最急降下法(一括修正)です.

 

学習データは,次の3通りに設定して比較してみます:

  1. 入力出力とも \( X_{\rm org} \) 
  2. 入力出力とも \( X_{\rm noisy} \)
  3. 入力は \( X_{\rm noisy} \),出力は \( X_{\rm org} \)  

1. と 2. は従来の autoencoder,3. が denoising autoencoder (もどき)です. 

 

Theano + Numpy で作ったプログラム

 

実験結果1: \( H = 3 \), 学習500回

まずは \( H = 3 \) のネットワークで学習を500回行った時点での様子.下図左は,学習後のネットワークに \( X_{\rm noisy} \) を入力して得られる出力.どれもある程度ノイズを除去して \( X_{\rm org} \) に近い値を出力できているように見えます.右は,ネットワーク内部にどのような表現が獲得されているかを調べたもの.入力の3次元空間中の格子点をデータとして(これを \( X_{\rm grid} \) と表記することにします )入力してみました.学習500回では,どの出力も平面に潰れています.3つの条件で学習したいずれのネットワークも,オリジナルの学習データが住んでいる2次元部分空間(平面)への射影を出力するような内部表現を作っているようです.つまり,隠れ層に \( H = 3 \) という冗長な数の素子を与えられても,データの本質的な次元数に合わせた内部表現をうまく獲得できているようです.

 

条件\(X_{\rm noisy}\)に対する出力\(X_{\rm grid}\)(赤)とそれに対する出力(青)
1. f:id:takatakamanbou:20150719163924p:plain f:id:takatakamanbou:20150719163922p:plain
2. f:id:takatakamanbou:20150719163930p:plain f:id:takatakamanbou:20150719163923p:plain
3. f:id:takatakamanbou:20150719163932p:plain f:id:takatakamanbou:20150719181637p:plain

 

実験結果2: \( H = 3 \), 学習5000回

さらに学習を重ねると,変化が生じます.5000回学習すると,条件 2. の平均二乗誤差は他の条件の場合よりずっと小さく,ほぼ 0 になります.出力を描画するとご覧の通り.条件 2. ではノイズ除去の効果がなくなっており(左),ネットワークの入出力が3次元入力に対する恒等写像になってしまっています(右).何の特徴抽出もできてへんわけで,これではわざわざ autoencoder に学習させた意味がありません.

 

条件\(X_{\rm noisy}\)に対する出力\(X_{\rm grid}\)(赤)とそれに対する出力(青)
1. f:id:takatakamanbou:20150719183447p:plain f:id:takatakamanbou:20150719183505p:plain
2. f:id:takatakamanbou:20150719183637p:plain f:id:takatakamanbou:20150719183648p:plain
3. f:id:takatakamanbou:20150719183816p:plain f:id:takatakamanbou:20150719183829p:plain

 

図は示しませんが,重みの初期値を変えると,条件 1. でも恒等写像に近い表現になってしまう場合が見られました.一方,条件 3. では,試した範囲では常に上記と同様の結果でした.

 

実験結果3: \( H = 2 \), 学習5000回

 上記は隠れ層素子数 \( H = 3 \) でしたが,\( H = 2 \) にするとどうなるかもやってみました(結果はわかりきってますが).学習回数は 5000 です.条件 1. と 3. は実験結果2 と変わりなかったので,条件 2. の結果のみ示します.

 

条件\(X_{\rm noisy}\)に対する出力\(X_{\rm grid}\)(赤)とそれに対する出力(青)
2. f:id:takatakamanbou:20150719204851p:plain f:id:takatakamanbou:20150719204902p:plain

 

隠れ層で2次元の表現しかできませんから,当然そういう内部表現になります.

 

考察

上記の結果を考察する際には,「実際に入手できるデータは \( X_{\rm org } \) なのか \( X_{\rm noisy } \) なのか」をよく考えねばなりません.上記のような denoising autoencoder の実験条件を許すということは,\( X_{\rm org } \) が観測できる場合を考えている,ということです.そう考えると,条件 1. は観測したデータでそのまま autoencoder の学習をする場合,条件 2. は観測したデータにノイズを付加して autoencoder の学習をする場合,そして条件 3. は,観測したデータにノイズを付加したものを入力,生のデータを出力の教師として学習する場合,ということになります.

 

結局,データの本質的な次元数に合わせて隠れ層の素子数を予め決定しておける,とかいう有り得へん状況を無視すると,条件 2. のやり方はやめた方がよい,と言えそうです.条件 1. 対 3. で考えると,重みの初期値に対する依存性とか十分調べきれてませんが,条件 3. の方に分がありそうです.

 

まあそんなわけで,denoising autoencoder は従来の autoencoder よりも良いと言えそうですね.

 

おまけというか宣伝というか

autoencoder の学習では,隠れ層の素子数をデータの本質的な次元数に合わせて適切に決めておかねばならない,という問題があります.上記の実験で扱ったのは線形素子から成る2層のネットワークでしたが,シグモイドのような非線形素子を含みかつより多くの層から成るネットワークでも同様です.大学院生の頃のたかたかは,これをどうにかしたいと考えました.で,固有値の大きさ順に寄与の大きさが決まる主成分分析のように,隠れ層素子が寄与の大きいものから順に特徴を抽出できる autoencoder 型の学習アルゴリズムというかコスト関数を考案しました.これを用いると,冗長な数の隠れ層素子を持ったネットワークに学習させておいて,何番目の隠れ層素子まで使うか,すなわち内部表現の次元数をいくつにするかを,学習後に決めることができます.もう20年近く前の研究ですが... (^^;

 古すぎて通信学会のサイトに置いてあるPDFは紙を手作業でスキャンしたものっぽい….図とか潰れてようわからへんようになってるとこありますな.国際会議のんも含めてちゃんと自分でアーカイブした方がええかな.まあ時間ができたら...

 

さらに宣伝 (^^;  autoencoder と普通の識別の学習を組み合わせて,顔画像の一部が隠れてても denoising して正しく識別できるよ,とか,カーネル主成分分析で非線形 denoising,とか.こっちも10年以上前の研究です...