まだタイトルない

アウトプット用です

【Kaggle】Ventilatorコンペ上位解法から学ぶ

f:id:teyoblog:20211205001615p:plain

こんにちは!

Lux AI何もわからなくて辛いてょです。まんまと見た目の可愛さに釣られました。

本記事はKaggle Advent Calendar 20215日目の記事です。タイトル通り先日終了したkaggleのGoogle Brain - Ventilator Pressure Predictionコンペの上位解法をまとめます。

内容は下記です

  • Brainコンペの上位解法をまとめる
  • 実際に動かしてみてコンペ期間の自分のベストモデルとの比較をする
  • やらないこと
    • PIDコントローラーの逆解析については今回は扱いません

1位

①simple LSTM(LB0.1209)

  • Task - regression
  • Model - 4層LSTM(input 9, hidden512)
    • SiLU
  • Features - u_in,u_out, time_step, RとCのOHEの計9個
    • 学習してるうちに派手な特徴量はいらないのではないかと気づいた
  • Optimizer - AdamW
    • lr: 2e-3 # or 3e-3
    • weight_decay: 0.1
  • Scheduler - ReduceLROnPleateau
    • patience : 30
    • factor : 0.6
    • min_lr : 1e-05
    • 500-600epochでearlystoppingで終了する
    • CosineAnnealingはoverfittingになりやすい
  • Loss - dual regression loss
  • batch_size: 512
  • Score
    • CV 0.1507
    • public 0.1503
    • private 0.1555

伸びすぎてコンペ中何してたんだろうという気分になりました

②LSTM CNN transformer

f:id:teyoblog:20211204233726p:plain 引用元:https://towardsdatascience.com/winning-the-kaggle-google-brain-ventilator-pressure-prediction-2d4c90d831ec

  • Task - regression
  • Model - LSTM CNN transformer
    • LSTM
      • 目標値が過去の時点大きく依存しているため必要
    • 1D conbolutions, transformers
      • グローバルな依存関係をモデル化するに適した組合せ
      • transformersがlocalな相互作用をとらえられないことを補っている
    • 層が深く、勾配の問題もあるため残差接続を追加
  • Features - 公開ノートで広く使われている基本的な特徴量のみ
    • originalデータに加えて、いくつかのラグや差分の特徴量、u_inの累積和、OHEされたR&Cの特徴を使用する
  • Optimizer - Ranger optimizer
  • Scheduler - CosineAnnealing 150epoch
    • 100epochくらいで下げきり、そこから一定のlr
  • Scaler - RobustScaler
  • batch size 128

2位

PIDコントローラーの解析

  • pulp-fiction(公開ノート)を7つ学習しbetter than medianでアンサンブルする
  • 生成PIDコントローラを決定し,可能な限り予測値を逆PIDコントローラの出力で置き換える
    • 4024000個の値のうち915437個を置き換えた

3位

  • Task - regression
  • validation - RCでStratified k-fold
    • そこまで有効ではなかった
  • Model - Conv1d + Stacked LSTM
    • オリジナル、カーネルサイズ2,3,4のConv1dを通したものをConcat(bs,L,4n)をLSTMに通す
    • LSTM(4N,1024,bidirectional=True,dropout=.1)
    • LSTM(1024*2, 512 bidirectional=True,dropout=.1)
    • LSTM(512*2, 256,bidirectional=True,dropout=.1)
    • LSTM(256*2, 128,bidirectional=True,dropout=.1)
    • FC
  • Features
    • オリジナル: u_in, u_out, R(one-hot), C(one-hot)
    • 追加特徴量: u_in_min, u_in_diff, inhaled_air, time_diff
    • inhaled_air???
    • u_inのcumsum はu_inが減少した時点での圧力の予測に支障が出ると考え使用をやめた
    • conv1dで特徴量を作るのでrollingの特徴量は使用しなかった
    • 初期圧力の予測が重要だと考える⇒初期圧力が異常に低いものがあった⇒u_inの最小値が非常に小さいことが判明⇒u_in_minという特徴量を作成
  • Optimizer - AdamW
  • Scheduler - Cosine
  • Data augmentation
    • R、Cをランダムにマスク
    • sequenceの順番をランダムにシャッフル
    • 2つのsequenceをmixup
      • RとCはonehot状態を*0.5して和をとった
      • LB0.117から0.1104になった
  • mixup(p=0.4)⇒shuffling(p=0.2)⇒masking(p=0.2)
  • Loss 2種類使用
    • pressureに対するMAE
    • Difference of pressure
      • sequence間のpressureのdiffもラベルとして学習した
      • LBが0.14x から 0.127xに向上
  • ensemble
    • Seedアンサンブル(median)
    • 1st Pseudo labeling(0.948)
    • 2nd Pseudo labeling(0.0942)
    • single model 0.1004
    • ensemble + post-processingで0.963

