stacked generalization

[概要]
最近のkaggle のコンペのwinning solution で、stacked generalization がよく使われています。これの元になった論文は、1992 年のWolpert さんによるものです。
triskelion さんのブログKaggle Ensembling Guide | MLWave
の中でもこの手法についての説明があります。

様々な学習器を上手く組み合わせて、より精度の良いモデルを作ろうというのが基本的な考え方です。具体的には次の図のような感じです。
f:id:puyokw:20151211225201p:plain
level 0 は、元となるデータです。またこの場合における各学習器はgeneralizer と呼ばれています。level 0 のデータにgeneralizer を適用して生成されたデータがlevel 1 のデータとなります。
その後も、同様に名づけられています。

[過去のコンペ]
まずは、多層パーセプトロンのように単純に組み合わせた場合の例を挙げます。
Otto のコンペでは、1 位、2 位、4 位の方はこの手法を使われていました。これは多クラス分類で、9 つのクラスに分ける問題で、評価関数はmlogloss です。
4 位の方はgithub にコードをupload されていますので、気になる方は参照してください。
1 位の方のモデル(kaggle のforum にて):
1st PLACE - WINNER SOLUTION - Gilberto Titericz & Stanislav Semenov - Otto Group Product Classification Challenge | Kaggle
2 位の方のモデル(kaggle blog にて):
Otto Product Classification Winner’s Interview: 2nd place, Alexander Guschin ¯\_(ツ)_/¯ | No Free Hunch
4 位の方のコード(github):
GitHub - diefimov/otto_2015

応用版は、さらに複雑なネットワークを形成したモデルです。
Dato のコンペは2 値分類で、評価関数はauc です。
Dato Winners’ Interview: 1st place, Mad Professors | No Free Hunch

こちらでは、階層をまたいだグラフになっています。

[訓練データの作り方]
まず検証用のデータは、いつも通りに訓練データを用いてモデルを作成して検証用のデータに適用します。
次に、1 段階上で使用する訓練データを作成します。ここでは、nfold =2 の場合で概略を説明します。
f:id:puyokw:20151204235306j:plain
cross validation の要領で、validation data の予測値を集めたものが次の段階で使用する訓練データになります。
nfold を増やすと、次の段階で使用するトレーニングデータの平均値が良くなります。しかしその反面、分散(標準偏差)が増えたり、計算に時間が掛かったりします。
分散が増えると、元のデータと異なる傾向のものになってしまう危険性があります。すなわち、cv score は改善しているのに、提出してみると酷いスコアが出てしまいます><
分散が大きいときの対策としては、nfold を小さくする、あるいはbagging をすることが考えられます。

自明なことですが、下位のモデルが改善すれば、それが伝播してより上位のgeneralizer が生成するモデルも良くなります。
またstacker model は、stacked generalization を使用するつもりがなくても、xgboost + NeuralNet のような単純なensemble をする場合に、どのくらいの割合で混ぜるのかを調べるのにも有用です。

チューニングのやり方は他のモデルと同様に、

  • cv score
  • 変数重要度(xgboost やrandomForest などでは)

を見ながら行っていきます。


[実際に試してみました]
ここでは、Otto のコンペのデータで実際にstacked generalization を使用してやり直した際に使用したモデルです。
上記の図を再掲しますが、これがそのときに使用したモデルです。
f:id:puyokw:20151211225201p:plain
コードはほぼcross validation を自分で書くだけのようなもので、やり方だけ確認して自分で組んでみるのが良いかなと思います。ちなみに、2nd level のxgboost による変数重要度の上位30 項目は次のようになっています。
f:id:puyokw:20151211225243p:plain
各々の学習器の何が効いているのかが、ちらっと垣間見えます。また上記の図では、モデルを簡略化して書いていまして、実際のところ、1st level の学習器の詳細は次のようになっています。

  • randomForest (n_estimators=300) + calibration
  • extraTrees (n_estimators=300) + calibration
  • xgboost (max_depth = 12, eta = 0.01)
  • kNearestNeighbor (k=2,4,8,16,32,64,128,256,512,1024,2048)
  • NeuralNet ( hidden-dropout の順に、中間層が次のような3 パターンを試しています。

512-0.5-512-0.5,
512-0.5-512-0.5-512-0.5,
512-0.5-512-0.5-512-0.5-512-0.5 )

  • svm(cost = 10)

今回の評価関数はmlogloss で、各クラスの境界付近を各学習器がどのように分けているのかが非常に重要で、mlogloss が0.40 を下回るにはそこを意識する必要があったように思えました。
ちなみに、今回試したモデルでのスコアは次のようになってました。
f:id:puyokw:20151211225338p:plain
Public LB score: 0.39756, Private LB score: 0.39869 でした。

ここで、使用したコードはgithub
github.com
にup していますので、気になる方はご覧ください。