実践多クラス分類 kaggle ottoから学んだこと
Post on 24-Jul-2015
3.343 Views
Preview:
TRANSCRIPT
実践 多クラス分類
西尾泰和
この資料の目的
Kaggleのコンペに参加することで色々な実践的ノウハウを学んだので
そのノウハウを共有する
p.3~53 コンペ中に自分がやったことp.54~99 ハイランカーがやっていたことp.100~ハイランカーかやっていたことを
自分も実際にやってみる
2
kaggle
Otto Group Product Classification Challenge
IN:93個の特徴量、OUT:9クラスに分類
train.csv 61878行 test.csv 144368行
各クラスである確率を提出し、log lossで評価
3
クロスバリデーション
回答の投稿は1日に3回まで
手元でいろいろ試してよさそうなものを選びたい
↓
train.csvでのクロスバリデーション
4
Stratified K Fold
train.csvは各クラスごとにデータが並んでいた→単純に分割してテストデータにしてはいけない→Scikit-learnが色々な方法を提供している例: StratifiedKFold:クラス比率を保つように分割
5
def do_cross_validation():model = make_model()cv = cross_validation.StratifiedKFold(ys)scores = cross_validation.cross_val_score(
model, xs, ys, cv=cv, scoring='log_loss')print("Accuracy: %0.2f (+/- %0.2f)“
% (scores.mean(), scores.std() * 2))
http://scikit-learn.org/stable/modules/cross_validation.html#cross-validation
とりあえずロジスティック回帰
Accuracy: 0.76±0.01
所要時間 4分
6
とりあえずロジスティック回帰2
2個ずつの組み合わせで(93 * 92 / 2)の特徴を追加0が多いのでscipy.sparse.lil_matrixを使ったそのままLRに食わせられる/stdはない
Accuracy: 0.79±0.01 (0.03アップ)
所要時間 45分
未解決課題:掛け算で大きな値に。スケール調整が有効ではないかと思うが、スパース行列だから「平均を引く」とかやると台無し。どうする?
7
sklearn.joblib
train.csvをnumpy.arrayにするだけで9秒かかる
作ったarrayをjoblib.dumpでファイルに書き出す
joblib.loadは1.5秒。
学習済みモデルとかもダンプできる!便利!
(注意点:大量のファイルができるので保存用のディレクトリを作るべきだった)
8
とりあえずRandomForest
複数の特徴量を組み合わせたい→決定木
Kaggleでは決定木の仲間のRandomForestとGBDT(Gradient Boosted Decision Tree)が人気らしい(gbm, xgboostなど)
両方試してみよう
9
10 R Packages to Win Kaggle Competitionshttp://www.slideshare.net/DataRobot/final-10-r-xc-36610234
RF/GBDT
trainの1/100のデータAと全データBとで比較
LR 0.76±0.01 -
RF(A) 0.62±0.02 2秒RF(B) 0.78±0.01 22秒GBDT(A) 0.70±0.02 50秒GBDT(B) 0.78±0.00 1時間15分!
GBDTは勾配を推定してその情報を利用するため2クラス分類しかできず、この例だと36回の2クラス分類が行われて時間がかかる。
LRよりは良い性能になった。
10
submitしてみる
スコアはLog lossなので小さい方がよい
1次のLR 0.66674
2次のLR 0.65391(best)
RF 3.99786(えっ)
ここまでAccuracyでモデルを評価していたけど、ここでLog lossで評価しないとKaggleのスコアとの食い違いが大きいことに気が付く
11
scoringオプション
cross_val_scoreはデフォルトでは正解率を返す
scoringオプションでlog lossなど色々なものを選ぶことができる
12
def do_cross_validation():model = make_model()cv = cross_validation.StratifiedKFold(ys)scores = cross_validation.cross_val_score(
model, xs, ys, cv=cv, scoring='log_loss')print("LogLoss: %0.2f (+/- %0.2f)"
% (scores.mean(), scores.std() * 2))
http://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter
Log lossでのLRとRFの比較
RFはデフォルトで木が10本。変えて試す。
RF(10) -1.57±0.08 30秒RF(20) -0.97±0.08 43秒RF(40) -0.72±0.02 1分25秒RF(100) -0.63±0.02 3分50秒RF(200) -0.60±0.02 11分RF(400) -0.59±0.01 14分RF(600) -0.59±0.01 22分RF(800) -0.59±0.01 -
RF(1000) -0.60±0.02 -
1次のLR -0.67±0.00 1分30秒
13
Log lossでのLRとRFの比較
RF(400)Log loss -0.59±0.01
Accuracy 0.80±0.00
1次のLR
Log loss -0.67±0.00
Accuracy 0.76±0.01
RF(400)は1次のLRよりは良いはずだ!
14
submitしてみる2
スコアはLog lossなので小さい方がよい
1次のLR 0.66674
2次のLR 0.65391(best)
RF(10) 3.99786
RF(100) 1.27508RF(400) 1.21971(あれれ?)
Log lossを最適化する問題*にRFを使うのが筋悪なのかな??
15
*追記:Kaggle Ottoは各クラスの確率値を提出させ、そのLog lossでランキングする課題
合体
未解決課題:Log Lossを最適化する問題には何を使うのがよいのだろうか?→RFよりはLRの方がマシかな?
RFは「特徴量が閾値以上か」という二値分類機を多段で組み合わせて決定木を作ってくれる。
LRは「特徴量をどんな重みで足し合わせるとLog Lossが最小になるか」を求めてくれる
→この2つを合体!
16
合体:GBDT+LR
GBDT(10)の予測した確率を特徴量に追加してLRを学習(以下GBCLR)
LR -0.67±0.00
GBCLR -0.54±0.01 (大躍進!)
Submitしてみた
LR 0.666742次のLR 0.65391
GBCLR 0.58467 (大躍進!)
17
(2次のLRのCVの結果がないのはexpがoverflowして計算できなかったため)
LRの弱点をRFが補う
LRは与えられた特徴量の線形結合なので複数の特徴のANDの情報を使うには掛け合わせるなどした特徴を作る必要がある
決定木系は閾値関数のANDを人間の代わりに試行錯誤してくれる
作られた特徴量を入れる代わりに9次元に潰された情報を入れただけで性能がかなりアップした
18
LRの弱点をRFが補う2
LRは重みつき足し合わせなのでスケールを適切に調整する必要がある
RFは閾値でぶった切るのでスケールは無意味
今回のtrainデータは実は0に鋭いピークがあって指数的に頻度が下がり大きい方の値は50とかもあるような「全然正規分布じゃない」分布
どうスケール調整するかは悩ましい問題だった
19
合体路線の今後の案
GBRTの木の数を増やす(つまらない)
GBRT全体での推測結果ではなく、GBRTの各木の推測結果を特徴量にする
GBRTの各木の各リーフをバイナリ特徴量にする(特徴量の数がとんでもないことになる)
20
土台固め
モデルの改善よりも土台周りで色々見えてきた問題を先に解決しておこう
21
--after複数同時に走らせるとメモリが心配
次のを走らせるために、今走っている処理が終わるのを人間が待つのは嫌
そこで--after=<pid>オプションを指定するとそのPIDのプロセスが死ぬまで待ってから自分自身の処理を続行するようにした
22
def wait(pid):while True:
try:os.kill(pid, 0)
except OSError:return
else:time.sleep(60)
その後プロセスIDを手で打つのもたるいので--after=autoで一番新しいPythonを対象にするようにした
if args.after == "auto":pid = int(subprocess.check_output("pgrep python", shell=True
).split()[-2])
joblib再び
joblibの保存先をソースフォルダから分けた
data/fooに保存するとdata/foo_2000.npyとか(特にRFだと)2000個のファイルが作られる
保存されたモデルを一覧で見づらい *
不要なものを削除するのも不安 **
data/foo/indexに保存して、消すときにはfooをディレクトリごと消すのが吉かな(でも今から変えるのは既存の保存データの扱いが面倒。次回やる***)
23
* ls data | grep –v npy** 富豪的に「消さない」ってのもありか*** forest-coverでやった。
保存データの名前空間今はフラットな名前空間にモデルも学習データも混在して直置きされているが…
24
41252
43563
46334
GBC
GBCLR
LABELLR
cross_lr
rfc
rfc10
rfc100
test_cross_data
test_data
train_GBC
train_cross_data
train_data
train_labeled
←PIDで自動保存されたモデル、リネームされてないのはいらないやつだから消してもいいはずだが…
←自動保存されたモデルをリネームしたもの
←モデルの保存名をソースにハードコードしてた時代
←モデルの種類とパラメータからモデルの保存名を生成しようとしていた時代(データを変え始めて破綻)
←変換済みテストデータ(保存し忘れがある模様)(PIDでの自動保存をこっちにも追加すべきか)
←変換済み学習データ
カオス!
保存データの名前空間
「なんとなくな命名規則」で今まで進んできたがデータの側をいじり始めて:
「モデルM1」「モデルM1で特徴量を付加したtrain_M1」「train_M1で学習したモデルM2…の名前は…」
きな臭いにおいがし始めている…。
(--train=train_foobar ってオプションも微妙)
25
--name
--name=<name>が指定されているとき、そのプロセスが作るすべてのファイル名に<name>が入る(例: 学習済みモデル<name>.npy, 投稿用データsubmit_<name>.csv)
指定されない時、モデル種別・元データ・PIDから一意な名前を生成して使う
・わかりやすい名前を付けることができる・名前を付けなくても後から探しやすい・事後的にmvで分かりやすい名前に変えられる・適当にやっても既存のファイルを壊さないが実現される
26
データの指定
学習データをオプションで指定するのは正しい設計だろうか??
ユースケース「-c --train=train_fooでクロスバリデーション」「うん、いい成果だ、submitしよう」「-s --train=train_foo」→テストデータが指定されていないため、デフォルトのものを使おうとして次数ミスマッチで死亡
27
データではなく変換を指定
オプションでデータを指定するのではなく変換方法を指定すべきでは?(変換済みデータがない場合は生成・保存)
28
と思ったのだけど
ユースケース:4000次元×60000行のtrainデータは作れて学習もできたが、4000次元×140000行のtestデータは作るときか使用するときにメモリ不足で死ぬ
メモリ不足で死んだときには自動で少しずつ作るモードにフォールバックすべき?
今は手書き個別対処(どうせ1日に3件しかsubmitできないので)
29
追記:その後write_submit関数がテストデータのイテレータを取る設計に変更した
行列の分割
arrayを少しずつ処理するためにnp.arrayを分割するコード。numpy.array_splitという便利なものがあるのに今気づいた…。
30
def split_array(xs):
N = len(xs)
for start, end in split(N):
yield xs[start:end]
……# deflate(inflate(xs))相当
new_xs = np.r_[tuple(
deflate(inflate(xs_))
for xs_ in split_array(xs))]
self.model.fit(new_xs, ys)
def split(N, divide=10):
M = N / divide
for i in range(divide):
start = i * M
end = (i + 1) * M
if i == divide - 1:
end = N
yield start, end
LabelBinarizer
特徴量に名義尺度のものが混ざっているという噂
分布を眺めてみたけどそれらしき分布は見つからない…(でも名義尺度の頻度順ソートかも)
全特徴量をLabelBinarizer#fitしてLRしたら改善LR -0.67±0.00 0.66674
LABELLR -0.61±0.00 0.59759
確かに名義尺度が混ざっているのかも…。
31
for i in range(NUM_FEATURES):
lb = preprocessing.LabelBinarizer()
lb.fit(xs[:,i])
labels[i] = lb.transform(xs[:,i])
xs = np.c_[tuple([xs] + labels)]追記:np.c_[tuple(…)]はnp.hstackがよさそう→
4053次元
全特徴を名義尺度とみなしたものを追加すると特徴量は4053次元になる
GBDT(10)元データ -0.78±0.00 1時間15分名義尺度 -1.08±0.01 2時間33分
GBDT(20)名義尺度 -0.85±0.01 5時間04分
決定木の眷属は特徴量が多くなると「うまい組み合わせを選べる確率」が下がって性能が出なくなる?→LRをL1でつかう
32
L1による特徴選択
LogisticRegression(penalty=‘l1’, C=0.01)で4053次元の名義尺度データを学習
model.transform(xs)で4053次元のデータを低次元に投影→179次元になった
33
LB→LR(L1)→GBDT
元データA、LabelBinarizerしたデータB、それをLR(L1)で圧縮したデータCについて:
GBDT(10)A -0.78±0.00 1時間15分B -1.08±0.01 2時間33分C -1.08±0.01 7分14
GBDT(20)B -0.85±0.01 5時間04分C -0.85±0.01 15分5
GDBT(40)C -0.71±0.01 26分49
34
時間の差の大きさに一瞬戸惑ったが、データの次元が22倍で15分の22倍は5時間半だから変というほどではないか?むしろGBDT(10)のAが変?
全部入り(ICHI)
「オリジナルのtrain.csv
+GBDT(100)で予測したクラス+LB→LR(L1)→GBDT(40)で予測したクラス」を全部まとめてLRで学習させたモデル
略してICHI
LR -0.67±0.00 0.66674
GBCLR -0.54±0.01 0.58467
LABELLR -0.61±0.00 0.59759
ICHI -0.53±0.00 0.55831
35
全部入り(NII)
ICHIの特徴量にRF(400)での推定結果を加えて学習させたLR、略してNII
RF(400) -0.59±0.01
ICHI -0.53±0.00
NII -0.01±0.00 (えっ?!)
Submitしてみた
ICHI 0.55831NII 0.63648 (悪化…。)
アンサンブル学習のやり方がまずい?保留。
36
PCAの効果
「PCAで次元削減して~するとよい」という噂
93次元しかないデータなのに、いきなり「分散が小さい」って理由で何軸かの情報を捨ててしまうとか、悪くなる気がする……。
でも、検証してみよう。
37
PCAの効果2
0:オリジナル 1:PCA掛けただけ2:PCAで白色化 3:PCAで50次元に削減4:30次元に削減 5:10次元に削減
RF(10) LR0 -1.57±0.08 -0.67±0.001 -1.67±0.08 -0.67±0.002 -1.68±0.09 -0.68±0.003 -1.65±0.03 -0.71±0.004 -1.77±0.03 -0.78±0.005 -2.36±0.03 -1.06±0.01
次元削減のダメージは大きい
38
PCAの効果3
次元削減ではなく軸を回転することによって「軸方向の分割」で構成されている決定木は性能が向上する可能性がある。確かめてみよう。
RF(400)PCAなし -1.57±0.08
PCAあり -1.59±0.01
→目立った効果はない「PCA→RF(400)」の結果を追加した「SAN」を作るつもりだったけどやめた
39
分離が難しいクラス
クラス2とクラス3の分離が難しいという噂・どうすれば自分でそれに気づけるか・どう対処するか
作ったモデルで分類して、間違えて分類したものに関する統計データが手軽に得られるべき
・クラス2と3だけのデータでモデルを学習したら分離に適切な特徴量が出てくるのでは・間違えて分類したものだけ選んで学習したらどうか(手動AdaBoostもどき)
40
sklearn.svm.SVC
当初、木やリーフの情報を特徴量にするつもりでRFをチョイスしていたけど、結局、推定結果を特徴量にしているのでRFである必要はない
RFで軸に沿ってまっすぐ切るのは既にやったからどうせなら曲線で切りたい
→じゃあサポートベクターマシン!
41
SVC
「SVCの計算量はデータの二乗よりでかいオーダーだから10000以上だとつらいかもね」(意訳)
とマニュアルに書いてある。測ってみる。
N=100 16ms
N=200 54ms
N=400 191ms
N=1000 1.08s
N=2000 3.7s
N=4000 17s
N=10000 102s
42
YON
ICHIでtrain.csvをpredictしてLog Lossの大きい方から10000件のデータを選んでSVCし、そのpredict結果を特徴量として追加。
ICHI -0.53±0.00 0.55831
NII -0.01±0.00 0.63648
YON -0.47±0.01 0.54944 (改善!)
43
# 2行目もっとうまく書ける?
lp = model.predict_proba(xs)
logloss = np.array([lp[i, ys[i] - 1] for i in range(len(xs))])
bad_items = logloss.argsort()[:N_BEST]
アンサンブル学習
アンサンブル学習について調べていたら [1][2][3] 、僕と同じLRによるアンサンブルをやっているソースコード [4] を発見。彼は711
人中17位になったそうな。対象コンペ [5] は2クラス分類でLog
Lossで評価される、今回のによく似たタイプ。
[1] How to ensemble different models? - Africa Soil Property Prediction Challenge | Kaggle
https://www.kaggle.com/c/afsis-soil-properties/forums/t/10753/how-to-ensemble-different-models
[2] Best Ensemble References? - Africa Soil Property Prediction Challenge | Kaggle
https://www.kaggle.com/c/afsis-soil-properties/forums/t/10391/best-ensemble-references/54305
[3] Question about the process of ensemble learning - Predicting a Biological Response | Kaggle
http://www.kaggle.com/c/bioresponse/forums/t/1889/question-about-the-process-of-ensemble-
learning/10945
[4] kaggle_pbr/blend.py at master · emanuele/kaggle_pbr
https://github.com/emanuele/kaggle_pbr/blob/master/blend.py
[5] Description - Predicting a Biological Response | Kaggle
http://www.kaggle.com/c/bioresponse
44
アンサンブラーの実装
given X, Y, Xsub, make YsubM: モデルの個数 pp: Predict Probability
45
GO
Ensamble(LR, GBDT(100), LB→LR(L1)→GBDT(40),
RF(400), ICHI→LogLoss Top10000→SVC)
をやりたいのだけど、スモールスタートで
Ensamble(LR, GBDT(100), LB→LR(L1)→GBDT(40),
RF(100), ICHI→LogLoss Top1000→SVC)
をやった。2時間36分。
ICHI -0.53±0.00 0.55831
YON -0.47±0.01 0.54944
GO - 0.47977 (すごい改善!)
46
ROKU
Ensamble(LR, GBDT(100), LB→LR(L1)→GBDT(40),
RF(400), ICHI→LogLoss Top10000→SVC)
機械学習勉強会までに計算が終わるか終わらないか微妙なところ(朝9時現在)
10時間3分
GO 0.47977ROKU 0.46783 (改善)
Top10% 0.44371 (目標)
47
順位的には2301人中 631位→513位
アンサンブラーの高速化
個別のモデルに関する部分はメモ化できる。
少し手を加えれば普通のクロスバリデーションとしても使える。
クロスバリデーションで色々なモデルを試す過程で、ブレンド用のデータを吐き出して置けば、それを束ねてLRするだけで良いのでは?
48
以下追記49
写真150
写真151
93*6万次元のXと1*6万次元のYと93*14万次元のXsubから9*14万次元のYsubを作る。9はクラス数。10foldで9割のtrainと1割のtestにわけ、trainXとtrainYでモデルMを学習。モデルMにtestXを入れて確率推定したものPを10個並べて9*6万のQができる。それぞれのモデルにそれをしてM個並べて(9*M)*6万のRができ、RとYとでLRを学習。またモデルMにXsubを入れて9*16万のS、SをM個平均してT、Tを並べてUを作る。先ほど学習したLRにUを入れて確率推定したものがYsub。
僕のアンサンブラー
ICHIやNIIで使った僕のアンサンブラーも各モデルの推定結果を特徴量にしてLRを学習するところは同じ。
Foldしてないのが違い(過学習の原因)
52
アンサンブルしない普通のをこの記法で描くとこう
写真253
M個並べるのよりも手前はモデルごとに計算できるので、メモ化可能。モデルにはKNNや各種カーネルのSVM、NBなど色々突っ込める。後段で学習しているLRは各モデルの予測結果と正解から予測結果の良さを得てアンサンブルの際の混ぜあわせ重みを決定する役割を果たしている。
追記2
コンペが終わったので・最終的にどうなったか・上位ランカーはどういう方法を使っていたか・新しく知った手法を試してみるを追記
54
1ページで前回のおさらい
Kaggle Otto Group Product Classification Challenge
IN:93個の特徴量、OUT:9クラスに分類train.csv 61878行 test.csv 144368行各クラスである確率を提出し、log lossで評価
西尾の戦略RandomForestとかSVMとかで予測した結果を特徴量としてLRでアンサンブル。特徴量を5-fold CVで作るようにしたら性能0.54→0.47
55
成果発表
西尾:
public 0.45545 799位private 0.45715 838位/3512
1位のチーム:
public 0.38055
private 0.38243
アンサンブラ改善に匹敵する大きな差が。上位入賞者がモデルを公開しているのでよく読んで技術を盗もう!
56
1位のチーム
Gilberto Titericz & Stanislav Semenov
3層構造
1層目:33個のモデル(これの予測結果を2層目の特徴量として使う)と8個の追加特徴量
2層目:
GDBT(XGBoost)
NN(Lasagna)AdaBoost(ScikitのExtraTree)
3層目:重み付き平均
57
https://www.kaggle.com/c/otto
-group-product-classification-
challenge/forums/t/14335/1st-
place-winner-solution-gilberto-
titericz-stanislav-semenov
1層目のモデル
-Model 1: RandomForest(R). Dataset: X
-Model 2: Logistic Regression(scikit). Dataset: Log(X+1)
-Model 3: Extra Trees Classifier(scikit). Dataset: Log(X+1)
(but could be raw)
-Model 4: KNeighborsClassifier(scikit). Dataset:
Scale( Log(X+1) )
-Model 7: Multinomial Naive Bayes(scikit). Dataset:
Log(X+1)
Log(X+1)。これ計算してplotまではしたけど形がイマイチで特徴量として採用してなかった…
58
1層目のモデル:FM
-Model 5: libfm. Dataset: Sparse(X). Each feature
value is a unique level.
libfm*はSVDなどのような行列分解系の方法をSVMと組み合わせることによって、SVMが苦手なスパースなデータに対してよい性能を出すFactorization Machines**の実装。
59
* http://www.libfm.org/
** http://www.ismll.uni-hildesheim.de/pub/pdfs/Rendle2010FM.pdf
1層目のモデル:NN
-Model 6: H2O NN. Bag of 10 runs. Dataset:
sqrt( X + 3/8)
H2Oは多層のNN(いわゆるディープラーニング)
の実装を容易にするライブラリ。
60
http://0xdata.com/product/
1層目のモデル:NN
-Model 8: Lasagne NN(CPU). Bag of 2 NN runs.
First with Dataset Scale( Log(X+1) ) and second
with Dataset Scale( X )
-Model 9: Lasagne NN(CPU). Bag of 6 runs.
Dataset: Scale( Log(X+1) )
Lasagneは多層のニューラルネットを実装することを容易にするライブラリ。Python。
61
http://lasagne.readthedocs.org/en/latest/index.html
1層目のモデル:t-SNE
-Model 10: T-sne. Dimension reduction to 3
dimensions. Also stacked 2 kmeans features
using the T-sne 3 dimensions. Dataset: Log(X+1)
t-SNEは” t-distributed stochastic neighbor
embedding”の略。次元削減の方法。
62
t-distributed stochastic neighbor embedding - Wikipedia, the free encyclopedia
http://en.wikipedia.org/wiki/T-distributed_stochastic_neighbor_embedding
sklearn.manifold.TSNE — scikit-learn 0.16.1 documentation
http://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html
1層目のモデル:Sofia-Model 11: Sofia(R). Dataset: one against all with learner_type="logreg-pegasos" and loop_type="balanced-stochastic". Dataset: Scale(X)-Model 12: Sofia(R). Trainned one against all with learner_type="logreg-pegasos" and loop_type="balanced-stochastic". Dataset: Scale(X, T-sne Dimension, some 3 level interactions between 13 most important features based in randomForestimportance )-Model 13: Sofia(R). Trainned one against all with learner_type="logreg-pegasos" and loop_type="combined-roc". Dataset: Log(1+X, T-sneDimension, some 3 level interactions between 13 most important features based in randomForestimportance )
63
Sofia
Sofia*色々なアルゴリズムの詰め合わせ。パラメータでlogreg-pegasosを指定しているから
>Logistic Regression (with Pegasos Projection)を使っているのだろう。
Pegasos**はSVMのSGDによる最適化部分を置き換えることで収束速度を改善するもの。ここではLRの最適化に流用している。
64
* https://code.google.com/p/sofia-ml/
** Pegasos: Primal Estimated sub-GrAdient SOlver for SVM
http://www.ee.oulu.fi/research/imag/courses/Vedaldi/ShalevSiSr07
1層目のモデル:xgboost
-Model 14: Xgboost(R). Trainned one against all. Dataset: (X, feature sum(zeros) by row ). Replaced zeros with NA.-Model 15: Xgboost(R). Trainned Multiclass Soft-Prob. Dataset: (X, 7 Kmeans features with different number of clusters, rowSums(X==0), rowSums(Scale(X)>0.5), rowSums(Scale(X)< -0.5) )-Model 16: Xgboost(R). Trainned Multiclass Soft-Prob. Dataset: (X, T-sne features, Some Kmeans clusters of X)-Model 17: Xgboost(R): Trainned Multiclass Soft-Prob. Dataset: (X, T-sne features, Some Kmeans clusters of log(1+X) )-Model 18: Xgboost(R): Trainned Multiclass Soft-Prob. Dataset: (X, T-sne features, Some Kmeans clusters of Scale(X) )
65
xgboostはGBDTの実装の一つ
https://github.com/dmlc/xgboost
1層目のモデル:NN(GPU)
-Model 19: Lasagne NN(GPU). 2-Layer. Bag of 120
NN runs with different number of epochs.
-Model 20: Lasagne NN(GPU). 3-Layer. Bag of 120
NN runs with different number of epochs.
Lasagnaを使ってNNをGPU実装。
66
1層目のモデル:xgboost
-Model 21: XGboost. Trained on raw features.
Extremely bagged (30 times averaged).
特に工夫なくxgboostを30回走らせて結果を平均したもの。
データをダウンロードして、まず真っ先に「xgboostを繰り返すプログラム」を走らせてから他の実装を始めたと憶測
67
1層目の特徴量:KNN
-Model 22: KNN on features X + int(X == 0)
-Model 23: KNN on features X + int(X == 0) +
log(X + 1)
-Model 24: KNN on raw with 2 neighbours
-Model 25: KNN on raw with 4 neighbours
:
-Model 33: KNN on raw with 1024 neighbours
モデル4にKNN(Scale( Log(X+1) ))があったけど特徴量としても追加している。異なるチームメンバーが別個に実装したと憶測。
68
1層目の特徴量:Distance
-Feature 1: Distances to nearest neighbours of
each classes
-Feature 2: Sum of distances of 2 nearest
neighbours of each classes
-Feature 3: Sum of distances of 4 nearest
neighbours of each classes
-Feature 4: Distances to nearest neighbours of
each classes in TFIDF space
-Feature 5: Distances to nearest neighbours of
each classed in T-SNE space (3 dimensions)
最寄りクラスタまでの距離
69
1層目の特徴量:謎
-Feature 6: Clustering features of original dataset
何を意味しているのかよくわからない
70
1層目の特徴量:非ゼロ
-Feature 7: Number of non-zeros elements in
each row
非ゼロの特徴の数
-Feature 8: X (That feature was used only
in NN 2nd level training)
生データ
71
2層目3層目
XGBOOST(GDBT): 250 runs.
Lasagna(NN): 600 runs.
ExtraTree(ADABOOST): 250 runs.
3層目でXGBOOSTとNNを0.65:0.35で幾何平均その後ETと0.85:0.15で算術平均
平均の種類を変えてパラメータサーチすることがかえって過学習の原因にならないか疑問。
72
自分の方法との比較
SVMがない(改善しないので捨てたらしい)→おそらくFMで十分カバーされている
PCAがない(これも捨てたらしい)→おそらくt-SNEで十分カバーされている
非ゼロ個数を特徴に追加→同じ
距離を特徴に追加→その発想はなかった
73
1層目は弱い学習機でもよい
1層目でPoorでも2層目の改善に貢献する
> Interestingly some of our models scored very
poorly at 1st level. But contributed in 2nd level. ex.
Model 2 CV ~ 0.65, Model 5 CV ~ 0.55.
Model2はLR、Model5はFM
74
計算コスト
> I used AWS Amazon CPU server with 32 cores
for calculating XGboost, etc. And used AWS
Amazon GPU server with 4 Nvidia Grid K520 for
calculating NNs. Models on 2nd level is really
computationally hard.
32コアなのはc3.8xlarge。1時間$1.68。スポットインスタンスを利用して$0.256。何時間走らせたのかは不明。
75
Leakage
CVの際のLeakageを気にする声
一方、Leakageしない別のアプローチでは計算コストが高くなりすぎることから「悪くないトレードオフ」との指摘もある。
これはコードが公開されてから再確認が必要そう
76
6位チーム
“it seems like this competition was all about two
things: finding ways to get different biases in
the individual models, and having a good
method for ensembling beyond just
averaging.”
77
https://www.kaggle.com/c/otto-group-product-classification-
challenge/forums/t/14296/competition-write-up-optimistically-convergent
アンサンブル
5-fold stratifiedでモデルを学習して、trainデータ全体に対するpredictionを作る。
→ケース1: 5つでBaggingしてtestに対して使う
→ケース2: 使わずに別途全データでtraining
→最終的に: そのpred.を使ってアンサンブルのパラメータをfitting
大枠では僕のと同じ。彼らのアンサンブラはNN
78
ニューラルネット全部ReLU。出力層はSoftmax。
LB=0.446: Input -> 0.13 Dropout -> 2500 -> 0.77 Dropout -> 1300 -> 0.35 Dropout -> 40 -> 0.1 Dropout -> Output (AdaGrad, 600 epochs, batch=1024, linear decreasing learning rate starting at 0.04, ending at 0.005)
LB=0.441: Input -> 0.15 Drop -> 2000 -> 0.7 Drop -> 1200 -> 0.4 Drop -> 40 -> Output (AdaGrad, 400 epochs, batch = 512, learning rate from 0.04 to 0.001)
LB=0.463: Input -> 0.15 Drop -> 180 -> 0.1 GaussianNoise-> 0.1 Drop -> 180 -> 0.05 Drop -> 180 -> 0.05 Drop -> 140 -> 0.05 Drop -> 140 -> 0.05 Drop -> 140 -> 0.1 Drop -> 140 -> 0.1 GaussianNoise -> 160 -> Output (AdaGrad, 100 epochs, batch=512, rate = 0.03 to 0.005)
79
ニューラルネット
>One thing is that even though the network with
2000 nodes in the first layer had a better LB score,
it ensembled significantly worse than the one
with 2500 nodes.
入力層が2000個の方がLBでのスコアはよかったが、アンサンブル結果は2500個の方がよかった→2500個の側が運よくいい特徴を拾っていただけではないかと憶測
80
Boosted Neural Nets
Input→0.15→2000→0.7→1200→0.4→40→Outputをrate=0.02 .. 0.005で25エポックだけ学習
→Log lossが平均Log lossの2%より小さいRowを削除して学習しなおす(僕がモデルYONでLogLoss
の大きい方から1万件だけでSVCを学習したのと同じようなアプローチ)
→これを16回繰り返す(!)
→0.433のNNができた(僕のスコアを超えた)
81
SGDで特徴探し
SGDは最高で0.58程度だけど、シンプルな仕組みであるがゆえに「よい特徴を追加した」時に性能が大きく上がるので特徴探しに便利。
「大きい方から4件の特徴の位置に1が立っている93次元ベクトル」
特徴AとBのインタラクションを「A*B」ではなく「1 if A > B else 0」にした方がよい成績。
82
SVM
カラムごとにスケールを調整するとよい。
83
キャリブレーション
NNに対してCalibratedClassifierCVを使ってキャリブレーションをすると大きく改善する。
10-fold isotonic calibrationで、0.443→0.435
84
http://scikit-
learn.org/stable/modules/generated/sklearn.calibration.CalibratedClassifierCV.html
アンサンブル
アンサンブルの手法が最も重要
このコンペはLog lossを問うものだからもしたくさんのものを平均しすぎると平均回帰によってLog lossが悪化する→NN-basedアンサンブラ→0.58!
85
アンサンブル
2つのモデルをブレンドする際に、まずその2つのモデルが同じクラスを返す確率pXYを求め、モデル1の重みをbとして
Pb = pXY * (P1*b + P2*(1-b) ) + (1-
pXY)*( P1^(2*b) * P2^(2*(1-b)) ) / ( P1^(2*b) *
P2^(2*(1-b)) + (1-P1)^(2*b) * (1-P2)^(2*(1-b)) )
でブレンド後の確率を求める。
この有用性に関してはよくわからない。0.0007の改善になったらしい。
86
FE不要論
“Minimal feature engineering was needed, as all
the features were count of some events not
disclosed to participants”
「特徴量がイベントの回数である」という説明を読み落としていた…。
これだとラベル化は筋悪ということになる。
87
https://kaggle2.blob.core.windows.net/forum-message-
attachments/79384/2507/summary.pdf?sv=2012-02-12&se=2015-05-
28T02%3A29%3A24Z&sr=b&sp=r&sig=GSMFMgUpNYb%2B4xZaWtxF%2BNzT3s%2F
Ve3kwvoHjHdqS9qM%3D
モデル
XGBoost: scikit-learnの他のモデルとの一貫性のためにラッパーを実装、0.44x
NN: Lasagne使ってReLUとDropout、GPU。Sparse AutoencoderとReLUで多層Perceptronとも書いてあるけど、Lasagneでやったか不明* 0.44x
SVM: RBFカーネルが一番 0.45x
RF, Extra Trees: ETがRFよりも良い成績。キャリブレーションがとても有効。0.44x
あと2次のLRとKNN
88
* Referenceにkerasが載ってるからそっちかも
パラメータサーチ
・人力GD
→収束カーブを見て「もっとDropoutが必要だ」などと判断できるメリット
・グリッドサーチパラメータの少ないSVCとかRFに有効
・ランダムサーチ何が重要なパラメータかわからない時に有用
89
Bergstra and Bengio(2012)“Random Search for Hyper-Parameter Optimization”
http://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf
ランダムサーチ
寄与の小さいパラメータがある場合、Grid Layoutではその軸方向のサンプルが無駄になってしまう
90
[Bergastra and Bengio 2012]から引用
ガウス過程によるパラメータサーチ
「良い結果が得られるパラメータを探す」は関数の最大値を探す最適化問題
関数が滑らかである仮定をガウス過程として導入することで、未探索の値に対してのUCBが計算できるようになる
UCBが最大となる点を探索していくことでRegret
最小の探索ができる(強化学習的発想)
91
Srinivas+ (2010) “Gaussian Process Optimization in the Bandit
Setting:
No Regret and Experimental Design”
http://las.ethz.ch/files/srinivas10gaussian.pdfhttp://www.robots.ox.ac.uk/seminars/Extra/2012_30_08_MichaelOsborne.pdf p.82から
Random Direction
現在の最良のパラメータを中心として正規分布で適当に選んで実験、良くなっていたら採用、悪くなっていたら捨てるだんだん正規分布の分散を狭める
(局所解にはまりそうな…)
92
実験
XGBoostは5つのパラメータがある。- 木の最大数 5..35
- shrinkage 0.4..1- 最大深さ 4..10
- 行サブサンプリング 0.4..1
- 列サブサンプリング 0.4..1
これを上記4手法でパラメータサーチ
93
結果94
RDが意外といいけど、予想通りLocal Minimumにはまるケースが多く分散が大きくなっている。GPは安定しているが、平均的にはRDに負けてる。GP自体にハイパーパラメータがあり、それのチューニングはされていない。
アンサンブル
まず単純平均を試してみた→まあまあ
シグモイドの逆関数で変換(IST)してからLR→改善
最終的に:ISTしてから隠れ層1枚のNNでFittting
NNのハイパーパラメータはGP UCBで決めた。
何度か異なる乱数シードで走らせると0.00xぐらい改善する
比較:自分のやったのは「ISTしないでLR」
95
25位?
xgboostでモデルを作ってGAでアンサンブル
特徴量:総和、非ゼロの個数、 1,2,3の個数、最大値、最大値の場所、t-SNE、距離
今までで最良のモデルによる推定結果を特徴量として追加する(僕と同じ)
96
https://www.kaggle.com/c/otto-group-product-classification-
challenge/forums/t/14315/strategy-for-top-25-score
距離
各行に対して、各クラスの中のすべての行との距離を計算して、距離の分布を求め、その分布の10, 25, 50, 75, 90th percentileを45次元の特徴量として加える
1位チームの「各クラスの最も近い点への距離」は0パーセンタイルだけを使っていることに相当する。階層的クラスタリングでの、ある点がどのクラスタに最も近いかを判定する上で最も近い点か最も遠い点かそれとも平均かセントロイドか…
という議論*に似ている。
97
* http://en.wikipedia.org/wiki/Hierarchical_clustering のLinkage criteriaの節
GAでアンサンブル
DEAP* を使う
the gene was a vector length 20 composed of
different model numbers.
20個以上あるモデルの中から20個のモデルをどう選ぶかを遺伝子にコーディングし、選んだモデルを平均したののスコアを最適化する
98
* https://github.com/deap/deap
112位相当:Meta-bagging
“Meta-bagging”によって112位相当のスコアが出せるという主張。“Meta-bagging”という言葉は広く使われているものではない。
第1層でSVM、RF、GBM*などを学習した後、その結果の幾何平均と元データとを入力とするNN
を50個学習してそれらをBaggingする
99
https://www.kaggle.com/c/otto-group-product-classification-
challenge/forums/t/14295/41599-via-tsne-meta-bagging/79084
* GBM=Gradient Boosting Machine, たとえばxgboost
やってみる
xgboost
Lasagne
Gaussian Process
t-SNE
100
xgboost
R用だけどPythonからでも叩ける
xgb.train叩くだけ、予想外に楽&早かった
Ottoのデータに対してCVして他の方法と比べてみよう→Sklearnのインターフェイスと揃えるためにラッパーを自分で書いて少しトラぶった。すでに書いて公開している人もいる。これを使うのでもよかったかも。
101
https://gist.github.com/slaypni/b95cb69fd1c82ca4c2ff
xgboost
Log Loss: -0.48 (+/- 0.01)
Fit time: 2730.05 (+/- 548.52)
Predict time: 769.46 (+/- 202.69)
elapse 09h54m23s
参考ICHI -0.53±0.00 0.55831
YON -0.47±0.01 0.54944 *
GO - 0.47977
* アンサンブラ改良前最高性能と同程度
102
Lasagne
ラザニアだからLasagnaと思ってたけどeが正解
宣言的にニューラルネットの層の間の接続を記述すると中でTheanoが更新式を作り出して良しなに学習してくれるNN界の超高級言語
バージョン0.1devだけどKaggleで使われているのをよく見かけるライブラリの一つ
ドキュメントがPoorなのでサンプルコードを読む
103
サンプル: mnist.py104
この図に描いてあるようなことがほぼそのままbuild_model関数の中に書いてある
実行
Epoch 1 of 500 took 144.361straining loss: 1.344822validation loss: 0.466205validation accuracy: 87.58 %%
Epoch 2 of 500 took 140.929straining loss: 0.592950validation loss: 0.332910validation accuracy: 90.45 %%
500ステップのうちの1ステップに2分掛かるということは単純計算で全部終わるまでに17時間かかるよな…。
105
実行中
約1時間後Epoch 30 of 500 took 154.024straining loss: 0.130883validation loss: 0.089886validation accuracy: 97.31 %%
約2時間半後Epoch 60 of 500 took 160.892straining loss: 0.077516validation loss: 0.067623validation accuracy: 97.86 %%
約3時間半後Epoch 170 of 500 took 80.355straining loss: 0.026319validation loss: 0.056770validation accuracy: 98.43 %%
106
学習終了
約15時間後Epoch 500 of 500 took 157.920straining loss: 0.007425validation loss: 0.064233validation accuracy: 98.48 %%
python mnist.py 40219.81s user 130.37s system 74% cpu 14:58:08.57 total
でも一番性能がいいのはEpoch 397 of 500 took 94.733straining loss: 0.010540validation loss: 0.061012validation accuracy: 98.59 %%
107
ハイパーパラメータ
Nesterov Momentumなんだか重要な役割をしているみたい近いうちに調べておく
学習率、レイヤーのサイズ、ドロップアウト率うーん、パラメータだらけだぞ
108
考察
成績を見て適当なところで打ち切るか、一番良いものを取っておくように実装する必要がある
割と時間的コストが高い。しかも、これたぶん並列に走らない
ハイパーパラメータがたくさんあるのでパラメータを変えて何度も走らせる必要がある。ここを並列でやるのがよいか。
なんにせよラップトップにはつらい。
109
サンプル: mnist_conv.py110
サンプル: mnist_conv_dnn.py
Conv2DLayerがdnn.Conv2DDNNLayer
MaxPool2DLayerがdnn.MaxPool2DDNNLayer
になっている(ネーミングセンス…)
これはNVIDIAの出しているcuDNNライブラリをTheano経由で叩く実装、つまりGPUを使う
cnDNNではConvとPoolとSoftmaxしか実装されてなさげ→画像処理でないDNNには有用でない
111
sandbox.cuda.dnn – cuDNN — Theano 0.7 documentation
http://deeplearning.net/software/theano/library/sandbox/cuda/dnn.html
言及されていたもの色々fchollet/keras
同じくTheanoベースのNNライブラリLasagneと比べてどうなの?ドキュメントどこ?
https://github.com/fchollet/keras/tree/master/ker
as
IssamLaradji/NeuralNetworks
SklearnベースのNNライブラリ、Sparse Autoencoderの実装がある
https://github.com/IssamLaradji/NeuralNetworks
112
Gaussian Process UCB
GPはsklearnに実装がある
fitしてpredictすると平均と分散が返ってくるのであらかじめ計算しておいた定数βを掛けてargmax
113
http://scikit-learn.org/stable/modules/gaussian_process.html
http://scikit-
learn.org/stable/modules/generated/sklearn.gaussian_process.GaussianProcess.html
GP-UCB-PE, TPE
GP-UCBを改良したGP-UCB-PE*の実装が改良した本人によって公開**されている(Matlab)
Tree of Parzen Estimators (TPE)***がhyperoptというハイパーパラメータ最適化用のライブラリで実装されている****(Python)
114
* Contal et al. (2013) “Parallel Gaussian Process Optimization with Upper Confidence
Bound and Pure Exploration”
http://arxiv.org/abs/1304.5350
** Emile Contal - Homepage
http://econtal.perso.math.cnrs.fr/software/
*** Bergstra et al. (2011) “Algorithms for Hyper-Parameter Optimization”
http://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf
**** Hyperopt by hyperopt
http://hyperopt.github.io/hyperopt/
ハイパーパラメータサーチ
パラメータサーチしない <<<< グリッドサーチ<<< Randomized Grid < (GP-UCBとかTPEとか)
という感じなのでTPEをツールとして使うのでいいかなーと思っている
115
hyperopt
git cloneしてsetup.py installだけだと動かないpip install networkxが必要
MongoDBが必要と書いてあるが、単一プロセスで使う上では必要でない
116
実験
scipy.optimize.fmin(downhill simplex)と比較
目的関数を3次元
sin(x) + cos(y) + sin(0.123 + 0.456 * z)
+ 0.1 * ((x - 1) ** 2 + (y - 2) ** 2 + (z - 3) ** 2)
scipyは(-10, -10, -10)から探索開始hyperoptは(-10, 10)を各変数の値の範囲と指定
117
結果118
←DS
↑TPE
num trial
func value
疑問
-10と10の中点0はわりと正解に近い位置scipyを(0, 0, 0)から探索開始したらどうなる?
119
結果120
↑DS (0,0,0)スタート
さらに疑問
では逆に答えが(-9,-8,-7)のあたりの場合は?目的関数を3次元
sin(x) + cos(y) + sin(0.123 + 0.456 * z)
+ 0.1 * ((x + 9) ** 2 + (y + 8) ** 2 + (z + 7) ** 2)
121
結果122
↓local minimum に引っかかった
↑近くから探索を始めれば成果は出る
↓答えの場所によらず似たような成果
まとめ
hyperoptのTree of Parzen Estimatorsとscipyのdownhill simplexとを比較すると
・TPEは答えの位置によらず似たような成果・DSは初期値が正解から離れていたり運悪くLocal Minimumに引っかかったりするとTPEに比べてひどい結果になる
TPEの方が時間はかかるけど現実的スケール試行あたりの時間コストが高い最適化にはTPEを使うのがいいんじゃないかな
123
t-SNE
sklearnに実装がある。Manifold learningについての解説ページもある。見た目的にはt-SNEは確かにきれいだが、軸に深い意味はないので後段にDTやKNNなどの空間を分割するタイプの分類機を伴わないとイマイチじゃなかろうか。
2~3次元用とのことなので「新しいデータはとりあえずt-SNEで2次元にして眺めてみる→
きれいなら特徴量にも使う」がよいかも。
124
sklearn.manifold.TSNE — scikit-learn 0.16.1 documentation
http://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html
2.2. Manifold learning — scikit-learn 0.16.1 documentation
http://scikit-learn.org/stable/modules/manifold.html
t-SNE
fitなしのtransformメソッドがない学習データでfitしてテストデータをtransform
することはどうすればできるのだろうか?*
61878*93のデータ→MemoryError
10分の1に削った(StratifiedKFold)→遅い
100分の1に削った
125
* こっちを使うべき? http://lvdmaaten.github.io/tsne/
結果126
まとめ、振り返り、次回に向けて
RFには無用だからとスケール調整を無視して、その後SVMとかやるときにも忘れたままだった。
データの解説は一字一句しっかり読む。
sklearnのGBDTが遅くて使うことをあきらめたがとりあえずXGBoostを一晩走らせるべき。
スパースなのでSVMの代わりにFMという案。次元削減の目的にはPCAの代わりにmanifold系を使う案。Isomapとか。今度試す。
127
まとめ、振り返り、次回に向けて
アンサンブラは今ので悪くないがISTする。余裕があればLRをNNに変えてhyperopt。
単体ではPoorな性能でもアンサンブルで化けるかもしれないので捨てない。
Boosted Neural Netsなど、うまくできないものだけを取り出して学習するアプローチ。
距離、TopN、max、min、などの特徴量の追加。
128
まとめのまとめ
Lasagne、XGBoost、hyperopt
129
top related