4th

  • 30%のデータは逆PIDコントローラーの値を使用

5th

  • Task - classification
  • seq長を80でなく40にした
    • u_out==0が最大でも35までだったため
  • Validation -
  • Model - transformers
    • encoder 20層
    • head 128
    • dropout(0.8)
    • multihead
  • Features
    • 基本的に公開ノートで広く使われているもので、アーキテクチャのほうが精度に貢献している
    • original特徴量とConv1dの特徴量を結合
    • 作成した特徴量をカーネルサイズ(2,3,5,7,11,15)のconv1Dで16chanにしてconcatすることで96次元の特徴量に変換
  • Optimizer - AdamW
  • Loss - Cross Entropy
  • 1000epoch
  • 15fold
  • 15seed

f:id:teyoblog:20211204233610p:plain

6th

  • Task - regression
  • Validation - 全データで学習 30seed
  • Model - nn.LSTM(input_dim, 512, batch_first=True, bidirectional=True, num_layers=4, dropout=0.1)
  • Features - raw_features, u_in_cumsum, u_in_log, [time_step, u_in, u_in_log]のdiff1-4
  • Optimizer - AdamW
    • lr - 3e-4
  • Scheduler - CosineAnnealingWarmRestarts(3restarts
  • Scaler -
  • Loss -
  • Batch size - 128
    • 大きいと性能が悪くなった
  • Score
  • 280epoch
  • 近隣学習とマルチタスク学習による性能向上
    • RとCでグループ
    • u_inのMAEでソート
    • trainセット内の上位5つの近傍breathからランダムで1つ選択
    • uin, uin_diff1-2, pressure, pressure_diff1-2, neighbour_uin-self_uinを特徴量に追加
    • TTAではtop5つそれぞれで予測し5つの推測値のアンサンブル
  • マルチターゲットで学習すると収束が早くなった
    • diff of pressure
    • diff2 of pressure
    • pressure - neighbour's pressure
    • classification label (950 classes)
  • pseudo-label

9th

  • ベースはnakama-sanの公開ノート
  • loss - likelihood loss
  • 10fold
  • 10seed
  • pseudo label
  • 誤差をラプラス分布と仮定したL1ノルムの最小化をした
  • sequence noごとに誤差の分散が異なると過程
    • modelからは予測値xと予測分散bを出力
    • スコアが0.01以上改善

10th

  • Task - regression
  • Model - 4層LSTM layers + Dense layers + Output Layer with skip connections
  • Features - 一番重要
    • 7つのMagic特徴量で0.017-0.018改善
      • R,C,整数に丸めたu_in,rankを結合したカテゴリを作成 (trainだけでunique 22422)
      • カテゴリのcount
      • カテゴリの基礎統計量(mean min max)
      • u_inと基礎統計量3種との差
    • seqを逆順にして学習
      • 正順で作られた特徴量も加える
      • seq80は1個目と80個目のu_inが特徴としてある状態
      • 正順LSTMよりも0.002ほど良い
    • 特徴は誤分類されるbreathの情報とそれを校正することを目的に考えた
  • 正順と逆順をアンサンブルして0.004のブーストがかかった
  • Score(public:0.1093,private 0.1133)

マジック特徴量の実装は公開ノート

11th

  • Task - regression と classification 両方
  • Pseudoラベルは有効だった
    • 実ラベルと擬似ラベル予測の層を分けたりすることも有効だった

Regression Part

  • Model
    • u_inとRCをConv1dを通してsignal hidden unitへ(このsignal hidden unit がよくわからない
    • signal hidden unit; time embedding(time stepから作成?) -> Transformer with Disentangled Self Attention -> LSTM
      • Disentangled Self Attentionの実装は、NLPのDeBERTa Modelを参考に位置の埋め込みを時間ステップの埋め込みに置き換えた
      • https://arxiv.org/abs/2006.03654
  • Optimizer - AdamP
    • lr 2e-4
  • Scheduler StepLR
    • Decay 0.95/5epoch
  • Loss - u_outの値ごとのマルチタスク
  • Score - 0.1160

Classification Part

  • Model - 4層 conformer
  • Optimizer - Ranger
    • lr 5e-3
  • Scheduler - CosineAnnealingLR
    • 最初の100エポック
    • そこからReduceLROnPlateau
  • Loss - BCE
    • u_out==1は学習しない
  • RCの組み合わせが異なると、挙動がかなり異なることを発見した
    • すべてのデータから一般的な学習をしたあと異なるRCに対してfine-tuneをした(0.002改善
  • Score - LB0.1167

Ensemble

  • 回帰と分類のモデルのアンサンブルで0.1112
  • 上記から得られるpseudo labelでモデルを再学習してensembleに加えて0.1074までboost

13th

Transformer(regression)

  • Model - skip connectionを使用したtransformer encoder を12層
  • Features - 特徴量は公開ノートのもの
  • Scheduler - cosine with restarts (+0.020
  • Target - pressure.diff()も予測してlossに使用(+0.015
  • Train - 全データで学習
  • https://www.kaggle.com/cdeotte/tensorflow-transformer-0-112
  • Score -CV:0.133,LB0.112

bidirectional LSTM(regression)

  • Model - 4層LSTM
  • Features 20個
    • u_inの対数
    • u_inのcumsumを200で割った値
    • time_step, u_in, log_u_inのdiff(1-4)
    • 詳細はdiscussion
  • Target - pressure, pressure.diff(), pressure.cumsum()を予測してMAE
  • Train - 全データで学習
  • Score - CV 0.135 LB 0.118

CNN-LSTM(classification)

  • Model - todaさんの公開ノートベース
    • LSTMの前にCNNを追加
  • lr - 2.5e-4
  • Scheduler - cosine
  • Loss - u_out=0だけで計算
  • Batch size - 32
  • Train - 全データで学習
  • 70epoch
  • Score - CV 0.145 LB 0.125

LSTM-GRU(regression

  • Model - Pulp Fictionベース
    • LSTMの前にCNN
  • Features - u_in, u_out, time_step,RとCのdummyの18個
  • lr - 2.5e-4
  • Scheduler - cosine
  • Batch size - 32
  • 70epoch
  • Score - CV 0.150 LB 0.127

Ensemble

  • 72モデルを最適化を用いて加重中央値を計算し、アンサンブル
    • CV 0.117 LB 0.116
  • 上記4種*32model+72の200モデルでアンサンブル
  • 200modelのアンサンブルから作られたpseudo labelを使ってCNN-LSTMで再学習
    • 全データ(trainもtest)で32seed分学習してLB 0.110
    • 20%のcutmix
    • Loss pressure, pressure.diff(), pressure.cumsum()
    • LSTMの前にCausalCNN blockを使用
      • time_stepから8つの新しい特徴量を作成するもの
      • 作られた8つの特徴量を他の特徴量と結合してLSTMに入力

14th

  • Features - 公開ノートを参考
    • u_inの対数(u_inオリジナルも使用)
  • Scaler - Robust Scale qunatile-range(10:90)
  • Target - pressure_diff(1個前と1個後)の追加で0.010改善した
  • Loss MAE
  • Model(keras)
    • 4層 bidirectional LSTM
    • CNNの追加
    • 活性化関数 最後はseluでなくlinear
      • seluは-1.75~の値をとり、圧力の差分を目的変数として使用するのに適していない
    • fold 10~16
    • Score - cv 0.134 public 0.1157
  • Model(pytorch)
    • 5層 bidirectional LSTM
    • マルチタスクにすることでkerasよりもスコアがよくなった
    • Scheduler - CosineAnnealingWarmupRestarts
    • Score - cv 0.135 public 0.1153
  • Ensemble
    • 15モデルの出力の中央値
    • CV 0.1117 / Public 0.1103 / Private 0.1107
  • Stacking
    • 15モデルの出力のスタッキング、および8つのスタッキングの中央値
    • CV 0.1134 / Public 0.1100 / Private 0.1111*
  • breath_idに対して最適なモデルを選択するモデルを作ったがまったくうまくいかなかった

まとめた感想

今回は金圏まででご勘弁...

本コンペで私は3090に乗るだけbatch_size上げてたのですが上位はほとんど共通してバッチサイズは小さい方がいいとなっていますね。なんででしょうか・・・? 特徴量に関してはガッツリと作り込む場合や、作りすぎると収束が早くなるので殆ど作らない、Conv1dに任せるなどが見られました。 CV戦略についてはデータがかなり多かったのでランダムでも十分LBとの相関が取れ詰めるポイントではなかったようです。(全データで学習してるチームも多くありました。 後は多くのモデルでアンサンブルも重要ではありそうでした。

自分で金圏のスコアを出したい

今まで復習すらあまりしてなかったのですが今回はソリューション(コード)を見ながら自分で金券を目指してみようと思います

まずはコンペ中のベストモデル

  • Model - 4層LSTM dual regression head
  • Features - ['Base','Area','U_in_cumsum_mean','U_in_Lag','RC_OHE','U_out_stat','U_in_Lag_Diff','U_in_Rolling','U_in_delta','Area_cumsum','U_in_stat','U_in_half_stat','U_in_first_last','U_in_diff_maxmean','FFT',]
  • Optimizer - RAdam
    • lr - 5e-3
    • weight_decay - 1e-5
  • Epochs - 300
  • Scheduler - CosineAnnealingLR
    • min_lr - 1e-5
  • Batch size - 1024
  • Scaling - RobustScaler -> StandardScaler
  • Score
    • CV 0.16745
    • public0.1708
    • private0.174

1位のSimpleLSTM

  • singleFold
    • CV 0.1507403004
    • public 0.1503
    • private 0.1555

じっくり学習するだけでここまでのビルとは思いませんでした

  • 15fold
    • CV 0.1450459443
    • public 0.1253
    • private 0.1282(38th相当)

1位のLSTM CNN transformer

  • singleFold
    • CV 0.1397898606
    • public 0.122
    • private 0.146
  • 15fold
    • CV 0.1417298052
    • public 0.1255
    • private 0.1285(41st相当)

上記2モデルのアンサンブル

  • public 0.1182
  • private 0.1212(25th相当)

十分強いですけどまだ銀色なのでもう少し他のモデルを作ります

10th

まずはアーキテクチャだけ真似してみます

  • CV 0.1360389739

十分強い

マジック特徴量使用

  • singleFold
    • CV 0.1235325308
    • public 0.1265
    • private 0.131
  • 15fold
    • CV 0.1290646463
    • public 0.1117
    • private 0.1159(19位相当)

強すぎた

結果

上記の1位のモデル2種と、10位のモデルを2種アンサンブルした結果金圏スコアを出すことができました!

f:id:teyoblog:20211204233627p:plain

f:id:teyoblog:20211204233635p:plain

無事ソリューションの復習と自分で金圏スコアを出すことに成功しました。めでたしめでたし。

使用コード

おわりに

今回アドベントカレンダーという機会を活用して参加したコンペをいつも以上にじっくり復習させていただきました。自分は学生の頃から復習が苦手で模試とかも受けっぱなしなタイプでしたし、kaggleでもコンペも終わったらダラダラしてしまうことが多かったのですが、やはり復習はすべきだなと再認できました。今回の復習は結構ダラダラ時間をかけすぎてしまったのでそこは課題として今後も復習はしっかりしていきたいと思います。