Fri Sep 13 2019

[WIP] fastcnn を作っている

fasttext は本当に好きなツールで, 中身は word2vec (SGNS) の高速化+subword に他ならない. 中身への信用度もあるけど, テキスト分類ツールとして必要な操作が全てコマンドで提供されいているのもいい. だからとりあえずテキスト分類したいものが手元にあって, 労力を掛けずにどの程度分類出来るのかを試すのによく使う.

ただしそれが日本語の場合はままならない. subword があるにしても, 基本的にはトークナイズがなされていることが前提にある. 従って MeCab なりなんなりで, ある程度はトークナイズをしてから fasttext に投げるのが理想的だ. しかしそんな労力すら惜しい.

  1. なんでもいいからルールベースのニホンゴトークナイザーを作る
  2. 文字 CNN

1 は簡単だからその内やるとして, 今は fasttext の文字CNN 版を作っている.

fastcnn

中身は Keras だし, 別に fast ではない. いい加減 Python を脱却したいので, いい自動微分ライブラリがあれば Rust なりで書き直したい. GPU を要求するのもいい加減ダサいし.

BBC News

データフォーマットは fasttext と全く同様. 具体的には次のようなもの.

URL=https://storage.googleapis.com/dataset-uploader/bbc/bbc-text.csv
curl $URL | tail -n +2 | sed 's/^\([^,]*\),/__label__\1\t/' > data.all
cat data.all | awk 'NR % 4 != 0' > data.train
cat data.all | awk 'NR % 4 == 0' > data.valid

ちなみにこのデータセットはニュース記事に5種類のラベルが貼られている.

走らせる. 実際には Keras のいろんなログや警告メッセージが大量に流れるけど省略.

   fastcnn supervised data.train --verbose --validate data.valid --stat --maxlen 100 --kernel-size 5 --dim 300 --epochs 300 --stop-window 90 --lr 0.2 --clip-norm 2.0

  ___________________________________________
 /                                           \
| Task: classify_single, #labels=5, #chars=57 |
| - Training with 1669 samples                |
| - Validation with 556 samples               |
 \                                           /
  ===========================================
                                                \
                                                 \
                                                   ^__^
                                                   (oo)\_______
                                                   (__)\       )\/\
                                                       ||----w |
                                                       ||     ||


  ______________________________
 /                              \
| Training data stat:            |
| Labels:                        |
| - __label__tech : 300          |
| - __label__business : 373      |
| - __label__sport : 390         |
| - __label__entertainment : 292 |
| - __label__politics : 314      |
| Sentence Length:               |
| - max : 25483                  |
| - min : 727                    |
| - avg : 2271.0107849011383     |
 \                              /
  ==============================
                                   \
                                    \
                                      ^__^
                                      (oo)\_______
                                      (__)\       )\/\
                                          ||----w |
                                          ||     ||


  _____________________________
 /                             \
| Validation data stat:         |
| Labels:                       |
| - __label__sport : 121        |
| - __label__business : 137     |
| - __label__tech : 101         |
| - __label__politics : 103     |
| - __label__entertainment : 94 |
| Sentence Length:              |
| - max : 19136                 |
| - min : 501                   |
| - avg : 2238.6978417266187    |
 \                             /
  =============================
                                  \
                                   \
                                     ^__^
                                     (oo)\_______
                                     (__)\       )\/\
                                         ||----w |
                                         ||     ||

Model: "classify_single"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
embedding_1 (Embedding)      (None, 100, 300)          18300
_________________________________________________________________
conv1d_1 (Conv1D)            (None, 96, 600)           900600
_________________________________________________________________
max_pooling1d_1 (MaxPooling1 (None, 48, 600)           0
_________________________________________________________________
conv1d_2 (Conv1D)            (None, 47, 600)           720600
_________________________________________________________________
max_pooling1d_2 (MaxPooling1 (None, 1, 600)            0
_________________________________________________________________
flatten_1 (Flatten)          (None, 600)               0
_________________________________________________________________
gaussian_noise_1 (GaussianNo (None, 600)               0
_________________________________________________________________
dropout_1 (Dropout)          (None, 600)               0
_________________________________________________________________
dense_1 (Dense)              (None, 300)               180300
_________________________________________________________________
dense_2 (Dense)              (None, 5)                 1505
=================================================================
Total params: 1,821,305
Trainable params: 1,821,305
Non-trainable params: 0
_________________________________________________________________
Epoch 1/300
 - 4s - loss: 1.6090 - acc: 0.2205 - val_loss: 1.6088 - val_acc: 0.2176
Epoch 2/300
 - 2s - loss: 1.5968 - acc: 0.2536 - val_loss: 1.5963 - val_acc: 0.2464
Epoch 3/300
 - 2s - loss: 1.5914 - acc: 0.2634 - val_loss: 1.5900 - val_acc: 0.3040

 :

Epoch 41/300
 - 2s - loss: 0.0249 - acc: 0.9982 - val_loss: 0.5630 - val_acc: 0.8183
Epoch 42/300
 - 2s - loss: 0.0212 - acc: 0.9994 - val_loss: 0.5485 - val_acc: 0.8129
Epoch 43/300
 - 2s - loss: 0.0153 - acc: 1.0000 - val_loss: 0.5409 - val_acc: 0.8255

ちなみにこのデータセットはそんなに難しくないらしくて, この人は学習済み GloVe 300 次元を使って 90% を簡単に達成してる. https://github.com/cemsaz/bbc-news-classifier

しかし, 単語ベクトルの学習がそうであるように教師なし学習は偉い. 教師ありで 300 次元なんてやっても, 簡単に訓練データに過学習するだけだ. 教師なしは過学習とかが無いから偉い.