まんぼう日記

takataka's diary

Denoising Autoencoder の実験をしてみる (3)

昨日で定期試験の採点もおわり,夏休み気分のたかたかです.ちうわけで久しぶりの研究ねた.Denoising Autoencoder の実験をしてみる (2) - まんぼう日記 のつづきです.MNIST で denoising autoencoder の実験をやってみました.前回との違いは,

  • 学習が一括修正やったんを SGD にして,学習データ数も多くした
  • ノイズとして,画像の平行移動も導入した
  • 隠れ層の活性化関数として,線形(恒等写像)に加えて Rectified Linear (ReLu) も試した
  • 出力だけじゃなくて重みも可視化してみた

ってところです.

 

実験条件

データ

前回( Denoising Autoencoder の実験をしてみる (2) - まんぼう日記 )はMNIST の手書き数字画像のうち2000枚で学習,2000枚でテスト,っていう小規模なものでしたが,今回は学習用6万枚のうち5万枚を学習データとし,テスト用1万枚をテストデータとしました.学習用の残り1万枚は検査用にとっときましたが,今回は実質使ってません.MNIST の画像は 28 x 28 画素なので,データの次元数は D = 768 です.

 

このデータにノイズを加えたものを作ります.以下,例によってノイズを加えていない元の学習データを \( X_{\rm org} \),これにノイズを加えたものを \( X_{\rm noisy } \) と表記します.ノイズの入れ方は,次の3通り:

  1.  画素値を確率 0.1 で最大値または最小値にする(いわゆる「ごま塩」ノイズ,前回のノイズとは微妙に違う)
  2. 画像を水平垂直にそれぞれ -2 から +2 画素の範囲でランダムに平行移動させる(以下「シフト」と呼びます)
  3. シフト + ごま塩

 

f:id:takatakamanbou:20150809005905p:plain f:id:takatakamanbou:20150809005929p:plain

左はテストデータオリジナルの最初の50個,右はそれにノイズを加えたもの(シフト + ごま塩).

 

ネットワークの構造と学習法

ネットワークは素子数 D - H - D の3層で,H は 100 と 1000 の二通り.活性化関数は,隠れ層については線形または ReLu(ReLuの場合はしきい値あり),出力層は線形.コスト関数は平均二乗誤差.前回と違い,SGD で学習します.学習に関する細かいパラメータについては,プログラムを参照してください.

 

学習データの与え方は,例によって次の3通り:

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

1. と 2. は従来の autoencoder,3. が denoising autoencoder です.前回と違い,ノイズは学習の繰り返し毎に新たに生成しなおして,同じ学習データでもepoch毎に異なるノイズがのるようにしてます.

 

プログラム

Python + Theano + NumPy + OpenCV で作成.

 

実験1: 隠れ層ニューロン数 H = 100,線形

この実験では,ノイズは全て「シフト+ごま塩」.結果はこんなんなりました.

入力出力教師誤差(L)誤差(T)ノイズありテストデータに対する出力
\(X_{\rm org}\) \(X_{\rm org}\) 4.5 58 f:id:takatakamanbou:20150809013349p:plain
\(X_{\rm noisy}\) \(X_{\rm noisy}\) 36 60 f:id:takatakamanbou:20150809013412p:plain
\(X_{\rm noisy}\) \(X_{\rm org}\) 34 34 f:id:takatakamanbou:20150809013445p:plain

 

この表の誤差(L)と誤差(T)は意味が違うので要注意.誤差(L)は,学習データに対するコスト関数の値,つまり,ネットワークの出力と教師との平均二乗誤差です.一方,誤差(T)の方は,ノイズありテストデータを入力したときのネットワーク出力とノイズなしのオリジナルとの平均二乗誤差です.

 

隠れ層ニューロン数 H がデータの次元数 D より小さいので,どの条件でも denoising はそれなりにできてます.テストデータに対する出力画像を見ると denoising autoencoder の場合はいまいちですが,誤差的にはこれが一番よい値.

 

f:id:takatakamanbou:20150809015250p:plain f:id:takatakamanbou:20150809015311p:plain f:id:takatakamanbou:20150809015328p:plain

こちらは重みの値を可視化したもの.上と同じ順番.入力から隠れ層への重みを描く方が普通かもしれませんが,ここでは,隠れ層から出力層への重みを,H = 100 個の隠れ層ニューロン毎に描いてます.白が正,黒が負,灰色が 0.どれも見て面白いもんではないですね.

 

実験2: 隠れ層ニューロン数 H = 1000,線形

 

実験1とは H が違うだけ.したがって,ノイズは全て「シフト+ごま塩」.

入力出力教師誤差(L)誤差(T)ノイズありテストデータに対する出力
\(X_{\rm org}\) \(X_{\rm org}\) 0.012 83 f:id:takatakamanbou:20150809021344p:plain
\(X_{\rm noisy}\) \(X_{\rm noisy}\) \(3.6\times10^{-11}\) 95 f:id:takatakamanbou:20150809021400p:plain
\(X_{\rm noisy}\) \(X_{\rm org}\) 34 34 f:id:takatakamanbou:20150809021423p:plain

  

f:id:takatakamanbou:20150809021442p:plain f:id:takatakamanbou:20150809021506p:plain f:id:takatakamanbou:20150809021529p:plain

 

前回( Denoising Autoencoder の実験をしてみる (2) - まんぼう日記 )と同様の結果です.隠れ層ニューロン数 H がデータの次元数 D より大きいので,最後の denoising  autoencoder 以外は恒等写像を学習しちゃって,ほとんど denoising できてません.denoising autoencoder の方は,H を大きくしても変わりなし.

 

あ,重みの可視化の方は,1000個のうち100個の値のみを示してます.

 

実験3: 隠れ層ニューロン数 H = 1000,ReLu

 

隠れ層ニューロンの活性化関数を Rectified Linear にしてみました.denoising でない autoencoder の場合,実験2と同じで恒等写像にしかならなかったので,結果は省略します.denoising autoencoder の場合について,ノイズののせ方を変えたらどうなるかを見てみました.

 

ノイズノイズありテストデータに対する出力隠れ層-出力層の重み
ごま塩 f:id:takatakamanbou:20150809023529p:plain f:id:takatakamanbou:20150809023536p:plain
シフト f:id:takatakamanbou:20150809023803p:plain f:id:takatakamanbou:20150809023809p:plain
両方 f:id:takatakamanbou:20150809024001p:plain f:id:takatakamanbou:20150809024008p:plain

誤差(T)の値は,順に 4.6, 10.8, 16 となりました. 

 

活性化関数を ReLu にしたら,獲得される内部表現ががらっと変わりました.しかも,ノイズののせ方によっても全く違います.面白い.特にごま塩ノイズの場合,まるでスパースコーディングしたみたいな重みになってますね.ReLu ではニューロンへの入力の総和が一定以下なら出力が 0 になってしまうので,自然にスパースな表現が獲得されるのでしょう.

 

しかし,これだけノイズののせ方に依存して結果が変わるとなると,deep なネットワークの事前学習なんかに使う場合,どんなノイズを使うかの選択に気ぃ使わなあきませんね.