cedro-blog

Keras MLPの文章カテゴリー分類を理解する

今回は、ロイター・ニュースをMLPでカテゴリー分類するプログラムは、一体何をしているのか理解したいと思います。

こんにちは cedro です。

そろそろ、自然言語処理をやってみたいと思い、とっかかりを探していました。例によって、Kerasサンプルプログラムの中から物色した結果、初級編としてはロイター・ニュースをMLPでカテゴリー分類するものが良いのかなと思いました。

で、とりあえず動かしてみたわけです。私の Macbook Air でもあっという間に(1分以内に)完了したのは良かったわけですが、アウトプットは、Test accuracy: 0.7929652715939448 という文字がスクリーンに表示されるだけ。何をやっているのか、全く分かりませんでした。

という訳で、自然言語処理に踏み込む第一歩として、今回は、ロイター・ニュースをMLPでカテゴリー分類するプロフラムは、一体何をしているのか理解したいと思います。

 

ロイター・ニュースのデータセットとは?

ロイター・ニュースのデータセットとは、11,228個ニュース・データ46種類カテゴリーに分類されたもので、ニュース・データの単語は数字で表現されています。この数字は、同じ単語なら同じ数字が割り振られ、データ全体に登場する回数が多い単語ほど小さい数字が割り振られています。

 

実際のニュースデータカテゴリーの内容を見るためのプログラムです。実行すると、ニュースデータx_train) と カテゴリーy_train) の一番最初のデータ [0] を表示します。ニュースデータ87個の数字(データによって個数は異なりますカテゴリー1個の数字で表される訳です。ちょっと味気ないですね(笑)。

 

kerasのデータセットには、ロイター・ニュース単語を数字に変換する辞書があるので、まずそれを見てみましょう。このプログラムを実行すると、辞書の中身が見えます。先頭が {   ‘   ‘ で囲まれた単語を数字に変換した結果が : の次に書かれています。例えば、単語 ‘ mdbl ‘ を数字に変換すると 10996 になるという訳です。それでは、この辞書を使って、先ほどのニュースデータの数字を単語に戻してみましょう。

 

ニュースデータ87個の数字単語に戻すプログラムです。実行すると、辞書(単語→数字)を取得して来て、逆引き辞書(数字→単語)を作成し、単語へ変換します。文章の内容は「ある会社がある会社を買収して、利益が順調に伸び、配当も期待できそうだ」という意味の様です。英語は良く分かりませんが、さすがに数字よりはこっちの方が良いですね(笑)。

 

逆引き辞書の中身を確認するプログラムです。実行すると、先ほど表示した辞書とは、反対の表記になっていることが分かります。

 

辞書の数字出現頻度が高い単語ほど小さくなるので、出現頻度トップ10の単語を見るためのプログラムです。実行してみると、映えあるベスト1は「 the 」でした! パチパチパチ。以下、c の値を変えて、100位あたり、500位あたりも見て見ましたが、そう特別な単語がある訳ではないですね。

一つ注意したいのは、データセットは1〜3特別な意味を表す数字として使っているので、辞書で単語を数字に変換する場合は、3を加えて変換します。例えば 「said」 を数字に変換する時は、5+3=8となります。

 

せっかくなんで、最下位の方も見てみました。辞書に登録されている単語は、全部で30978個で、さすがにこの辺りになるとよく分からない単語ばかりになります。そうした中、映えある最下位は、「 jung」でした。

 

サンプルプログラムを順番に見て行きます。

冒頭の部分です。reuters.load_data で引数 num_words = 1000 とすることで、頻出上位1000位までの単語のみの数字データで読み込み、1000位以上の単語は「」(該当単語無し)として読み込みます。

 

Tokenizer を使って、文章をベクトル化する部分です。各ニュースのデータ数はまちまちですが、MLPに掛ける時には一定にする必要があります。また、データは特徴的な部分のみ残して余分な情報は省いておく方が、その後の処理が効率的です。

今、対象単語(num_words)10個とした場合、単語10個分のリストを作り、使っている単語は「1」使っていない単語は「0」とすることで、一定の長さのデータになり、かつシンプルなデータ構造になります。具体的に言うと、

I like fruit  —>  [ 1, 2, 3 ]  —>  [ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 ]
I like apples  —>  [ 1, 2, 4 ]  —>  [ 1, 1, 0, 1, 0, 0, 0, 0, 0, 0 ]
An apple is a fruit  —>  [ 5, 6, 7, 8, 3 ]  —>  [ 0, 0, 1, 0, 1, 1, 1, 1, 0, 0 ]

こんな感じです。各ニュースに出て来る単語の種類のみに着目して、出現する順番頻度の情報は省くことで、一定の長さでシンプルなデータ構造になります。この手法をBag of Words と言います。このプログラムでは、対象単語num_words)を1000個として処理しています。

カテゴリーを表す、0〜45の数字も、keras.utils.to_categorical でこれと似たようなデータに変換します。例えば y_train [ 0 ] = 3  —>  [ 0, 0, 0, 1, 0, 0, 0,      …..    0, 0 ] という感じ(3のところだけ1)。正確に言うと、これはワンホット表現と言って、46個の数字の内どれか1つだけ1で残りは全て0と言う表現です。

 

3行目からモデル構築です。入力を512個の全結合層で受けて、ドロップアウトを挟んで、46個の全結合層で出力、SoftMaxを使って46個の出力の確率を計算しています。一応、プログラム起動時に、モデルを表示したかったので、9行目に model.summary() を追加しました。26行目からは、予測精度の推移グラフを表示させる部分を追加しました。

 

プログラムを動かします

プログラムの起動初期画面です。ロイター・ニュースの内容やプログラムの動きを理解してから改めて動かしてみると、今までとは全然違う気持ちで画面を見れますね(笑)。

 

予測精度の推移グラフです。プログラムは、あっと言う間に完了し、予測精度 5 epoch79.07%でした。MLPは軽くて高速に動きますので、どんどんやってみたくなり、10 eopch を試してみましたが 79.16% とほとんど変わらず、グラフを見てもそれ以上は望めない感じです。

それならばと次は、max_words = 1000 を最大の 30978 にしてみようと、トライしてみました。計算量は飛躍的に増えますが、MLPですから 1epoch / 60 sec くらいで、楽勝です。

 

いやー、予想外でした。ほとんど変わらないんです。サンプルプログラムの設定、最適化されてます。それにしても、使っている単語数は 30,978語もあるのに、その中の頻出1000語だけを使うだけで、全部使ったのとほとんど変わらない予測精度が出せるのは、面白ですね。基本的な単語に絞っても、カテゴリーによって使う単語に結構違いがあるということでしょうか。

では、また。