Theano で Multi Layer Perceptron & Convolutional Neural Net - まんぼう日記 と
Theano で MLP & CNN (2) - まんぼう日記 の Convolutional Neural Net の実験のつづきで,MNIST のかわりに CIFAR-10 を使ってみることにしました.ちうことで,CIFAR-10 について.あと,CIFAR-10 では ZCA whitening という前処理をした方がよいかもという話があったので,ついでにそっちの話も.
CIFAR-10
CIFAR-10 はこちらで入手できます: CIFAR-10 and CIFAR-100 datasets
32x32画素の小さい画像を10種類のクラスに分類する識別問題用データセットです.クラスあたり6000枚で,学習用が5万枚,テスト用が1万枚あります.
というわけで,データ読み込み用の Pyhon プログラムを作ってみました: cifar10.py
それを使って,学習データの各クラス最初の10枚を可視化してみるとこんなん.
2015-02-20 追記: 最初に記事を書いた時点のプログラムでは,上記プログラムの可視化の処理で画素値の扱いを間違ってました(RGBとBGRの間違い).プログラムを修正して画像もさしかえました.どうりでなんか青っぽかったわけや (^^;
ZCA whitening
CIFAR-10 を提供してる,Hinton さんとこの Alex Krizhevsky さんは,大規模画像認識コンペ ImageNet Large Scale Visual Recognition Competition (ILSVRC) で Convolutional Neural Net で高い性能出したりしてるひとです.
ImageNet の論文( http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf )ではRGBの画素値を平均引くだけでそのまま使ってるみたいですが,より以前の,CIFAR-10 に RBM (Restricted Boltzmann Machine) 適用した研究とかでは ZCA whitening による前処理をやってます.そういうわけで ZCA whitening について調べたので以下にまとめます.
参考にしたのは
- Krizhevsky さんの修論 http://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf
です.
以下,
C = XX^{\top}
です( N か N - 1 で割れよというつっこみは置いといてーな.どうせ定数倍やから以下の議論に関係ないし).
PCA — 共分散行列の対角化
PCA(Principal Component Analysis(Principle じゃないよ.Princess でもないよ (^^) ), 主成分分析)では, X を D \times D 行列 W によって Y = WX と変換したときに,変換後のデータ Y の共分散行列が対角行列になるような W を求めます.なんでそんなことしたいかは,統計とかデータ解析とかの勉強したらわかります.ここでは省略.
共分散行列 C は正定値対称行列なので(説明が面倒なので,「半」正定値じゃなくて正定値にして説明します),
C = U \Lambda U^{\top}
と分解できます. \Lambda = {\rm diag}( \lambda_1, \lambda_2, \dots , \lambda_D ) は固有値をならべた対角行列, U は固有ベクトルをならべた直交行列.
このとき, Y_{\rm PCA} = U^{\top} X とすると, Y_{\rm PCA} の共分散行列 C_{\rm PCA} は
\begin{align} C_{\rm PCA} &= Y_{\rm PCA}Y_{\rm PCA}^{\top} = U^{\top} XX^{\top} U = U^{\top}CU \\ &= U^{\top}U\Lambda U^{\top}U = \Lambda \end{align}
となって対角行列になります.したがって,PCAでは W_{\rm PCA} = U^{\top} を変換行列とすればよいわけです.実際には固有値の大きさ使って一部の成分を捨てて次元圧縮したりするわけですが…省略.
Whitening ー 共分散行列の単位行列化
上記の議論から, Y_{\rm wh} = \Lambda^{-\frac{1}{2}}Y_{\rm PCA} とおくと,共分散行列を対角なだけじゃなくて単位行列にできることがわかります. \Lambda^{-\frac{1}{2}} = {\rm diag}\left( 1/\sqrt{\lambda_1}, \dots ,1/\sqrt{\lambda_D} \right) ね.
C_{\rm wh} = \Lambda^{-\frac{1}{2}} Y_{\rm PCA}Y_{\rm PCA}^{\top} \Lambda^{-\frac{1}{2}} = \Lambda^{-\frac{1}{2}} C_{\rm PCA} \Lambda^{-\frac{1}{2}} = I
というわけで,元のデータ X に対して W_{\rm wh} = \Lambda^{-\frac{1}{2}} U^{\top} という変換を施すと,単位行列を共分散行列とするデータが得られます.データをこのように加工することを,whitening(白色化)と言います.なんでそんなことしたいかは…省略.
ZCA whitening ー 白色化したデータを元の空間で眺める
さて実は,共分散行列を対角化/単位行列化する変換は,上記の W_{\rm PCA} および W_{\rm wh} の形に限られるわけではありません.簡単のため白色化の方の話に限りますが,任意の直交行列 A を使って \hat{Y} _{\rm wh} = A Y_{\rm wh} とすると,\hat{Y}_{\rm wh} の共分散行列もやはり単位行列になりますので.
そういうわけで,ZCA whitening では, A として U を用い, W_{ZCA} = U\Lambda^{-\frac{1}{2}} U^{\top} という変換を用いて白色化を行ないます.つまり
Y_{\rm ZCA} = W_{ZCA} X = U\Lambda^{-\frac{1}{2}} U^{\top} X
ということ.
なんでこんなことしたいかというと…省略…はしません.ひとことでいうと,普通の白色化やと U^{\top} で変換して固有空間でデータを眺めることになるけど,ZCA whitening ではそれを U で元の特徴空間に戻して眺められるから,ということでしょうか.たとえばデータベクトルの要素番号が画素位置に対応してる画像データの場合を考えてみます.この場合,普通の白色化では,白色化後のベクトルの要素と元の画素位置との間に対応はつきません.全ての画素値がまざっちゃってますから.しかし,ZCA whitening の場合,白色化後のベクトルの要素は元のベクトルの要素と対応が付くので,元の画素値と同じようにならべて画像として眺められます.
え,ありがたみがわからない? まあそうですね,一般のデータ前処理として考えたら,別に直交変換 U をかませても本質的に何もかわらへんわけですから.ただ,後の処理で元の特徴空間での要素のならびを気にした処理をしたいこともあるわけで.Convolution Neural Net みたいに近傍を定義したいとかね.
おまけ — 正則化
普通の白色化,ZCA whitening 共通の話ですが, \Lambda^{-\frac{1}{2}} による変換って,いやんな感じですね.共分散行列のランクが落ちてて一部の固有値が 0 になってたらとか,大きい方の固有値に比べて小さい方の固有値がずっと小さかった場合,そっち方向の要素をものすごい拡大することになるから,とか.
というわけで,よくやるのは, \Lambda の正則化,すなわち,各固有値に微小な正の定数 \varepsilon を加えて, \Lambda^{-\frac{1}{2}} のかわりに ( \Lambda + \varepsilon I )^{-\frac{1}{2}} を用いる,という方法です.
実験
実際に CIFAR-10 の画像を ZCA whitening してみます.プログラムはこちら:zca0215.py
まず,共分散行列の固有値はこんな値でした.最大固有値は55.4.
で,ZCA whitening した画像はこんなん.ここでは,画像毎に絶対値の最大で規格化して可視化してます.小さい固有値をもつ成分が強調されるので,エッジ等空間周波数が高い所が強調された画像になります.
以下は,正則化した場合.左から順に, \varepsilon = 1\times 10^{-5}, 0.001, 0.1 . \varepsilon を大きくすると ( \Lambda + \varepsilon I )^{-\frac{1}{2}} は単位行列の整数倍に近づいていく(大きい対角要素と小さい対角要素の比が1に近づく)から,結果は元画像に近づいていきます.
ついでに,元の画素値(平均を引いた後)と白色化後の値の分布を描いてみました.
左が元の画素値,真ん中が白色化後の値,右はその一部の範囲を描いたもの.
ZCA whitening で値がスパースになってることがわかります.