Kaggle APTOS 2019 Blindness Detection
もう終わってから三週間になりそうですが、いろいろ書き残しておきます。
20th / 2943 teamsでした。ソロ銀狙いで50位前後をふらふらしていたらPrivateでジャンプアップしてびっくりでした。
モデル
- Model A (public: 0.822, Private: 0.925)
- EfficientNet-b5
- 2015のデータ全て(train + test)使ってpretrainしたのち、2019のtrainでfine-tuning。ただしfine-tuning時にbodyの学習率はheadと比べて1/10に設定
- 320x320, Ben's Crop
- Flip, ShiftScaleRotate, RandomContrast, RandomBrightness, Cutout
- regression / MSE loss
- Model B (public: 0.794, Private: 0.918)
- EfficientNet-b5
- 2015のデータ全て(train + test)使ってpretrainしたのち、2019のtrainでfine-tuning
- 320x320, Ben's Crop
- Flip, ShiftScaleRotate, RandomContrast, RandomBrightness, Cutout
- soft label for ordinal regression / BCE loss
- Model C (Public: 0.817, Private: 0.924)
- EfficientNet-b5
- 2015のデータ全て(train + test)使ってpretrainしたのち、2019のtrainでfine-tuning
- 224x224, blank除去のみ
- Flip, ShiftScaleRotate, RandomContrast, Cutout
- regression / MSE loss
学習
- pretrain時はheadのみ10エポック→body+headを10エポック
- fine-tuning時はCosineLR(1e-3 ~ 1e-6、Tmax=32)で128エポック
- optimizerはAdam
- fine-tuning時に2019のtrainを5foldに分割しcv
推論
- TTA 5回
- モデル三種類×5fold×TTA5回で計75predictionを作成したのちweighted average
- Model Cのみ最初のfoldのseed averageがCVより良かったので、cv averageではなく最初のfoldのseed averageになっている。
- testはリサイズすればRAMに全部乗ることが分かったので、最初にリサイズすることで画像読み込みの時間を減らしました。結果としてpredictionをたくさん作れるようになりましたが、モデルが少なかったので時間が余ってしまいました。上位のようにもっとがんばって200predictionくらい作るべきでした……。
Model Cだけ過激なことをやっていました。ちなみにModel Bは今年のCVPRに採択された手法を使ってモデル多様性に貢献させようとしたのですが、なくても0.929出てましたね……。
敗因
pseudo labelingしなかった。なぜか禁止されてるものだと思い込んでました……。
余談
僕より強いひとからチームマージのお誘いが来たのがエモかったです。マージ期限過ぎていたのでマージしませんでしたが、今回のコンペで一番うれしかったです。
ikiri_DSの歴史
さすがに全部は追えないので、集められるものだけ集めました。歴史なので?ソリューションについては述べません。
全てはここから始まった
homecreditの打ち上げ既にしたい
— onodera (@0verfit) June 26, 2018
なぜかコンペが終わっていないのに打ち上げ(お通夜)が企画される。
https://t.co/BV3MQfGch8
— onodera (@0verfit) June 27, 2018
とりあえず作りました
homecreditお疲れ様でした会はお葬式の雰囲気でやります
— onodera (@0verfit) June 28, 2018
CV0.8超えられない人たちの集まりだったはずが、Maxwell氏がCV0.8を超えてしまったため、「CV: 0.800超えてしまったMaxwell氏にチームマージをお願いする会」に変更される。
手元 Local 0.800 超えているなんて言えない・・・
— HoxoMaxwell❄️ (@Maxwell_110) June 28, 2018
「CV: 0.800超えてしまったMaxwell氏にチームマージをお願いする会」になってるwww
— ireko8 (@_ireko8) June 28, 2018
最終的にonodera、takuoko、Maxwell、pocket、akiyama、RK、amaotone、nejumi、 sugawarya、irekoの8人が結集した。
team名考えるか pic.twitter.com/LsGElwYBOH
— onodera (@0verfit) June 28, 2018
Home Cteditマージお願いします会、某氏の「silver足りなくてマスターになれてないです」を発端に殴り合いが起きた時はどうなるかと思いましたが楽しかったです!
— onodera (@0verfit) July 3, 2018
俺が激ヤバ特徴見つけてみんなをmasterにしてやるからな…
— onodera (@0verfit) July 3, 2018
打ち上げからikiri_DS誕生前夜
ついに上陸。ですが、ここからですね。
— HoxoMaxwell❄️ (@Maxwell_110) July 25, 2018
まだまだ改善を続けていきます。 pic.twitter.com/n0vQEPzs0m
Maxwell氏がゴールド圏に上陸
ikiri_DS誕生
ONODERAXWELL爆誕 pic.twitter.com/CUGrdGYnfQ
— onodera (@0verfit) July 25, 2018
おや?ONODERAXWELLの様子が・・・ pic.twitter.com/3SV7fNlHGp
— RK (@ryuichi_74) July 25, 2018
ikiri_DSがここに誕生する。
RK氏が軽く爪を見せただけでこれなので、そろそろゲームバランス考えて接待プレイしないといけないかも pic.twitter.com/BhNKBMfD06
— onodera (@0verfit) July 27, 2018
コンペのためにgoogle driveに廃課金(¥250)したので崇められてる pic.twitter.com/SHzPyixA9Q
— onodera (@0verfit) July 28, 2018
public LB of Home Credit on 05.Aug.2018
— HoxoMaxwell❄️ (@Maxwell_110) August 5, 2018
public overfit している圏内者が多少いたとしても、まだまだ安全圏にはほど遠い状況。 pic.twitter.com/kGWTIKmLpA
チームメンバー同士で抜きつ抜かれつ、LBを駆け上がるikiri_DSチーム
どやぁ pic.twitter.com/qQ70bOLGWi
— RK (@ryuichi_74) August 5, 2018
そして、RKさんにまた抜かれるw
— HoxoMaxwell❄️ (@Maxwell_110) August 5, 2018
とはいえ、そろそろ fusion する季節がやってきています。 pic.twitter.com/dMMMabsztn
Whether boosting or bagging, I'm top 10 and #bragging. #kaggle https://t.co/k1OfroY8BD
— HoxoMaxwell❄️ (@Maxwell_110) August 8, 2018
そして、0.808 台へと。
ここでtosh氏が合流。
深夜のちょっとした改善。
— HoxoMaxwell❄️ (@Maxwell_110) August 8, 2018
そろそろ寝る・・・。 pic.twitter.com/JVgn8vaJ4T
コンペの最中にGCPの支払い明細を見た時 pic.twitter.com/qMTaHT0GtT
— ねじゅみ (@nejumi_dqx) August 10, 2018
このあたりで1stのスコアが急上昇する。
そこの 1st 暴走車、止まりなさい。
— HoxoMaxwell❄️ (@Maxwell_110) August 11, 2018
止まらないと、撃つぞ! pic.twitter.com/uJlOJ0U6DK
14.Aug.2018 Public LB of Home Credit
— HoxoMaxwell❄️ (@Maxwell_110) August 14, 2018
何もしていないけど、順位が元に戻りました。
Gold 圏内でも、巨大チームがどんどん生まれていますね。 pic.twitter.com/KouJlQ950M
昨日の敵は今日の友 pic.twitter.com/H3k9Khjibw
— onodera (@0verfit) August 14, 2018
ここでTam氏が合流
Like the SVM, I intend to maximize my (winning) margins. #kaggle https://t.co/k1OfroY8BD
— HoxoMaxwell❄️ (@Maxwell_110) August 15, 2018
0.809台へ。
そしてtakuoko氏がゴールド圏に……
ここからが本番ですね pic.twitter.com/mAxWgIdLb5
— takuoko (@takuoko1) August 15, 2018
もう待ち合わせ場所きてんじゃん pic.twitter.com/FI8pTCEY8a
— onodera (@0verfit) August 15, 2018
LB:0.809 circlecircleを超える
5 to go. pic.twitter.com/heQHEGst2T
— HoxoMaxwell❄️ (@Maxwell_110) August 15, 2018
ikiri_DSチーム、circlecircleを超える
circle circle…おめえはすげえよ よくがんばった…たったひとりで… pic.twitter.com/y2hylA6t92
— onodera (@0verfit) August 15, 2018
4 to go! pic.twitter.com/b8rxEU7HWS
— HoxoMaxwell❄️ (@Maxwell_110) August 17, 2018
みんな優秀なので褒めるくらいしか仕事がない pic.twitter.com/v9tfv35e3b
— onodera (@0verfit) August 17, 2018
もう少し! pic.twitter.com/1JP3Fn8fo4
— RK (@ryuichi_74) August 20, 2018
気になるのは、1st position のチームのスコアですね。
— HoxoMaxwell❄️ (@Maxwell_110) August 20, 2018
流石に、異次元のスコアな気がします。 pic.twitter.com/mbXrRhpPQ0
さて・・・ここからどうすれば・・・ pic.twitter.com/GFn3FrvaoV
— HoxoMaxwell❄️ (@Maxwell_110) August 21, 2018
そして2位に……
Home Creditはここで盟友達と合流してラストバトルです。1stのチームはどうも闇の衣的なものを纏っているのでそのままではダメージが通らなそうですね。光の玉で引き剝がさなければ!
— ねじゅみ (@nejumi_dqx) August 21, 2018
盛り上がってきた pic.twitter.com/yNqvAvoNAo
— onodera (@0verfit) August 21, 2018
Home credit、独走する1位に対して団結する2位。そして不穏な静けさを放つbestfitting氏。参加者は過去最高。これkaggleの最終回的な盛り上がりだ。
— u++ (@upura0) August 21, 2018
Giba & takuokoさんチーム合流、最終週に突入
All set, let's finish this competition! pic.twitter.com/hAdcIiOlrF
— onodera (@0verfit) August 22, 2018
Giba氏合流!
ここからは優勝に向けて少しでも貢献できたらなと思います!🥇 pic.twitter.com/ON6HKc0yaR
— takuoko (@takuoko1) August 21, 2018
takuoko+Angus+Brandenのtakuokoさんチームもマージし、ラストスパート。
元々は、@nejumi_dqx 氏達とほそぼそやっていたのですが、オフ会を経て、@0verfit 氏と @ryuichi_74 氏が加わり、Tam 氏が加わり、@takuoko1 チームが加わり、最後に Giba 氏が加わり・・・気づいたらとんでもない人数に。
— HoxoMaxwell❄️ (@Maxwell_110) August 23, 2018
これだけの人数で kaggle に参加することは今後ないかもしれないですね。
あと一週間ぐらいikiって勝ちに行く。
— Hiroki Yamamoto (@tereka114) August 23, 2018
そしてcirclecircleとbestfittingがマージし、阿鼻叫喚が発生する。
https://www.kaggle.com/c/home-credit-default-risk/discussion/64222
にじりよってくる circle circle
— HoxoMaxwell❄️ (@Maxwell_110) August 25, 2018
あと 3 日間、ちゃんとリードを保ち、かつ、private でもちゃんと上にいれるかどうか、確信がもてません( yowaki_DS ) pic.twitter.com/fEIMg4Uoo6
今この時こそ勝負所以外の何物でもない!全部燃やす!
— ねじゅみ (@nejumi_dqx) August 23, 2018
うおおおおお!頼む、神様!今なんだ!一生分の閃きを前借りさせてくれ!
— ねじゅみ (@nejumi_dqx) August 23, 2018
ついに最終日
home credit 勢 起きてますかー?
— HoxoMaxwell❄️ (@Maxwell_110) August 29, 2018
起きている人は retweet !
そして……
Overfit していなかったぞーーーー!!!! pic.twitter.com/PgXmHbECBv
— HoxoMaxwell❄️ (@Maxwell_110) August 30, 2018
泣ける pic.twitter.com/SywwR8bzvZ
— RK (@ryuichi_74) August 30, 2018
We got 2nd place in Home Credit Default Risk Competition at kaggle.
— HoxoMaxwell❄️ (@Maxwell_110) August 30, 2018
Thanks to team members and all participants !
It was very tough and exciting competition.
And finally I became Kaggle Master.
From now on I will keep on studying. pic.twitter.com/044dn5STFR
2位だあああ〜〜〜 pic.twitter.com/r5DJO1grMA
— takuoko (@takuoko1) August 30, 2018
HomeCredit 2nd!ニューラルネットワーク担当でした。周りが凄くて、足引っ張らないかひやひやしながらでしたがとても楽しかったです!次も頑張ります!
— Hiroki Yamamoto (@tereka114) August 30, 2018
また何人もエキスパート牧場から巣立っていくんだな...みんな元気でな...
— あきやま (@ak_iyama) August 30, 2018
更に闘う者達
ホストがあの巨大なパイプラインを動かそうとして……?
Home Credit 社が チーム ikiri_DS の script を本当に動かそうとしているかもしれないとの報告が・・・。
— HoxoMaxwell❄️ (@Maxwell_110) October 9, 2018
開けたな・・・パンドラの箱を!
あの箱実行しようとしているのか‥。いつ終わるんだろう
— Hiroki Yamamoto (@tereka114) October 12, 2018
そして、次に発火したのは私の山だった・・・。
— HoxoMaxwell❄️ (@Maxwell_110) October 17, 2018
Home Creditのホストによる再現は完遂の瞬間は最早感動ものですね。https://t.co/SFqxvRTU5bの最後にスタッフロール流すコードを追加で配置したくなってきました。
— ねじゅみ (@nejumi_dqx) October 17, 2018
一応、私の山の FE 岳⛰の木は、燃え尽きました。
— HoxoMaxwell❄️ (@Maxwell_110) October 19, 2018
また後で、MODEL岳とBLENDING岳が、不運にも燃え上がる予定です。
HC 担当者に、また燃やすからな、と暗に言われました。
え・・・まだモデル検証やるの!?
— HoxoMaxwell❄️ (@Maxwell_110) November 14, 2018
賞金をもらってから、また、Mt.Maxwell が噴火しました。
ikiri_DS チームの皆さんは、お小遣いに湧きかえっていますが、
— HoxoMaxwell❄️ (@Maxwell_110) November 14, 2018
一人残業の私は早く開放されたい気持ちで一杯です。
あと残ってるのは、私の他だと Giba ちゃんだけなんですが、
彼のタスクすぐ終わるからなぁ・・・。ずるい。
モデル検証が完遂するか不安に駆られるチームメンバーだったが
おお!
— HoxoMaxwell❄️ (@Maxwell_110) November 22, 2018
home credit の全スクリプトの検証が終わったみたいです!
解放された!
完遂! これにてHomeCredit終了!
Appendix
ikiri_DSチームに関する記事をまとめておきました。
DeNAのKagglerである小野寺和樹と加納龍一を含むチームが、過去最大のKaggleコンペである"Home Credit Default Risk"にて、7198チーム(参加者数8572名)中2位に入賞しました。今年4月からのKaggle社内ランク制度開始以来の、大きな成果となりました! (https://t.co/WkM2GOKwbc) pic.twitter.com/E1pEmuY6DU
— DeNA (@DeNAPR) August 30, 2018
Tensorflow Speech Recognition Competition 参加記
はじめまして。Maxwell氏の大学の後輩、Ireko8です。今回、tensorflow speech recognition competitionに参加して72位になり銅メダルを取得しました。Titanicをのぞけば初めてのKaggle competitionでしかもはじめて自分がまともにディープのモデルを使うコンペでした。
経緯
Maxwell氏の会社のもとでインターンをしていたとき、Google Speech APIなどを用いたSpeech to Textの簡単なシステムを作ったりしていたので、今回のコンペで音声認識の勉強になると思い参加しました。
コンペ概要
- タスク
約1秒の音声が指定された十種類のコマンド("on"や"left", "stop"など)+silence(音声が入っていない)+unknown(音声は入っているが指定されたコマンドではない)のどれにあたるかを分類します。
- Rasberry Piで実行できるモデルで一番精度のよかったものをつくるPrizeもあったのですが割愛します。
ルール
- External Dataは禁止。Pretrained Modelの使用も禁止。
データ
訓練データ
30種類程度の単語(分類対象のコマンドを含む)を録音した音声データおよそ6万件。ファイル名にはその音声を録音した人のidがついています。
- 同一の人物が発した音声は似通っているため、学習の際に訓練データと検証データの両方に同じ人物の発した音声が含まれているとleakになるので、データはidが重複しないように分割する必要があります。
訓練データにはsilenceと明確にラベリングされたデータはありません。silenceのデータは自分で生成する必要があります。ただし、訓練データを作成するときに用いられたバックグラウンドノイズ(ホワイトノイズなど)があり、External Data禁止なので基本的にこれを用いることになります。
- テストデータ 音声データ16万件弱。訓練データより多い上に、訓練データには含まれていない単語の音声(Unknown Unknowns)が存在します。
手法
- モデル スペクトログラムを入力とするVGG-likeな二次元CNNとwaveデータをそのまま入力とするVGG-likeな一次元CNNの二つを作りました。
- augmentation
リアルタイムに行ったaugmentationは、音声をフリップする(wavデータを-1倍する、波形の正負を反転する)のとノイズを付加する、ボリュームを変える、一秒ではない音声についてはランダムで切り出すor前後に無を追加の3つです。ピッチを半音の範囲でずらす、スピードを変えるといったaugmentationもofflineで行いました。librosaが重すぎて、ピッチシフトとスピードチェンジはリアルタイムにできませんでした。
- 音声フリップに関しては実は効果がなかったのでは、という疑いがあります。
- silence data 訓練データのバックグラウンドノイズから切り出したwavデータにランダムにボリュームを変えた20000件を用いました。いま考えると、バックグラウンドノイズを連結させたwavからEpochごとに必要なぶんだけ切り出したほうがよかった気がします。
- Pseudo-Labeling & Ensemble
5foldで学習させたあと、
CrossPseudo-Labelingを行い、入力データやaugmentationを変えたモデルをaveragingしました。- Pseudo-Labelingとはテストデータの予測ラベルのうち予測スコアが高いデータを訓練データに追加することでデータ数を増やす半教師あり学習です。このままですと自分自身の出力を訓練データに含めていることになるため、若干leakyになってしまいます。そこでまず独立に学習させた複数のモデルからテストデータの予測スコアを計算し、特定のモデルのpseudo-labelを作る際はそのモデル以外のモデルから計算された予測スコアをensembleした予測に基いてラベルを作ります。
これをCross Pseudo-Labelingと呼ぶそうです。たとえば5foldで独立に学習させたモデルがあった際、1fold目のモデルのためのpseudo-labelを作る際には2~5fold目のモデルの予測を用いる、といった具合です。詳細はiwiwi氏のstatefarm解説スライドを参照してください。修正(2018/2/1)statefarmの解説を読み直したら、自分の手法はCross Pseudo-Labelingではないですね……。
- Pseudo-Labelingとはテストデータの予測ラベルのうち予測スコアが高いデータを訓練データに追加することでデータ数を増やす半教師あり学習です。このままですと自分自身の出力を訓練データに含めていることになるため、若干leakyになってしまいます。そこでまず独立に学習させた複数のモデルからテストデータの予測スコアを計算し、特定のモデルのpseudo-labelを作る際はそのモデル以外のモデルから計算された予測スコアをensembleした予測に基いてラベルを作ります。
敗因
僕の用意したモデルはpublic LB 0.85強 ~ 0.86程度の性能だったのですが、終盤3日くらいで上位陣がsingle 0.87 ~ 0.88の性能のモデルを使っていることがわかったので、単体の性能で負けました。完全に見込みが甘かったとしかいえないです。
また、締め切り一週間前にトップがpublic LB 0.86のモデルを3つdiscussionに投下してきたのですが、そのコードが手元で再現できなかったのも痛いです。今回、discussionで上げられていた一次元CNNのモデルは手元で全く再現できませんでした。
最後の一週間くらい、一次元CNNのほうが二次元CNNより性能が悪かったので、そっちの性能向上に注力したのですが、うまくいかなくて諦めたのですが、二次元CNNのほうが性能向上は簡単だったので、これも誤算だったとしかいえません。
細かいところだと、
無音データの生成が足りなかった
テストデータに異常な数の無音が含まれていることには気づいていて、silenceデータ生成のときにも20件くらい無音を混ぜたのですが、もっとたくさん生成してもよかったと反省しています。ただ、結論からいうと、privateに含まれるsilenceやunknownの割合は10%弱で、このデータを大量に生成するとoverfitする可能性はあった気がします。(しかし、3%上がったと言っている方がいるので実際はわかりません)
ミスラベルを直さなかった
rightのデータがsilenceだった、などラベルミスがあるのは気づいてましたが手作業で取り除くのは負担が大きく、10~20%くらいミスラベルあってもokらしいので無視しました。しかし上位陣のソリューションではミスラベルを直すと精度が上がったらしいので、やるべきでした。
validationがとれなかった
訓練データに含まれていない単語がテストデータに含まれるというデータの性質上、正しくvalidationするのが困難でした。
shakeupに怯えすぎた
訓練データにはない音声がテストデータに入っている点、Public LBのラベルの分布とsubmitのラベルの分布が全く異なる点から、big shakeがあるのではとささやかれていました。一方でコンペのdescriptionにあるとおり、全てのデータがLBに用いられるわけではなく、さらにCVとLBに相関がとれていたので、そこまで心配する必要もないという気持ちがありました。蓋を開けてみれば、ほとんどのデータがダミーだったので杞憂だったわけで、minor shakeupで済みました。
Mel系の特徴量を使わなかった
MFCCなどの特徴量を上位陣は使っていました。MFCCへの変換が重すぎるので早々に見切ってしまったのは完全に誤りでした。
- ensembleのweightの決め方がわからなかった
上位陣のsolution
基本的にたくさんモデルを作ってensembleするのが主流でした。
-
raw wave・melspectrogram・MFCCの三種類のモデル(single public LB 0.86)をpseudo-labelingしてensembleというオーソドックスな手法でした。ただし、他のチームメンバーはsingle LB 0.88程度の強いモデルを持っていたみたいです。
-
log-mel filterbankを使った特徴量でCNNでした。この方はsingleでprivate 90.9%の精度を出すというすごいことをやっていました。wavを20~50のchunkに切り出しstandizationする、VLTPを使う、というaugmentationが大変有効だったそうです。
-
pseudo-labelingに加えて、pseudo-labelだけでまず学習させてその重みを初期値としてtraining dataでfine-tuningするという手法を使っていました。ねじゅみさんのメモにもある手法ですね。
-
stacking。silenceに関しては、confidence scoreの低いものでpowerが小さいものをtest dataから取ってきたみたいですね。
-
ベータ関数からサンプリングしたweightで二つのデータを混ぜるmixupが有効だったみたいです。このチームではシンプルにwavを混ぜていたみたいです。
使わなかった手法
RNN
16000Hzでサンプリングされた約1秒のデータということもあってRNNは使いませんでした。実際、上位陣の多くはCNNで畳み込んでいました。
silenceとそれ以外のclassifierを作る
テストデータの分布が訓練データの分布が異なりunknownやsilenceに偏っていたため、silenceやunknownに特化したclassifierとそれ以外のclassifierの二つを作る、というアイデアは考えてました。しかし、特定のlabelにoverfitするかも、と日和って採用しませんでした。今回一位のHeng氏も同様のアイデア(https://www.kaggle.com/c/tensorflow-speech-recognition-challenge/discussion/47083#latest-268685)を出していましたが実装はしていなかったみたいです。
test time augmentation
一位のHeng氏が使って(ピッチシフトなど)有効だったみたいです。
今回参考にしたサイト
-
Kaggleのテクニックについて簡潔にまとまっている素晴らしいメモです。
-
人物でvalidationを分けるなど、今回のコンペで類似するところが多々ありました。ただ各々のテストデータが似通っているわけではなかったので、test dataに対するunsupervisedは行いませんでした。
- kaggler-jaのログ
装備
GTX 1080とTesla K80(コンペで配られたGCPの500ドルクレジットを使いました)
終わりに
今回はいろいろ見込みが甘かったので、次はもっと上位に行きたいです。