ココンの情報をいつでも、どこでも。ココントコ。

エンジニア 2018.09.20

アンサンブル学習による自然言語分類 -後編-

AI戦略室の坂本です。
前回はアンサンブル学習と呼ばれる学習手法について、基本的なロジックをざっくり紹介しました。
今回は実際のプログラムコードを元にして、TF-IDFベクトルとアンサンブル学習による自然言語分類の手法を紹介します。
なお、ここで紹介しているコードは全て、
https://github.com/cocon-ai-group/ensemble-sample
にて公開しています。

目次

データセットの入手

まずはサンプルとして使用する、文章データの入手からです。
ここでは、日本語Wikipediaの文章から、「共和政ローマ」「王政ローマ」「不思議の国のアリス」「ふしぎの国のアリス」「Python」「Ruby」の6つの記事をダウンロードして、その中にある文章を3つのクラスに分類します。

つまり、「共和政ローマ」「不思議の国のアリス」「Python」の記事に含まれている文章から学習して、「王政ローマ」「ふしぎの国のアリス」「Ruby」の記事を正しく、「世界史に関する記事」「不思議の国のアリスに関する記事」「コンピューター言語に関する記事」に分類できるモデルを作成する、という事がお題となります。

そのためのプログラムは、上記GitHub内のget_word_vector.pyにあります。
データのダウンロードと形態素解析に関するコードは解説を省略します。
上記のプログラムで使用されるのは、ダウンロードした文章からTF-IDFベクトルを作成して返す関数で、以下のように定義されています。

この関数では、「1.txt」〜「6.txt」まで6つのファイルに、形態素解析して分かち書き済みの文章が保存されていることを前提にしています。
そして、ファイルの内容を読み込んだ後、TfidfVectorizerでTF-IDFベクトルを作成し、学習用データのセットと、テスト用データのセットを返します。
また、TfidfVectorizerからベクトルの要素に対応する語彙を取得して、「voc.txt」として保存します。

ランダムフォレスト法による分類

文章がTF-IDFベクトルになれば、機械学習のアルゴリズムを使用してモデルを作成するのは簡単で、ほぼライブラリのAPIを叩くだけです。
まずはScikit-learnにあるランダムフォレスト法を使用するコードから。

上記の関数は、ランダムフォレスト法で学習したモデルを返します。
作成したモデルは、以下のようにして使用することが出来ます。

分析結果をスコアとして表示するには、Scikit-learnのclassification_report関数を使用します。

以上の内容をまとめた、ランダムフォレスト法による分類を行うコードは、。上記GitHub内のrandomforest_classifier.pyにあります。
このプログラムを実行すると、以下のように分類のスコアが表示されます。

なお、この結果は乱数種の指定や元データによってだいぶ変化することに注意してください。
同じコードで実行しても、Wikipediaの文章が変更されているかもしれないため、同一の結果を保証するものではありません。

LightGBMによる分類

次にLightGBMを使用したコードです。
LightGBMではScikit-learnと同じ形式のAPIも用意されていて、そちらの形式を紹介している記事が多いですが、ここではオリジナルのAPIを使用してLightGBMを使用します。

APIの使用方法としては難しいところは無く、学習パラメーターをディクショナリで指定してやり、「lgb.Dataset」クラスで学習用データセットを指定してやるくらいです。
ランダムフォレスト法と異なるのは、学習の際に学習用データセットだけでは無く評価用のデータセットも一緒に指定することで、ここで指定した学習用データセットが決定木内のパラメーター学習に使用される一方、評価用のデータセットを使用して過学習を防ぐように動作します。
つまり、LightGBMのアルゴリズムは、評価用のデータセットによるスコアがそれ以上向上しなくなるか最大の学習回数まで、学習用データセットを使用して決定木の分岐を作成してゆきます。「lgb.train」関数で指定している「num_boost_round」が最大の学習回数で、「early_stopping_rounds」は、その回数だけ評価用のデータセットによるスコアが連続して悪くなった場合に学習を終了するというパラメーターです。

predictの結果は、全てのクラスに対するスコアとなるので、最大のスコアからなる配列を作成して、最終的な結果とします。

以上の内容をまとめた、LightGBMによる分類を行うコードは、。上記GitHub内のlightgbm_classifier.pyにあります。
このプログラムを実行すると、以下のように分類のスコアが表示されます。

印象として、LightGBMはパラメーターの最適化が必要で、小さいデータセットに対して漫然と使用しても、ランダムフォレスト法と同等以下の結果しか出ない場合があるようです。
一方、大規模なデータに対してチューニングしたパラメーターを指定してやると、非常に良い結果をもたらすので、使用の際にはそれなりの配慮が必要になりそうです。

XGBoostによる分類

次はXGBoostを使用したコードです。
XGBoostによるコードもLightGBMとほぼ同じで、難しいところはありません。

LightGBMと異なるのは、学習済みのモデルに対してpredictを呼び出すところで、LightGBMではnumpyのndarrayをそのままpredict出来ましたが、ここでは「xgb.DMatrix」クラスのインスタンスである必要があります。
そこで、「get_xgb」関数の最後では、学習済みモデルと一緒に「xgb.DMatrix」クラスのインスタンスにしたテスト用データを返すようにしています。実行時には以下のように使用するようにしました。

