はじめるDeep learning

そうだ、Deep learningをやろう。そんなあなたへ送る解説記事です。
そう言いながらも私自身勉強しながら書いているので誤記や勘違いなどがあるかもしれません。もし見つけたらご連絡ください。

# Deep learningとは
こちらのスライドがとてもよくまとまっています。

[Deep learning](http://www.slideshare.net/kazoo04/deep-learning-15097274)

つまるところ、Deep learningの特徴は「特徴の抽出までやってくれる」という点に尽きると思います。
例えば相撲取りを判定するモデルを構築するとしたら、普通は「腰回りサイズ」「マゲの有無」「和装か否か」といった特徴を定義して、それを元にモデルを構築することになります。ちょうど関数の引数を決めるようなイメージです。

ところが、Deep learningではこの特徴抽出もモデルにやらせてしまいます。というか、そのために多層、つまりDeepになっています。
具体的には頭のあたりの特徴、腰のあたりの特徴、そしてそれらを複合した上半身の特徴・・・というように、特徴の抽出を並列・多層に行って学習させて、それでもって判定させようというのが根本的なアイデアです(以下、イメージ図)。

![deeplerning.PNG](https://qiita-image-store.s3.amazonaws.com/0/25990/cb1e2e8b-6a05-1141-c394-6455c2786da4.png)

図中にあるとおり、Deep learningはそれを構成する技術要素を以下のように分けることができます。

* データの分割  
判定に使用するデータの分割方法。画像判定の場合、画像を何pixelの幅で何pixelごと分割するかなど。
* 特徴の抽出  
    * 特徴抽出に利用するモデル  
    特徴の抽出に使用するモデル。代表的な例だとAutoencoderや制限ボルツマンマシンなど。これらのモデルは、通常一つ一つにつき事前に学習を行っておく(Pre training)。
    * 抽出した特徴量の伝播方法  
    抽出した特徴を、どのノードに、どうやって伝えるか。例えば、抽出した特徴をすべて次のノードに伝えるとすると、逆に誤差も伝播してしまうことになるので、そこを調整するなど。
* 判定：抽出した特徴から最終的な判定を行う  
実はここはもうニューラルネットワークではなく、SVMなど一般的な分類器でもよい

以下は、その要素ごとに解説していきます。

# データの分割
データや音声など、解析対象のデータには様々な特徴が含まれます。最も理想的なのは1データ1特徴の形で分割することですが、そもそも何が特徴かわかってない状態でそれを行うのは難しいので、なるべく特徴を欠損させないようにデータを分割するのが重要になります。

例えば相撲取りの判定で最も重要なのが「マゲ」の有無だったとすると、この「マゲ」が分割した画像に収まってくれているかが非常に重要になります。仮にマゲが分割した画像の境界線上にあったりしたら判定ができなくなってしまうためです。

これに対するアプローチとして、単にデータを分割するのではなくある程度かぶせる(オーバーラップさせる)という手法がよく取られます。画像を分割する単位をウィンドウと呼びますが、このウィンドウを少しずつずらしていくというイメージです。文字列で言えば、データがABCDEでウインドウサイズが3・移動幅が1だとすると、データを「ABC」「BCD」「CDE」という風に取ることになります。
※なお、これはDeep learningに限った話ではないです

# 特徴の抽出
Deep learningの最大の特徴は、特徴それ自体の抽出を行える点です。では、それはどのように行われるのか。

## 特徴抽出に利用するモデル
基本的なアイデアは、Autoencoderというものです。Autoencoderについての解説は以下が分かりやすいです。入力と出力を同じにしたモデルを作成し、限られた特徴で入力を再現できるよう学習させるようなイメージです。

[Hello Autoencoder](http://kiyukuta.github.io/2013/08/20/hello_autoencoder.html)

これと共によく利用されるのが、制限ボルツマンマシン(Restricted Boltzmann Machine)です。こちらは、ざっくり言えば入力されたデータが発生するような確率分布を推定するという、確率モデルになります。解説はこちらが分かりやすいです。

[2012-12-12 ゆるふわ Restricted Boltzmann Machine](http://d.hatena.ne.jp/saket/20121212)

何れも「与えられたデータをうまく説明できるパラメータを探索する」という点で本質的には同じです([参考1](http://www.quora.com/How-is-a-Restricted-Boltzmann-machine-different-from-an-Autoencoder-Arent-both-of-them-learning-high-level-features-in-an-unsupervised-manner-Similarly-how-is-a-Deep-Belief-Network-different-from-a-network-of-stacked-Autoencoders)、[参考2](http://metaoptimize.com/qa/questions/11741/pretraining-neural-networks-autoencoders-vs-restricted-boltzmann-machines))。

Deep learningではこれらを個別に学習させて(Pre training)結合していきます。1層目は各自、2層目は1層目のパラメータを固定したうえで学習、という感じで進めていきます。イメージ的にはスタブを利用した単体テストに近いです。
この事前学習によって、層が深くなると誤差伝播がうまくいかない(上の層から伝播していくので、下の層に届きにくい)という多層ニューラルネットワークの弱点を克服しています。

## 抽出した特徴量の伝播方法
次に問題になるのが、次の層にどう伝えるかです。ここは、上述の通り情報の伝播と誤差の伝播がトレードオフの関係になります。
(なお、以下では各学習モデルのことをノードと記載します)。

![perception.PNG](https://qiita-image-store.s3.amazonaws.com/0/25990/8e9d8879-f1b7-129f-cad3-692aae77a715.png)

### 出力値(活性化関数(Activation function))
まず次の層(ノード)に伝播する値の計算方法を決めます。一般的なニューラルネットワークと同様シグモイド関数が使用されることが多いですが、Rectiﬁed  Linear Unitなども最近は使われるようです。
他にもmaxoutやLp Poolingなども利用されます。これらは複数の出力をまとめて値を決めるもので、maxoutはその名の通り最大値、Lp Poolingは・・・ちょっと一言では言えないいい感じの値を出力します。これについては、[Lp pooling](http://ceromondo.blogspot.jp/2012/10/lp-pooling.html)がとても分かりやすいのでご参照ください。  画像の細いエッジなどはそれを検知できるノードが少なくなり情報が伝播しにくくなりますが、これらはそうした微細な情報を取り洩らさないようにするためのテクニックになります(ざっくり言えば)。

### 伝播方法
伝播先をどのように設定するのかも検討事項です。一番簡単なのはニューラルネットワーク同様、次の層の全ノードに伝播することです。ただ、これだと当然誤差の伝播も発生し過学習などが発生することもあります。
これに対応する方法として、接続ノードを制限する局所受容野（Local receptive feild）や、ランダムに伝播しないノードを決定するDropoutといった方法が考案されています。

これらを決定した上で各ノードを結合していくことで、最終的に「事前学習済みの特徴抽出モデル」(ノード)が層状に組みあがります。これで抽出した特徴を利用し、最後の判定を行っていくことになります。

## 判定
最後判定を行うことになりますが、この最後の判定のための学習をFine trainingと呼びます。ここは、当然教師有学習になります。
最後までニューラルネットワークで組んで誤差伝播法で調整したり、SVMを上にくっつけて学習させるなどします。

以上がDeep learningの仕組みの解説になります。

# Deep learningを使う
もう気づいている方がいると思いますが、実はDeep learningは新技術というわけではなく、既存のニューラルネットワークをうまく組み合わせたものになります。そのため実装もやろうと思えば自力でできる・・・と思うのですが、さすがにつらいのでライブラリがあった方がいいと思います。

### ライブラリ

実装については、こちらにとてもよくまとまっています。
[実装ディープラーニング](http://www.slideshare.net/yurieoka37/ss-28152060?next_slideshow=1)

代表的なライブラリは以下になります。

* [TensorFlow](http://tensorflow.org/)
* [Chainer](https://github.com/pfnet/chainer)
* [Caffe](http://caffe.berkeleyvision.org/)
* [Theano](http://www.deeplearning.net/software/theano/)ベース
 * [Lasagne](https://github.com/Lasagne/Lasagne)
 * [Keras](http://keras.io/) ※TensorFlowベースでも動く
 * [Blocks](http://blocks.readthedocs.org/en/latest/) ※2015/12現在ではまだ開発途上
 * [pylearn2](http://deeplearning.net/software/pylearn2/) [※開発停止](https://github.com/lisa-lab/pylearn2/commit/48380daba195db8cf2a53ec86139a1ae7af89d7b)

GoogleがTensorFlowを発表し、これにかなり集約されていくのかなという感はあります。KerasがTensorFlowへの対応を行い、またscikit-learnライクに使えるラッパー([skflow](https://github.com/google/skflow))が登場するなど、周辺の開発も活発になっています。
画像ではCaffe、というのが以前の通説でしたがChainerではCaffeのモデル([Model Zoo](https://github.com/BVLC/caffe/wiki/Model-Zoo)で学習済みのモデルが公開されている)の[インポート機能が実装される](https://github.com/pfnet/chainer/pull/110)など、この辺りの優位性はなくなってくるかもしれません。Caffeはとかくインストールの手間(Issueの多くがインストール関連)やPython3非対応など周辺状況がよろしくないこともあり、モデルのインポート機能や他ライブラリでの学習済みモデルの配布が進むにつれ、移行が進む可能性は高いと思います。

なお、気になるPython3対応は、以下のようになっています。

* TensorFlow: 0.6.0より対応([Add support for Python 3.x](https://github.com/tensorflow/tensorflow/issues/1))。なお、TensorFlowはWindowsでは動かないので注意([現在対応中](https://github.com/tensorflow/tensorflow/issues/17))。
* Chainer: [1.1.0から対応](http://studylog.hateblo.jp/entry/2015/07/07/232858)
* Caffe: [対応する予定はないよう](https://github.com/BVLC/caffe/issues/293)。ただ、[気にはしており](https://github.com/BVLC/caffe/pull/1923#issuecomment-75701831)、[動かないことはない](https://github.com/BVLC/caffe/pull/1966)と見える
* Theano: 少なくとも2015/6の段階でsingle code baseでの対応を終えている([Document python3 installation](https://github.com/Theano/Theano/issues/2317))
 * pylearn2: 2014/11/15に[Python3対応のコードをマージ](https://github.com/lisa-lab/pylearn2/issues/948)
 
他は調べきれてないですが、多くのライブラリは対応をしています。TensorFlowで真っ先に立ったIssueがPython3対応だったことからも、Python2 onlyというのでは今後普及しないと思います。

ライブラリでなく自分で実装してみたい、という場合多くのライブラリがベースにしている[Theano](http://www.chino-js.com/ja/tech/theano-rbm/)、また[Restricted Boltzmann machines](http://scikit-learn.org/stable/modules/neural_networks.html)を搭載しているscikit-learnが役立つと思います。[yusugomori/DeepLearning](https://github.com/yusugomori/DeepLearning)はいろんな言語でDeep learningの実装をしているリポジトリで、こちらのソースコードも参考になると思います。

### 学習データ 
学習用データをどこから持ってくるのかも、機械学習における問題の一つです。自分で数万件のデータを取ってくるのは大変ですし、教師有学習のためにラベルを付けるとなったら気が遠くなります。
そんなわけで学習用データを提供してくれているサイトがあるので、ありがたく使わせていただきましょう。
※ただ、研究はともかくアプリケーションに活かそうとする場合はデータは自前で用意しないといけない場合が多く、ここでは地道かつ泥臭い作業が発生します。

* [MNIST](http://yann.lecun.com/exdb/mnist/)  
手書き文字のサンプルデータです。
* [CIFAR-10](http://www.cs.toronto.edu/~kriz/cifar.html)  
10クラス(airplane, automobileなど)にラベル付された画像集。CIFAR-100というより詳細なラベル付けがされたものもあります。
* [The Oxford-IIIT Pet Dataset](http://www.robots.ox.ac.uk/~vgg/data/pets/)  
CIFAR-10と同様、ラベル付きのデータ。その名の通り動物系です。
* [kaggle](https://www.kaggle.com/)  
データ解析のコンペティションサイト。モデルの精度を競い合うことができ、データも提供されています。[Kaggle Datasets](https://www.kaggle.com/datasets)でデータの検索、また公開もできるようになりました。
* [Microsoft Azure Marketplace](https://datamarket.azure.com/browse/data)  
NFLの試合結果や人口統計など、様々なデータが提供されています(有料なものもありますが、無料も多いです)。
* [UC Irvine Machine Learning Repository](https://archive.ics.uci.edu/ml/index.html)  
機械学習のためのデータセットを集めているサイト。
* [Harvard Dataverse](https://dataverse.harvard.edu/)  
ハーバード大学が公開しているデータセット。[Dataverse](http://dataverse.org/)というソフトウェアを使って公開していて、このサイトでは同様にこのソフトウェアを使ってデータを公開しているところを見ることができる。
* [COCO](http://mscoco.org/)  
Microsoftが公開している画像認識・また画像に対するキャプション等のデータセット(画像にキャプションを付ける[Neuraltalk2](https://github.com/karpathy/neuraltalk2)ではこれが利用されている)
* [nico-opendata](https://nico-opendata.jp/ja/index.html)  
研究者を対象にニコニコ静止画・動画のコメントなどのデータを提供している
* [DATA GO JP](http://www.data.go.jp/)  
日本政府が公開している、オープンデータのカタログサイト。[こちら](http://openlabs.go.jp/opendata/)には、各自治体の公開しているデータもまとまっている。
* [Data.gov](https://www.data.gov/)  
本家アメリカのオープンデータのカタログサイト
* [ShapeNet](http://shapenet.cs.stanford.edu/)  
3Dモデルのデータセット。家具から飛行機までと、色々な種類のモデルがそろっている。
* [DCASE](http://www.cs.tut.fi/sgn/arg/dcase2016/task-acoustic-scene-classification)  
自然音の分類を行うタスク(公園の音、オフィスの音など)で、学習・評価用データが公開されている。

その他、Deeplearning情報サイトの[Dataset](http://deeplearning.net/datasets/)でもいろいろなデータが紹介されています。画像系については[Resource - List of Interesting Very Large Datasets of Images](https://docs.google.com/spreadsheets/d/1VijZSkQbqOvsvYBXdCx9UGu5zHGZPPpzwH2uHS-2XxQ/edit#gid=0)によくまとめられています。

自然言語系はスクレイピングを行うことも多いですが、その際は倫理的な問題を頭に入れておきましょう([Webスクレイピングの注意事項一覧](http://qiita.com/nezuq/items/c5e827e1827e7cb29011))。

### 実践
今回はメジャーどころなpylearn2を使ってみます。Windowsの場合、恒例ですがインストールが地獄門なので[こちら](http://qiita.com/icoxfog417/items/707d25051fa15e843d09)をご参照ください(今回ばかりはこの地獄を抜けられないと一瞬思った)。

pylearn2が用意できたところで、まずは欲張らずにチュートリアルを動かしてみます。
[Quick-start](http://deeplearning.net/software/pylearn2/tutorial/index.html#tutorial)にあるのは`grbm_smd`というモデルで、これはDeep learningを構成する制限ボルツマンマシン(Restricted Boltzmann Machine)に該当します。

* `grbm`は`RBM with Gaussian units`の略です。RBMでは通常ノードが取れる値は0か1のバイナリ値ですが、これだと表現力に乏しいため、独立した分散を持つ線形関数(Gaussian unit)へ拡張したモデルになります。詳しくはこちらを参照してください([A Practical Guide to Training Restricted Boltzmann Machines](http://www.cs.toronto.edu/~hinton/absps/guideTR.pdf) 13.2の項)。この文書には、他にもRBMを実際に使う際のテクニックについてよくまとめられています。  
* `smd`は`denoising score matching`の意味で、これは入力データを意図的に欠損させ(ノイズを与える)、それがどれくらいうまく復元できたかをモデルの指標(=目的関数)とする方法です(Denoising autoencoder)。Deep learningの中にこうした役割の層を組み込むことで、例えば手書き文字で途中がかすれているような場合に対応力を上げることができます。

実際のモデルを図にしてみたものが以下になります。pylearn2では通常モデルをYAML形式のファイルで設定するので(今回のtutorialでは[cifar_grbm_smd.yaml](https://github.com/lisa-lab/pylearn2/blob/master/pylearn2/scripts/tutorials/grbm_smd/cifar_grbm_smd.yaml))、そちらの方も見てみてください。

![pylearn_quick.PNG](https://qiita-image-store.s3.amazonaws.com/0/25990/acf14bb2-047f-046b-f05b-1f6880663f03.png)

では、実際にやってみます。手順は[README](https://github.com/lisa-lab/pylearn2/tree/master/pylearn2/scripts/tutorials/grbm_smd)に書かれているので、そちらをなぞっていく形になります。

1. CIFAR-10データのダウンロード  
事前にpylearn2で使用するデータを格納するディレクトリを表す環境変数`PYLEARN2_DATA_PATH`を設定し、その後Gitのshellから  
`pylearn2/scripts/datasets/download_cifar10.sh`  
を実行します。
2. make_dataset.pyの実行  
`pylearn2/scripts/tutorials/grbm_smd`フォルダに移動し、データ作成のスクリプトを実行します(仮想環境の有効化を忘れずに)。  
`python make_dataset.py`  
3. train.pyの実行  
以上でデータが用意できたので、学習を行います(本当はpylearn2/scriptsをパスに入れるんですが、面倒なので相対パスで実行しています)。  
`../../train.py　cifar_grbm_smd.yaml`  
4. 実行結果確認  
これで学習済みのモデルができたはずなので、その中身を見てみます。matplotlibが使用されますが、これはcondaでインストールしないとうまく動きませんでした(Tcl/TckのGUI表示やPIL周りなど)。  
`../../show_weights.py cifar_grbm_smd.pkl`  
![learning1.PNG](https://qiita-image-store.s3.amazonaws.com/0/25990/1665f713-62da-20c0-2b7b-1b3e42e546d1.png)  
これがどうなっていればいいのかは謎ですが・・・少なくとも重みの大きさを反映しており、欠損はランダムに入ることを考えると、示されている色・濃さは復元しにくい色/箇所であることを表している?(補完の必要がなければ重みは必要ないはずなので)。  
また、学習によって誤り率が下がっていく状況を以下コマンドで簡単に確認できます(プロット対象に`b,L,M`を指定)。  
`../../plot_monitor.py cifar_grbm_smd.pkl`  
![learning2.PNG](https://qiita-image-store.s3.amazonaws.com/0/25990/19a63514-eb9f-9f32-d74a-6998fc5ebca8.png)

QuickStartは以上です。
難しい内容も含みましたが、ここまでで少なくともモデルの概念と実行環境は手に入ったのではないかなと思います。Deep learningは文字通りDeepな世界ですが、この記事がその理解へのとっかかりになればと思います。

# 参考資料
[Deep learning](http://www.slideshare.net/kazoo04/deep-learning-15097274)
[Hello Autoencoder](http://kiyukuta.github.io/2013/08/20/hello_autoencoder.html)
[2012-12-12 ゆるふわ Restricted Boltzmann Machine](http://d.hatena.ne.jp/saket/20121212)
[Lp pooling](http://ceromondo.blogspot.jp/2012/10/lp-pooling.html)
[ニューラルネットの逆襲](http://research.preferred.jp/2012/11/deep-learning/)
[Deep Learning技術の今](http://www.slideshare.net/beam2d/deep-learning20140130)
[実装ディープラーニング](http://www.slideshare.net/yurieoka37/ss-28152060?next_slideshow=1)
[ねこと画像処理 part 3 – Deep Learningで猫の品種識別](http://rest-term.com/archives/3172/)
[Convolutional Neural Network](http://ceromondo.blogspot.jp/2012/09/convolutional-neural-network.html)
[Convolution Neural Network for speech recognition](http://dnnip.wordpress.com/2013/09/04/convolution-neural-network-for-speech-recognition/)
[Building High-level Features Using Large Scale Unsupervised Learning](http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//archive/unsupervised_icml2012.pdf)