🐈

kaggle NBME解法まとめ

2022/05/09に公開

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)では以下の流れで行っていた

    1. 特定の臨床例を話すように訓練した人と対話し、メモを書く
    2. 訓練を受けた医者の採点者が、各症例の重要な概念(features)の注釈を使用し、書かれたメモについて採点する
    3. メモに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位

概要

  • MLM→Pseudo Labelingで学習
  • 学習時にAWPとaugmentを使用
  • 学習データはStratifiedGroupKFold(n=10)のうちの5foldsと全データの6つ
    • 時間制限によるもの

詳細

Datasets

  • Pseudo Labeling
    • 元データ10%, Pseudo Labeling90%
      • 予測値のしきい値ではなく、ランダムにサンプリングした方がCVが良かった
    • softラベル
      • hardラベルよりも経験的に優れている

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
    • CVの改善は僅かだが、Pseudo LabelingのEnsembleに使える
    • PBを確認したところ、効果的だった

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の区切りを作成してしまう
    • これに対応した後処理の関数を作成した
  • \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も試したが、性能が悪かったので使用しなかった
  • 様々な正規化を加えた
    1. classification headに5つのレベルのDropoutを入れた
    2. 全てのhidden stateをDropout + 線形結合して使用した
    3. アノテーション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を採用した
      1. 標準的なPseudo Labeling
      2. Weak Supervision: Contrastive-Regularized Self-Training Approach
      3. Meta Pseudo Labeling(MPL): Notebooks
    • HardとSoft双方のLabelを使用し、多様性を確保した
  • 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を区別することができるようになると思った

Not Worked

  • 予測区間のWBF, NMS
    • 単純な確率の重み付けが最も効果的だった
  • 予測閾値の調整
    • 全てのfeaturesに対して0.5を使用した
  • ほぼ全ての後処理の試行

参考にした他の解法

メモ書き

自分の解法

順位

  • 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は学習コストが高く採用できなかった

学習方法

  1. 通常の学習(base: Epoch = 10, large: Epoch = 5 apex=False)
    • 使用したモデルはLoss基準とMetric基準で両方試し、Metric基準の方が良かったので採用
    • Epochを伸ばすと性能が良くなったので、通常よりEpochを伸ばした
      • MLMの代わりにここでタスクドメインを学習していたものと思われる
  2. 訓練データでラベル付けがされていない6万個ほどのデータに対し1. のモデルをEnsembleし、Hard Pseudo Labeling
    • ここでリークしたため、以降のCVを正しく計算できなくなった
    • 提出前1週間の間にLeakを修正しようと再度計算したが、Leak修正前よりもスコアが下がった
      • 理由はおそらくモデルの多様性の低下が、Leak修正による影響を上回ったため
        • Leak修正前はValidation時のSeed値をモデルごとにずらしていた
        • Leak修正後はValidation時のSeed値をモデル毎に統一した
  3. 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"
  • CANINE
    • トークン化が失敗している例があったので、文字単位でのトークン化が効く可能性があると考えた
    • Roberta-baseよりCVスコアが低かったため採用せず

感想

  • MLMはCommonLitで効かなかった + BiomedNLPあたりが効かなかったので捨てていたが、良くなかった
    • 解法見るにMLMだけでLB0.890前後まで行っていたようなので、おそらくここが上位との差の一つ
    • ドメイン領域での事前学習と特定データでの事前学習の効きは別個
  • Pseudo Labelingにも改善の余地があった
    • Leakさせていた
      • 途中で気づいて修正したが、時間がかかった
    • Softを試したり、確信度が高いものは省いたり/単純にサンプリングしたりといったことを試す余地があった
  • 大きく間違えているサンプルばかり見ていたため、後処理で改善できる小さく間違えているサンプルを見落とした
  • 途中からColab Pro+を使用したが、記事通りA100はV100より3倍程度早く、非常に快適だった
    • ハイメモリ(メモリ 50GB)設定だと全く出なかったので、コードを整理して通常(メモリ 12GB)設定で動くようメモリ使用量を抑えた
    • V100を2つ回すよりA100を1つ回す方が早いので、A100が出なければセッションを起動せずにコードを書くなどしていた

興味深かった話題

Discussion