深層学習でニュース記事を分類する


#はじめに
ニュース記事のBag-of-Words(BoW)から，カテゴリを予測するみたいなことをStacked Denoising Autoencodersでやってみました．

#データセット
データセットは[livedoor ニュースコーパス](http://www.rondhuit.com/download.html#ldcc)を使います．
>本コーパスは、NHN Japan株式会社が運営する「livedoor ニュース」のうち、下記のクリエイティブ・コモンズライセンスが適用されるニュース記事を収集し、可能な限りHTMLタグを取り除いて作成したものです。

らしいです．

- トピックニュース
- Sports Watch
- ITライフハック
- 家電チャンネル
- MOVIE ENTER
- 独女通信
- エスマックス
- livedoor HOMME
- Peachy

の計9つのカテゴリがあるので，9クラス分類問題になります．

#データ前処理
まず記事をBoWにする必要がありますが，これには[yasunori](https://github.com/yasunori/)さんの[Random-Forest-Example](https://github.com/yasunori/Random-Forest-Example)のcorpus.pyを利用させていただきました．

```
python corpus.py
```
を実行すると辞書(livedoordic.txt)を作ってくれます．初回だけ実行します．
次に入力として与えるデータを作成します．corpus.pyについてget_class_idというメソッドについてのみ↓のように書き換えたんだけどかなり昔にやったからどうしてそうなったのか思い出せない．．．

```python:corpus.py
def get_class_id(file_name):
    '''
    ファイル名から、クラスIDを決定する。
    学習データを作るときに使っています。
    '''
    dir_list = get_dir_list()
    dir_name = filter(lambda x: x in file_name, dir_list)
    return dir_list.index(dir_name[0])
```


```python
import corpus
import numpy as np

dictionary = corpus.get_dictionary(create_flg=False)
contents = corpus.get_contents()

data = []
target = []
for file_name, content in contents.items():
	data.append(corpus.get_vector(dictionary, content))
	target.append(corpus.get_class_id(file_name))
data = np.array(data, np.float32) #入力として与えるデータ
target = np.array(target, np.int32) #正解データ
```

#Stacked Denoising Autoencoders
今回はDenoising Autoencoderを深層化したStacked Denoising Autoencoders (SDA)で学習させます．実装は[Chainer](http://chainer.org)を利用しています．Autoencoderに関する説明は[kenmatsu4](http://qiita.com/kenmatsu4)さんの[【ディープラーニング】ChainerでAutoencoderを試して結果を可視化してみる。](http://qiita.com/kenmatsu4/items/99d4a54d5a57405ecaf8)が個人的にすごくわかりやすいです．
SDAはAutoencoderを3つ積層，過学習防止にDropout，Masking noise，活性化関数にはReLUを使っています．訓練，評価データの比率は9:1です．
SDAのコードは僕のGitHubの[deep-learning-chainer](https://github.com/hogefugabar/deep-learning-chainer)リポジトリにSDA.pyという名前であげてます．
実行したコードは下みたいな感じです．

```python
import numpy as np
from SDA import SDA
from chainer import cuda

cuda.init(0)

rng = np.random.RandomState(1)
sda = SDA(rng=rng,
		  data=data,
		  target=target,
		  n_inputs=6974,
		  n_hidden=[500,500,500],
		  n_outputs=9,
		  gpu=0)
sda.pre_train(n_epoch=10)
sda.fine_tune(n_epoch=30)
```

#実行結果
###SDA
```
C:\Python27\lib\site-packages\skcuda\cublas.py:273: UserWarning: creating CUBLAS
 context to get version number
  warnings.warn('creating CUBLAS context to get version number')
--------First DA training has started!--------
epoch 1
train mean loss=0.106402929114
test mean loss=0.088471424426
epoch 2
train mean loss=0.0816160233447
test mean loss=0.0739360584434
--
中略
--
epoch 9
train mean loss=0.0519113916775
test mean loss=0.0670968969548
epoch 10
train mean loss=0.0511762971061
test mean loss=0.0661109716832
--------Second DA training has started!--------
epoch 1
train mean loss=1.28116437635
test mean loss=0.924632857176
epoch 2
train mean loss=0.908878781048
test mean loss=0.763214301707
--
中略
--
epoch 9
train mean loss=0.500251602623
test mean loss=0.55466137691
epoch 10
train mean loss=0.485327716237
test mean loss=0.517578341663
--------Third DA training has started!--------
epoch 1
train mean loss=1.0635086948
test mean loss=0.778134044507
epoch 2
train mean loss=0.656580147385
test mean loss=0.612065581324
--
中略
--
epoch 9
train mean loss=0.433458953354
test mean loss=0.486904190264
epoch 10
train mean loss=0.400864538789
test mean loss=0.46137621372
fine tuning epoch  1
fine tuning train mean loss=1.33540507985, accuracy=0.614027133827
fine tuning test mean loss=0.363009182577, accuracy=0.902306635635
fine tuning epoch  2
fine tuning train mean loss=0.451324046692, accuracy=0.869683239884
fine tuning test mean loss=0.235001576683, accuracy=0.945725910052
fine tuning epoch  3
fine tuning train mean loss=0.233203321021, accuracy=0.937104056863
fine tuning test mean loss=0.172718693961, accuracy=0.952510164098
fine tuning epoch  4
fine tuning train mean loss=0.156541177815, accuracy=0.957164381244
fine tuning test mean loss=0.167446922435, accuracy=0.962008120247
--
中略
--
fine tuning epoch  27
fine tuning train mean loss=0.0105007310127, accuracy=0.997586716714
fine tuning test mean loss=0.217954038866, accuracy=0.960651269438
fine tuning epoch  28
fine tuning train mean loss=0.00783754364192, accuracy=0.998340867404
fine tuning test mean loss=0.206009919964, accuracy=0.957937559732
fine tuning epoch  29
fine tuning train mean loss=0.00473990425367, accuracy=0.998491696822
fine tuning test mean loss=0.245603679721, accuracy=0.95793756782
fine tuning epoch  30
fine tuning train mean loss=0.00755465408512, accuracy=0.998190036187
fine tuning test mean loss=0.228568312999, accuracy=0.962008120247
```

分類精度の推移グラフは以下のようになっています．
<img src="https://dl.dropboxusercontent.com/u/38631959/sda_result.png" width=500px>

###多層パーセプトロン
事前学習を行わなかった場合どうなるのか調べたくて，同じ構造の多層パーセプトロンでも実験してみました．SDAと同じく過学習防止にDropout，活性化関数としてReLUを利用しています．
<img src="https://dl.dropboxusercontent.com/u/38631959/nn_result.png" width=500px>



#おわりに
最終的な分類精度としてはSDAは95%位となり，かなりいい結果となりました．多層パーセプトロンは92%位となり，SDAより汎化性能が悪いことがわかりますが，実験を一回しか回していないので結果の信憑性はあやしいです．

変なところとかありましたらご指摘いただけるとありがたいです．