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の歴史

さすがに全部は追えないので、集められるものだけ集めました。歴史なので?ソリューションについては述べません。

全てはここから始まった

 なぜかコンペが終わっていないのに打ち上げ(お通夜)が企画される。

CV0.8超えられない人たちの集まりだったはずが、Maxwell氏がCV0.8を超えてしまったため、「CV: 0.800超えてしまったMaxwell氏にチームマージをお願いする会」に変更される。

 最終的にonodera、takuoko、Maxwell、pocket、akiyama、RK、amaotone、nejumi、 sugawarya、irekoの8人が結集した。

chouseisan.com

打ち上げからikiri_DS誕生前夜

 Maxwell氏がゴールド圏に上陸

ikiri_DS誕生

 ikiri_DSがここに誕生する。

 

 チームメンバー同士で抜きつ抜かれつ、LBを駆け上がるikiri_DSチーム

ここでtosh氏が合流。

このあたりで1stのスコアが急上昇する。

 ここでTam氏が合流

 そしてtakuoko氏がゴールド圏に……

 LB:0.809 circlecircleを超える

ikiri_DSチーム、circlecircleを超える

 そして2位に……

Giba & takuokoさんチーム合流、最終週に突入

Giba氏合流! 

takuoko+Angus+Brandenのtakuokoさんチームもマージし、ラストスパート。

 そしてcirclecircleとbestfittingがマージし、阿鼻叫喚が発生する。

https://www.kaggle.com/c/home-credit-default-risk/discussion/64222

ついに最終日

そして……

更に闘う者達

ホストがあの巨大なパイプラインを動かそうとして……?

モデル検証が完遂するか不安に駆られるチームメンバーだったが

 完遂! これにてHomeCredit終了!

Appendix

ikiri_DSチームに関する記事をまとめておきました。

www.acroquest.co.jp

取締役大越を含むチームがKaggleのコンペティションで2位に入賞 | 株式会社キスモ

japan.zdnet.com

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で学習させたあと、Cross Pseudo-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ではないですね……。

敗因

僕の用意したモデルはpublic LB 0.85強 ~ 0.86程度の性能だったのですが、終盤3日くらいで上位陣がsingle 0.87 ~ 0.88の性能のモデルを使っていることがわかったので、単体の性能で負けました。完全に見込みが甘かったとしかいえないです。

また、締め切り一週間前にトップがpublic LB 0.86のモデルを3つdiscussionに投下してきたのですが、そのコードが手元で再現できなかったのも痛いです。今回、discussionで上げられていた一次元CNNのモデルは手元で全く再現できませんでした。

最後の一週間くらい、一次元CNNのほうが二次元CNNより性能が悪かったので、そっちの性能向上に注力したのですが、うまくいかなくて諦めたのですが、二次元CNNのほうが性能向上は簡単だったので、これも誤算だったとしかいえません。

細かいところだと、

上位陣のsolution

基本的にたくさんモデルを作ってensembleするのが主流でした。

  • 1位

    raw wave・melspectrogram・MFCCの三種類のモデル(single public LB 0.86)をpseudo-labelingしてensembleというオーソドックスな手法でした。ただし、他のチームメンバーはsingle LB 0.88程度の強いモデルを持っていたみたいです。

  • 2位

    log-mel filterbankを使った特徴量でCNNでした。この方はsingleでprivate 90.9%の精度を出すというすごいことをやっていました。wavを20~50のchunkに切り出しstandizationする、VLTPを使う、というaugmentationが大変有効だったそうです。

  • 3位

    pseudo-labelingに加えて、pseudo-labelだけでまず学習させてその重みを初期値としてtraining dataでfine-tuningするという手法を使っていました。ねじゅみさんのメモにもある手法ですね。

  • 4位

    stacking。silenceに関しては、confidence scoreの低いものでpowerが小さいものをtest dataから取ってきたみたいですね。

  • mixup(7位)

    ベータ関数からサンプリングした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のテクニックについて簡潔にまとまっている素晴らしいメモです。

  • iwiwi氏のstatefarmコンペのスライド

    人物でvalidationを分けるなど、今回のコンペで類似するところが多々ありました。ただ各々のテストデータが似通っているわけではなかったので、test dataに対するunsupervisedは行いませんでした。

  • kaggler-jaのログ

装備

GTX 1080とTesla K80(コンペで配られたGCPの500ドルクレジットを使いました)

終わりに

今回はいろいろ見込みが甘かったので、次はもっと上位に行きたいです。