🐈
kaggle NBME解法まとめ
2022/MBME 解法まとめ
概要
お題
目的
- 患者を診療する際にメモ書きする技術の習得と評価
今回の課題
- 試験の注釈にある臨床概念と、メモにある表現を対応付ける手法の開発
- 「食欲不振」→「食事量が少ない」「服がゆるい」
具体例
- 実際の形式だが文章は異なる(実際の文章はRule AcceptしてDataタブから見られる)
- 医療メモ: 20yo male with nauseous and abdominal pain since this morning, ate raw oysters yesterday...
- features: Nausea
- label: ["nauseous", "abdominal pain"]
必要性
現状の手法とその課題
-
実際にあった試験(USMLE)では以下の流れで行っていた
- 特定の臨床例を話すように訓練した人と対話し、メモを書く
- 訓練を受けた医者の採点者が、各症例の重要な概念(features)の注釈を使用し、書かれたメモについて採点する
- メモにfeaturesが多く見られるほどスコアが高くなる
-
訓練した専門家が多く必要で人的・経済的なリソースがかかる
-
NLPアプローチが試されたが、以下が課題として挙げられる
- 同じ現象に対して異なる表現があること
- 複数の文章(段落?)にまたがる概念があること
- 表現が曖昧な場合があること
コンペティションについて
データ
特徴量
- 患者メモ
- ケースID(大まかな患者ID)、患者ID、テキスト
- 試験の注釈にある臨床概念(features)
- ID、テキスト
ターゲット
- featuresに関連する患者メモの区間
付随情報
- ラベル付けされたデータが14300個あったのに対し、ラベル付けされていないデータが約60000個あった
予測方法 / 評価指標
- micro-averaged F1
制約
- 9h
- (x)large系のモデルを30個ほど入れられた
- 予測時にデータをToken長でソートして高速化するとbase x 32個 + large x 32個まで入った
全体的な解法
Datasets
- Soft Pseudo Labeling
- knowledge distillation
- foldを切ってスコアを検証し、Ensembleの段階で全データで学習
Model
-
deberta系統
- v3-large、v2-(x)large, large
- robertaより強かった
- 医療系のPretrained ModelであるBioBert, BioMegatronは性能が悪かったため使われず
-
Auxilliary Target
- ラベル区間、区間の開始位置、区間の終了位置の3種類の学習
- Pseudo Labelingを行いデータを増やした上でのfeatures IDの分類
-
特殊なTokenの付与
- ケースIDを入力文章の先頭に加える
- 改行や医療の略語を特別なトークンで扱う
-
Multiple Dropout
Train
- MLM
- 1~3, 30Epoch
- Pseudo Labelingデータ+全データで学習
- (Smooth) Focal Loss
- Smooth: + Label Smoothing
- augment
- 文章のセンテンスを1つ削除
- 文章のTokenを[mask]にする
- Adversarial Training
Predict
- ケースIDごとのしきい値
- token・予測位置の後処理
- スペースの削除と改行文字の予測の削除
Other Tips
- 直近で終了した似たコンペティションの1位解法Feedback Prize 1st Place Notebookが頻繁に言及されていた
個別解法
1位
概要
- MLM→Pseudo Labelingで学習
- 学習時にAWPとaugmentを使用
- 学習データはStratifiedGroupKFold(n=10)のうちの5foldsと全データの6つ
- 時間制限によるもの
詳細
Datasets
- Pseudo Labeling
- 元データ10%, Pseudo Labeling90%
- 予測値のしきい値ではなく、ランダムにサンプリングした方がCVが良かった
- softラベル
- hardラベルよりも経験的に優れている
- 元データ10%, Pseudo Labeling90%
Model
- {deberta-large, deverta-v2-xlarge, deberta-v3-large} x 2の6つ
- 訓練時の設定は個々で異なる
Train
- MLMで最初に学習後、学習
- AWPを使用: コード
- augmentを使用
- p=0.2で、1つのセンテンスを文章から削除した
- CVはほぼ変わらなかったが、タスクとデータに効きそうだったので採用した
- Pseudo Labelingデータでは使用しなかった
- 一部のものはAuxiliary Targetを使用
- 以下の3つを使用
- channel_0: 通常のターゲット
- ラベル区間を1, それ以外を0
- channel_1: 開始位置を1, それ以外を0
- channel_2: 終了位置を1, それ以外を0
- channel_0: 通常のターゲット
- CVの改善は僅かだが、Pseudo LabelingのEnsembleに使える
- PBを確認したところ、効果的だった
- 以下の3つを使用
Predict
- 先頭と末尾の空白を削除した: 参考
Not Worked
- shuffle Augmentation
- label smoothing
- clip gradient normalization
2位
概要
- アノテーション・Tokenによるノイズ、過学習に対応した
- MLM→Pseudo Labelingで学習
- 学習時にaugment、モデルにNLP backbone + RNN + Auxiliary Targetを使用
- 学習データは検証時に4folds、最終的な予測時に全データを使用した
詳細
Datasets
- アノテーションノイズに注意した
- アノテーションに一貫性がなく、ノイジーだった
- 繰り返しのアノテーションを見逃す可能性が高かった
- 文章を小文字に統一した
- 大文字と小文字に意味的な違いがなかった
- 医学的な略語で最も一般的なもののみを前処理・統一した
- Pseudo Labelingを使用した
- Softラベル
- 2回目のPseudo Labelingは効かなかった
Model
- Tokenのspanによりアノテーションの境界付近で失敗するパターンに対応した
- 以下の3つのケースが殆んどだった
- スペースがないテキストの前にスペースがある
-
\r\n
がいくつかのテキストの前にある -
yom
,yof
(~歳の男性・女性の略語)のTokenの修正- yo/m, yo/fの区切りが正しいが、y/om, y/ofの区切りを作成してしまう
- これに対応した後処理の関数を作成した
- 以下の3つのケースが殆んどだった
-
\n
トークンの追加を試したが、CV・LBが改善しなかったため使用しなかった- A simple way to add a lf token for deberta v2/3
- 終了後に検証したが、上記トークンを使用するとLBスコアに大きなノイズが加わっていた
- 一部のモデルでMLMを行っていなかったことが理由かもしれない
- deberta-largeとdeberta-v3-largeを使用した
- deberta-v2-xlargeとroberta-largeも試したが、性能が悪かったので使用しなかった
- 様々な正規化を加えた
- classification headに5つのレベルのDropoutを入れた
- 全てのhidden stateをDropout + 線形結合して使用した
- アノテーションSpanの開始位置、終了位置を補助学習した
- classification headの前にRNNを入れた
- 前述の通り、アノテーションノイズが文章内の順序に依存しているため
- GRUとLSTMを使用したため、1つのbackboneモデルから2種類のモデルができる
Train
- Squadv2 dataset(コンペティションと同じQAタスク)でMLMを行った
- 3Epochのうち、下流のタスクで最も性能が良かったEpochの重みを使用した
- OptimizerはAdamW + custom scheduler like conine warmup
- 正規化のためにaugmentationを行った
-
pn_history
の文章のtokenの内、10%をmask tokenに置き換えた-
features
の置き換えはCVスコアが下がった- おそらく文章が非常に短く、完全にマスクされるパターンがあったため
-
-
- BCEよりfocal lossが優れていた
- 理由を考え、easyサンプルを重視する損失関数を作成した
- 4foldで訓練していたが、最終的に全データの4seedsで訓練した
- Ensemble時はFoldモデルで重み付けを探し、Seedモデルで同じ係数を使用した
3位
概要
- MLMによる事前学習
- ラベル箇所、開始位置、終了位置による学習
- 多様な訓練
- Meta Pseudo Labels
- Knowledge Distillation from Model Ensemble
- feature textに対応したメタ情報Tokenの追加: ["QA CASE=0"]
- Stochastic Weight Averaging (SWA)
詳細
Datasets
- アンサンブル時に、モデルの大半は全てのデータを使って学習した
Model
- deberta-large, deberta-xlarge, deberta-v2-xlarge, deberta-v3-large
- Token分類ヘッドは最終の12層の出力を全て連結して使用した
- ラベル箇所、開始位置、終了位置の3種類の学習を行った
- 最後の4~12のtransformer層を初期化した
Train
-
patient notesを使用したMLM (p=0.2)
-
Meta Peuso Labeling: paper
- 以下の3手法をためし、最も性能が良かったMPLを採用した
- 標準的なPseudo Labeling
- Weak Supervision: Contrastive-Regularized Self-Training Approach
- Meta Pseudo Labeling(MPL): Notebooks
- HardとSoft双方のLabelを使用し、多様性を確保した
- 以下の3手法をためし、最も性能が良かったMPLを採用した
-
Studentモデルの転移学習(MPL)
- MPLではPseudo Labelを用いたラベルなしデータのみでStudentモデルを学習する
- なので、実際の学習データで更に学習できる
- 学習の際はSWAを用いた
- 教師モデルと生徒モデル両方をメモリに載せる必要があったため、mixed precision, 8bit adam, batch size: 4, freezing lower layers & checkpointingなどを使用した
-
蒸留
-
2つのdeberta-largeをMPLを用いて学習したあと、教師モデルとして別のdeberta-largeモデルの蒸留に使った
-
蒸留時の損失は以下
- 0.15 * 実際のデータラベルでのBCE loss + 0.15 * Pseudo LabelデータのhardラベルでのBCE loss + 0.7 * Pseudo LabelデータのsoftラベルでのBCE loss
-
Can Students Outperform Teachers in Knowledge Distillation Based Model Comparison?
-
-
マーク用Tokenの追加
- ケースIDを文章の前にマーク用Tokenとして追加した
-
ケースごとに新しいトークンを10種類
- 例:
[QA CASE=0]
- 例:
-
異なるケースID同士の一部のfeaturesは非常に近いと思った
-
テキストにケース番号の情報を入れることで異なるfeaturesを区別することができるようになると思った
-
- ケースIDを文章の前にマーク用Tokenとして追加した
Not Worked
- 予測区間のWBF, NMS
- 単純な確率の重み付けが最も効果的だった
- 予測閾値の調整
- 全てのfeaturesに対して0.5を使用した
- ほぼ全ての後処理の試行
参考にした他の解法
- 4位:4th place solution: Deberta models & postprocess
- 5位:5th place solution
- 6位:6th place solution
- 7位:7th place solution: Get 0.892 in just 10 minutes
- 8位:8th place solution
- 9位:9th Weight search and threshold modification
メモ書き
自分の解法
順位
- LB 59位、PB 31位とかなりシェイクアップした
- おそらく以下の理由
- Roberta系統を混ぜていたので頑健だった
- Subが25個(+4個エラー)でLBに過学習していなかった
- おそらく以下の理由
データセット
- 元データセット + 元の訓練データでラベル付けがされていないデータへのHard Pseudo Labeling
モデル
- deberta-v3-{base, large}, Roberta-{base, large}の4つ
- 重みはCV順に0.2, 0.4, 0.1, 0.3として固定
- deberta-v2-xlargeは学習コストが高く採用できなかった
学習方法
- 通常の学習(base: Epoch = 10, large: Epoch = 5 apex=False)
- 使用したモデルはLoss基準とMetric基準で両方試し、Metric基準の方が良かったので採用
- Epochを伸ばすと性能が良くなったので、通常よりEpochを伸ばした
- MLMの代わりにここでタスクドメインを学習していたものと思われる
- 訓練データでラベル付けがされていない6万個ほどのデータに対し1. のモデルをEnsembleし、Hard Pseudo Labeling
- ここでリークしたため、以降のCVを正しく計算できなくなった
- 提出前1週間の間にLeakを修正しようと再度計算したが、Leak修正前よりもスコアが下がった
- 理由はおそらくモデルの多様性の低下が、Leak修正による影響を上回ったため
- Leak修正前はValidation時のSeed値をモデルごとにずらしていた
- Leak修正後はValidation時のSeed値をモデル毎に統一した
- 理由はおそらくモデルの多様性の低下が、Leak修正による影響を上回ったため
- Pseudo Labelingしたデータ + 元データで再度学習(Epoch =1, apex=False)
効かなかったこと
- Label smoothing
- ラベルノイズがあったので試したが、CVスコアが改善しなかった
- MSE Loss
- トークン単位で学習し、文字単位で評価するので、長い文字のトークンを間違えた場合に損失を大きくしたほうが良いと考えた
- ラベルを0/1からトークン長に変化させて学習(評価時はトークン長で割って標準化)したが、CVスコアが改善せず
- 例:文: "Dog/is/cute.", ラベル:
Dog
(例示のため空白はラベル付けしない)- BCE: "1 0 0"
- MSE: "3 0 0"
- 例:文: "Dog/is/cute.", ラベル:
- CANINE
- トークン化が失敗している例があったので、文字単位でのトークン化が効く可能性があると考えた
- Roberta-baseよりCVスコアが低かったため採用せず
感想
- MLMはCommonLitで効かなかった + BiomedNLPあたりが効かなかったので捨てていたが、良くなかった
- 解法見るにMLMだけでLB0.890前後まで行っていたようなので、おそらくここが上位との差の一つ
- ドメイン領域での事前学習と特定データでの事前学習の効きは別個
- Pseudo Labelingにも改善の余地があった
- Leakさせていた
- 途中で気づいて修正したが、時間がかかった
- Softを試したり、確信度が高いものは省いたり/単純にサンプリングしたりといったことを試す余地があった
- Leakさせていた
- 大きく間違えているサンプルばかり見ていたため、後処理で改善できる小さく間違えているサンプルを見落とした
- 途中からColab Pro+を使用したが、記事通りA100はV100より3倍程度早く、非常に快適だった
- ハイメモリ(メモリ 50GB)設定だと全く出なかったので、コードを整理して通常(メモリ 12GB)設定で動くようメモリ使用量を抑えた
- V100を2つ回すよりA100を1つ回す方が早いので、A100が出なければセッションを起動せずにコードを書くなどしていた
興味深かった話題
-
deberta-v2-xlargeの学習方法について
- 学習率は小さめ(~1e-5)にする
- 層ごとに学習率を変える
- Top Layerを初期化する
-
Pseudo Labelingを使用した際のCVの計算方法
- foldごとにOOF予測して使う
-
計算リソース不足について
- P100 16GB 30h/weekは足りない
- deberta-v3-largeを5fold学習できない
- P100 16GB 30h/weekは足りない
-
Incoming Feature: Paid User Plans?
- htmlのjsonにuserPlanという項目が追加されている
Discussion