以上の内容をまとめた、LightGBMによる分類を行うコードは、。上記GitHub内のxgboost_classifier.pyにあります。
このプログラムを実行すると、以下のように分類のスコアが表示されます。

CatBoostによる分類

そして問題のCatBoostによる分類です。
実は、ここで使用しているサンプルデータでは、データサイズが小さいため、前回紹介したような次元削減の手法を使用しなくても、そのままCatBoostアルゴリズムを使用することが出来ます。
しかしそれでは、上記のLightGBM・XGBoostと同じことをするだけで面白くないので、ここではあえて次元削減の手法を使用して、小さくて密な行列によるCatBoostの使用方法を紹介することにします。

まずは入力データから重要度の高いデータを取得するところです。
重要度はLightGBMの学習済みモデルから取得するようにしており、ここでは関数の引数に指定が無ければ、新しく学習を走らせて学習済みモデルを取得するようにしました。
そして重要度の値でソートして、上位15個を表示します。ここで使用しているデータは、文章データから作成したTF-IDFベクトルなので、語彙として保存しておいたファイルを読み込めば、重要な単語を取得することが出来ます。
上のコードが実行されると、以下のように単語のリストが表示されます。

次に、重要度で上位500個の単語のベクトルと、次元削減のアルゴリズム5種によって作成した、それぞれ100次元ずつのベクトル5個を合わせて、合計1000次元のベクトルを作成します。
この、1000次元のベクトルデータが、学習データとなる密なベクトルとなります。

最後の機械学習部分はXGBoostの時とほぼ同じで、異なっているのはパラメーターの指定と、データの指定に「cb.Pool」クラスを使用しているくらいです。

以上の内容をまとめた、CatBoostによる分類を行うコードは、。上記GitHub内のcatboost_classifier.py
関わらにあります。
このプログラムを実行すると、以下のように分類のスコアが表示されます。

前述の通り、ここで使用しているサンプルデータは、データサイズが小さいため特に次元削減の手法を使用せずともCatBoostアルゴリズムを適用可能です。
ここでは例として次元削減を使用しましたが、使用しない場合の方がCatBoost単体でのスコアは高くなります。

アンサンブルによる分類

そしていよいよアンサンブル学習です。
アンサンブル学習では、これまで紹介した全てのアルゴリズムを使用して学習を行い、その結果から多数決を取って最終的な結果とします。
前回の記事にも載せたアンサンブル学習のロジック図をもう一度掲載するので、ソースコードと見比べてみてください。

まずは、アンサンブル学習を行う部分のコードです。

多数決を取る関数として「get_one」を定義し、4つのアルゴリズムで学習した結果を、最終的に一つの結果のリストにしています。
そして、そのアンサンブル学習を呼び出す部分です。

上のコードでは、4つのアルゴリズムからなるアンサンブル学習を一回だけ実行し、その結果のスコアを表示しています。
上のコードが実行されると、以下のようにスコアの値が表示されます。

これだけだとあまり良いスコアにはなっておらず、アンサンブル学習のメリットが感じられないかもしれません。
そこで今度は、乱数種を変えながら複数回アンサンブル学習を行い、それらの結果からさらに多数決を取るようにします。
これは、今回使用したアルゴリズムでは、学習用データセットと評価用のデータセットを分けて使用するものが多く、データセットの分割によって結果が大きく変わる場合があるためです。
ランダムフォレスト法ではサブサンプルの作成と結果の結合が主な原理でしたが、それと同じ事で、これはいわばアンサンブル学習のランダムなフォレストとも言えます。

また、乱数種を変えて複数回実行する方法の他に、FKold等で分割した複数回の学習を行う事もあります。

上記のコードが実行されると、以下のように結果のスコアが表示されます。

今度は、F1スコアを見ると、アンサンブル学習で使用したランダムフォレスト法・LightGBM・XGBoost・CatBoostそれぞれ単体でのどのスコアよりも、良いスコアが出てきました。
単体で最も良いモデルが最上で、悪いモデルに引きずられてスコアが下がるかと思いきや、面白いことにアンサンブルを取ることで全体としてより優れたモデルが作成されている訳です。

まとめ

以上、前後二回にわたってアンサンブル学習の手法を紹介してきました。
アンサンブル学習はディープラーニングと同じく機械学習の手法の一つですが、回帰分析やクラス分類においては多くの場合ディープラーニングよりも良い結果を出すことが出来て、しかも学習時間などの面で優位性もあります。
アンサンブル学習では、それぞれの学習アルゴリズムについてパラメーターのチューニングが必要になるなど、適切なモデルの作成に手間がかかるのが難点ではありますが、少なくとも回帰分析やクラス分類などの問題に対しては、現状で最高に近い結果をもたらしうる解析手法と言えるのではないでしょうか。

イベント 2018.12.06

手に汗握る!デジタルイラストグランプリ開催

Panda Graphics株式会社の塩田です! Panda Graphicsは、主にスマートフォン向けのソーシャルゲームを中心…

エンジニア 2018.11.14

競馬予想AI再び -後編- 〜アンサンブル学習編〜

AI戦略室の坂本です。 あまりに気合いを入れて作成すると、社内での自分の評価が「競馬予想の人」になって…

エンジニア 2018.11.14

競馬予想AI再び -前編- 〜LambdaRank編〜

AI戦略室の坂本です。 元はといえば忘年会の余興から始まった競馬予想AIですが、ブログ記事のアクセス数も…