riow1983 / nbme-score-clinical-patient-notes

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

nbme-score-clinical-patient-notes

header
https://www.kaggle.com/c/nbme-score-clinical-patient-notes
どんなコンペ?:
開催期間:
timeline
結果





実験管理テーブル

https://wandb.ai/riow1983/NBME-Public?workspace=user-riow1983

commitSHA comment Local CV Public LB

Late Submissions

commitSHA comment Local CV Private LB Public LB

My Assets

[notebook命名規則]

  • kagglenb001{e,t,i}-hoge.ipynb: Kaggle platform上で新規作成されたKaggle notebook (kernel).
  • nb001{e,t,i}-hoge.ipynb: localで新規作成されたnotebook.
  • {e:EDA, t:train, i:inference}
  • kaggle platform上で新規作成され, localで編集を加えるnotebookはファイル名kagglenbをnbに変更し, 番号は変更しない.

Code

作成したnotebook等の説明

name url status comment
kagglenb000e-EDA.ipynb URL Done データ確認用notebook
kagglenb001t-token-classifier.ipynb URL 作成中 🤗transformersによるtoken-classification訓練


参考資料

Snipets

// Auto click for Colab
function ClickConnect(){
  console.log("Connnect Clicked - Start"); 
  document.querySelector("#top-toolbar > colab-connect-button").shadowRoot.querySelector("#connect").click();
  console.log("Connnect Clicked - End"); 
};
setInterval(ClickConnect, 60000)

$ watch -n 1 "nvidia-smi"

# PyTorch device
torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Kaggle or Colab
import sys
if 'kaggle_web_client' in sys.modules:
    # Do something
elif 'google.colab' in sys.modules:
    # Do something

# output dir for Kaggle or other
from pathlib import Path
KAGGLE_ENV = True if 'KAGGLE_URL_BASE' in set(os.environ.keys()) else False
INPUT_DIR = Path('../input/')

if KAGGLE_ENV:
    OUTPUT_DIR = Path('')
else:
    !mkdir nb001
    OUTPUT_DIR = Path('./nb001/')

# hoge_path = OUTPUT_DIR / 'hoge.csv'

# pandas

>>> df = pd.DataFrame({"A":["a1", "a2", "a3"], "B":["b1", "b2", "b3"]})
>>> df
    A   B
0  a1  b1
1  a2  b2
2  a3  b3
>>> predictions = [[0, 1],[1,2],[2,3]]
>>> predictions
[[0, 1], [1, 2], [2, 3]]
>>> df[[0,1]] = predictions
>>> df
    A   B  0  1
0  a1  b1  0  1
1  a2  b2  1  2
2  a3  b3  2  3

# Push to LINE

import requests

def send_line_notification(message):
    import json
    f = open("../../line.json", "r")
    json_data = json.load(f)
    line_token = json_data["kagglePush"]
    endpoint = 'https://notify-api.line.me/api/notify'
    message = "\n{}".format(message)
    payload = {'message': message}
    headers = {'Authorization': 'Bearer {}'.format(line_token)}
    requests.post(endpoint, data=payload, headers=headers)

if CFG.wandb:
    send_line_notification(f"Training of {CFG.wandbgroup} has been done. See {run.url}")
else:
    send_line_notification(f"Training of {CFG.wandbgroup} has been done.")

# Seed everything
def seed_everything(seed=42):
    random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.backends.cudnn.deterministic = True
    
seed_everything(seed=42)

>>> import sys
>>> print(sys.argv)
['demo.py', 'one', 'two', 'three']

# reference: https://docs.python.org/ja/3.8/tutorial/stdlib.html

# JupyterのIOPub data rate exceeded エラー回避方法
!jupyter notebook --generate-config -y
!echo 'c.NotebookApp.iopub_data_rate_limit = 10000000' >> /root/.jupyter/jupyter_notebook_config.py

# PyTorchのバージョンを1.10.1に下げる方法 (Google Colabなのでpipでやる)
os.system('pip uninstall -y torch torchvision torchaudio')
os.system('pip install torch==1.10.1+cu111 torchvision==0.11.2+cu111 torchaudio==0.10.1 -f https://download.pytorch.org/whl/torch_stable.html')

# argparse example (reference: https://www.kaggle.com/code/currypurin/nbme-mlm/notebook)

%%writefile mlm.py

import argparse

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--model_name", type=str, default="", required=False)
    parser.add_argument("--model_path", type=str, default="../input/deberta-v3-large/deberta-v3-large/", required=False)
    parser.add_argument("--seed", type=int, default=0, required=False)
    parser.add_argument('--debug', action='store_true', required=False)
    parser.add_argument('--exp_num', type=str, required=True)
    parser.add_argument("--param_freeze", action='store_true', required=False)
    parser.add_argument("--num_train_epochs", type=int, default=5, required=False)
    parser.add_argument("--batch_size", type=int, default=8, required=False)
    parser.add_argument("--lr", type=float, default=2e-5, required=False)
    parser.add_argument("--gradient_accumulation_steps", type=int, default=1, required=False)
    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()

# !python mlm.py --debug --exp_num 0

Papers

name url status comment
Learning to select pseudo labels: a semi-supervised method for named entity recognition URL アブストのみ読了 PLによるNER訓練の論文らしいがPDFが落とせない
DeBERTa: Decoding-enhanced BERT with Disentangled Attention URL Keep -
Don’t Stop Pretraining: Adapt Language Models to Domains and Tasks URL Reading task-specific dataでもMLM訓練をすると良いらしい

Blogs (Medium / Qiita / Others)

name url status comment
CIFAR-10を疑似ラベル(Pseudo-Label)を使った半教師あり学習で分類する URL 読了 PLの使い所がよく分かる. 実装がKerasなのが玉に瑕.
(snorkel) Snorkel — A Weak Supervision System URL 読了 NLPアノテーションツールsnorkelの紹介
(snorkel) Snorkel and The Dawn of Weakly Supervised Machine Learning URL Keep NLPアノテーションツールsnorkelの紹介
(Python) Python map() function URL Done map関数の使い方
(typing) 実践!!Python型入門(Type Hints) URL Done typingの使い方
(PyTorch) 小ネタ:Pytorch で Automatic Mixed Precision (AMP) の ON/OFF をするときの話 URL Done torch.cuda.ampのON/OFF実装小ワザ
(PyTorch) [GPUを簡単に高速化・省メモリ化] NVIDIAのapex.ampがPyTorchに統合されたようです URL Done apexってNVIDIAのAMP機能のことだったのね
(LINE) 【kaggle入門】処理が終わった時にLINE通知する方法 URL Done requestsで簡単実装
(Bash) Bash For Loop Examples URL Done Bashによるfor loopの書き方
(Kaggle) Kaggleコード遺産 URL Keep Kaggleに使えそうなレガシーコード群
(W&B) 【入門】wandbの使い方(Google Colab+PyTorch) URL Done 一見分かりやすいが, 公式のColab Notebookを見たほうが良い
(W&B) Weights & Biases の使い方 URL URL Done
(Jupyter) Jupyter Notebook で IOPub data rate exceeded エラー URL Done jupyter_notebook_config.pyを編集すれば対処可能
(Prodigy) Supervised learning is great — it's data collection that's broken URL Keep Prodidyを検索している途上で出会ったInesの記事. 主旨がよく分からないが捨てられず.
A Gentle Introduction to Self-Training and Semi-Supervised Learning URL Keep PLの手順の基礎が確認できる
(PyTorch) pytorch 0.4の変更点 URL Keep 2018年4月の大改訂.
特にTensorとVariableの統合は備忘録として
【ミニバッチ学習と学習率】低バッチサイズから始めよ URL Keep 特に根拠が書いてある訳ではないが参考まで
(Python) クラス継承でobjectクラスを継承する理由 URL Keep 継承クラスが無い場合はobjectと書くか, 何も書かない.
(PyTorch) torch.sigmoid URL Done Returns a new tensor with the sigmoid of the elements of input.
(数学) ヤコビアンの定義・意味・例題(2重積分の極座標変換・変数変換)【微積分】 URL Done 今更ながらヤコビ行列とヤコビアン(ヤコビ行列式)の意味について
図解もあり非常に分かりやすい解説
(REINFORCE) ゼロから始める深層強化学習(NLP2018講演資料)/ Introduction of Deep Reinforcement Learning URL Keep Meta PLの論文にREINFORCE Algorithmが出てきたので, 見てみたら見事に撃沈

Documentation (incl. Tutorial)

name url status comment
(spaCy) Training Pipelines & Models URL Keep spaCyによるfine-tune方法
(snorkel) Programmatically Build Training Data URL Keep NLPアノテーションツールのsnorkelによるLF(ラベル関数)の多数決システムを使った自動アノテーション方式の説明.
PLでは無い.
(skweak) skweak URL Keep snorkelと同じくLF(ラベル関数)を使った弱学習フレームワークを提案するライブラリ.
spaCyと統合されているが使えるのか不明.
(:hugs:) DeBERTa URL Keep 🤗DeBERTaの解説
(:hugs:) Summary of the tasks URL Done pipeline及びAutoModelFor{task name}によるinferenceのexample.
しかしAutoModel+fine-tuningのexampleは無い.
(:hugs:) Auto Classes URL Done AutoConfig, AutoModel, AutoTokenizerがあれば他に何もいらない
(W&B) Launch Experiments with wandb.init URL Keep W&Bを使った実験管理についての公式ドキュメント
(W&B) wandb.init URL Done wandb.initに渡せる引数一覧
Trobe URL Keep Trove is a research framework for building weakly supervised (bio)medical NER classifiers without hand-labeled training data.
(PyTorch) INSTALLING PREVIOUS VERSIONS OF PYTORCH URL Done Google Colabの場合はpip管理
(pandas) pandas.testing.assert_frame_equal URL Done dfが同等かテストするメソッド

BBC (StackOverflow / StackExchange / Quora / Reddit / Others)

name url status comment
Annotation tools: Prodigy, Doccano, (or others)? URL 読了 NLPアノテーションツールの優劣について(本コンペでアノテーションツールは使わないが)
Difference between IOB and IOB2 format? URL 読了 知っていたIOBはIOB2だった
(pandas) How to apply a function to two columns of Pandas dataframe URL Done pandasで2列以上に同時に関数を適用させる方法
(Python) What does "''\r" do in Python? URL Done キャリッジ・リターンについて
(Colab) Just got Colab Pro, how can I ensure that processes remain running after closing the notebook? URL Done Colab Pro+でbackground executionが実行されていることを確認するには
(Python) Get number of workers from process Pool in python multiprocessing module URL Done Google Colab Pro+のnum of workersは8だった
(Bash) How can I display the contents of a text file on the command line? URL Done less filenameでJupyter上でもファイルの中身を全て表示できる
(Bash) Bash: Write to File URL Done echo 'this is a line' >> file.txtで良い
(PyTorch) Pytorch 0.2.1をバージョンダウンする方法 URL Done URLからインストールする際のリンク先等は公式ドキュメントの旧バージョンページに従うこと

GitHub

name url status comment
(skweak) skweak: Weak supervision for NLP URL Keep snorkelと同じくLF(ラベル関数)を使った弱学習フレームワークを提案するライブラリ.
spaCyと統合されているが使えるのか不明.
(:hugs:) huggingface/transformers URL Keep タスクごとのデータ構造を知りたくなったらここ
SentencePiece URL Keep "SentencePiece is an unsupervised text tokenizer"の一言が全て.
(:hugs:) debert TypeError: _softmax_backward_data(): argument 'input_dtype' (position 4) must be torch.dtype, not Tensor #16587 URL Done Google ColabのPyTorchのバージョンが1.10から1.11に上がったことに起因する:hugs:transformersのエラー.
nbroad1881によるPRにより解消されたものの,
🤗transformersをinputフォルダに入れて利用しているnb001tにとってはPyTorchのバージョンを1.10に下げるほか方法がなかった.
Feedback_1st URL Keep feedback prize コンペの1位解法 github repo
antmachineintelligenceは杭州にあるAlibaba系Ant groupのAIチームと思われ.
multi-task GDBの実装およびペーパーを出している点にも注目したい.

Hugging Face Platform

name url status comment

Colab Notebook

name url status comment
(W&B) Simple_PyTorch_Integration URL Keep PyTorchの訓練にW&Bを組み込む公式実装例

Kaggle (Notebooks)

name url status comment
QA/NER hybrid train 🚆 [NBME] URL Reading 🤗transformersによるQA/NERタスク訓練 (token classification task).
ただしAutoModelによるbody + リニアヘッドによるtoken classificationであり, AutoModelForTokenClassificationによるものでは無い.
PLの言及がある. 詳細は2022-02-15.
多様な言語モデルを扱えるように実装がモジュール化されておりその分可読性が犠牲になっている.
NBME / Deberta-base baseline [train] URL Keep 🤗transformersによるtoken classification task.
ただしAutoModelによるbody + リニアヘッドによるtoken classificationであり, AutoModelForTokenClassificationによるものでは無い点が面白い.
NBME / Deberta-base baseline [inference] URL Keep NBME / Deberta-base baseline [train]の推論版
NBME / pip wheels URL Done 🤗transformersとtokenizersの特定バージョンのwhlファイル
YoloV5 Pseudo Labeling URL Done PL実装の参考例の一つとして
feedback-nn-train URL Keep feedback prize コンペの1位解法notebookで, AWPの実装の参考例
その他coding全般が美しく参考になる
(MLM) [Coleridge] BERT - Masked Dataset Modeling URL Done 1st teamが参考にしたColeridgeコンペに出現したMLM訓練の実装
(MLM) NBME MLM URL Done 1st teamのMLM訓練の実装
🤗 Trainerで完結している

Kaggle (Datasets)

name url status comment

Kaggle (Discussion)

name url status comment
1st solution with code(cv:0.748 lb:0.742) URL Keep feedback prize コンペの1位解法
NBME コンペにも多大な影響を与えていた


Diary

2022-02-05

コンペ参加. kagglenb000e-EDA.ipynbにてデータ確認着手.


2022-02-08

kagglenb000e-EDA.ipynbにて関連テーブルを結合したtrainデータを外部出力しスプレッドシートで一つずつ確認する作業に着手.


2022-02-09

annotationが空欄[]になる理由について. 大半はpn_historyにfeature_textに沿った記述が無いため空欄[]になっているようだが,
中にはpn_historyにfeature_textに沿った記述があるにも関わらず, annotationが空欄[]になるケースもあるようだ.
e.g.,
文書ID=02425_000

# pn_history

17 yo CC palpitation 
-Started 3 months ago, , has experienced 5-7 episodes wich last 3-4 minutes, sudden onsent, no precipitations factor, no alleviating or aggravating factor 
-Do not has any visual disturbances, sweating. has has episodes during rest and exertion. has been progressively worsened. 
-Last episode associated SOB no chet pain 
-No changes in bowel movement, no heat intolerance, no skipped meals, no fever. No mood changes, no weigth loss
-Good relationship with friends, good school grades. 
-ROS: Negative except above
PMH: None 
AllergiesNKDA-NKA
Meds: Nones
FH: Mother hx of thyroid disease, Father IM at 52 
SH: College student, live with roomates, no tobacco, drinks socially,  One use of marijuana and stopped. Sexually active 1partner last yr, +Condoms. Exercises regualrly Healthy diet
# feature_text

Family-history-of-MI-OR-Family-history-of-myocardial-infarction
# annotation

[]

いや, これはもしかすると"Father IM at 52"が"Father MI at 52"であればannotationは空欄にならなかったかも知れないな. (IMはMIのtypoだと思うが, 試験としてはバツだろう.)
とするとやはり, 記述が無いから空欄になり, 記述があれば空欄にならない, ということでいいかも知れない.

ところで各case_numの行数について

case_num=0: 1300 rows




2022-02-10

pn_history内の表記によっては, 複数のfeature_textに分類され得る.
e.g., pn_historyn内の'1 day'という表記は, feature_textの'Duration-x-1-day'にも'1-day-duration-OR-2-days-duration'にも分類されている.
以下kagglenb000e-EDA.ipynbより

# [DEFICIENCY_RATE, {FEATURE_TEX: np.array of ANNOTATIONs}]

       [0.08,
        {'Duration-x-1-day': array(['1 DAY', '1 day', '1 day h/o', '1 day history', '1 day of',
               '1-days hitory', 'Began yesterday', 'FOR LAST 1 DAY',
               'Onset was yesterday', 'SINCE YESTERDAY', 'STARTED A DAY AGO',
               'Started yesterday', 'X 1 DAY', 'YESTERDAY', 'Yesterday',
               'began yesreday', 'began yesterday', 'for 1 day', 'for 1d',
               'for 24 hours', 'for one day', 'for the last 1 day', 'one day',
               'one day history', 'one day of', 'onset yesterday',
               'report this morning with pain', 'since yesterday',
               'since yeterday', 'started yesterday', 'starting 1 day ago',
               'staryed yesterday', 'when he woke up yesterday',
               'woke up with yesterday', 'woke up yesterday morning with pain',
               'woke up yesterday with this pain', 'woke up yeswterday with pain',
               'x 1 DAY', 'x 1 day', 'yeasterday', 'yesterday', 'yeterday'],
              dtype='<U35')}                                                                   ],
       [0.09,
        {'1-day-duration-OR-2-days-duration': array(['1 day', '1 day ago', '1 day duration', '1 day in duration', '1d',
               '1d duration', '1day', '2 day', '2 days', '2 days duration',
               'YESTERDAY', 'one day', 'one day Hx', 'past day',
               'started 1 day ago', 'stated in the morning when she woke up',
               'two day', 'x1 day', 'yesterday'], dtype='<U38')}                                                       ],

当てはまりそうな手法: IOB2スキームのNERタスクのpsuedo-labeling学習
というのもpatient_notes.csvにはtrain.csvに現れていないpn_historyが41146個(patient_notes.csvに収載されているpn_historyの総数は42146個)もあり, これらにはannotation (教師ラベル)が付与されていない. 従って, pseuedo-labelingが有効だと思われる.
タスクとしてはIOB2スキームのNER. ただしentity種類数は普通にやるとfeature_textの数(=917)となるが, これはやや数が多すぎる気がする. case_numごとにタスクを独立させる場合は1 case_numごとにentity種類数は平均して9-10程度になるので丁度良いか. これは, testデータにもcase_numは存在しており, testに未知のcase_numが現れることもないと保障されている(cf. 下記引用)ため, case_numごとにNERモデルを作る, というのは理に適っているように思える.

To help you author submission code, we include a few example instances selected from the training set. When your submitted notebook is scored, this example data will be replaced by the actual test data. The patient notes in the test set will be added to the patient_notes.csv file. These patient notes are from the same clinical cases as the patient notes in the training set. There are approximately 2000 patient notes in the test set.

The patient notes in the test set will be added to the patient_notes.csv file.

scoring時にhidden testデータのpn_historyがpatient_notes.csvに追加されるというのはどういうことか. 現時点で除去されているのはリーク防止のためだとすぐに分かるが, なぜわざわざscoring時に追加する必要があるのか?
これは推論時もpatient_notes.csvを学習プールとしてpseudo-labelingしつつモデルをアップデートできるようにする配慮なのだろうか? いや, hidden testの正解ラベルも一緒に供給されない限りは推論時pseudo-labelingは機能しないだろうから, そういうことでも無いか.


2022-02-15

NERタスクのPL学習の例が公開notebookにあった. ただしパフォーマンスが改悪したとして現在は除去された模様. これはPLの不安定さによるものである可能性が高く, うまくやれば改善すると思われる. (autherによる情報操作の可能性もある.)



2022-02-17

本コンペの工程を念頭に置きつつ, 現時点の自分のスキルレベル(データを見て独自解法の考案まではできるが, そこからシームレスに独自解法に沿った実装に直ちに着手できるほどの実装力/知力/意欲はまだまだ乏しいレベル)にfitしたKaggle工程表なるものを考えた:

  • 最初期フェーズ(全工程の16%): 自分なりのEDA, notebook以外の媒体でデータを見る, 独自解法の考案
  • 初期フェーズ(全工程の16%): 公開notebookの内, 優良なものを2,3精読 + 関連ライブラリの公式ドキュメント精読
  • 中期フェーズ(全工程の33%): 独自解法に沿った実装着手
  • 後期フェーズ(全工程の33%): submit, 実験, チューニング, アンサンブル

例えば3ヶ月あるコンペでは, 最初期フェーズに2W, 初期フェーズに2W, 中期フェーズに4W, 後期フェーズに4W, をそれぞれ充てる.

本コンペで言うと, 実際に最初期フェーズに対応する作業に2W使用し, 独自解法の考案までには至った. 今日から2月一杯は初期フェーズとして2,3選別した公開notebookを精読 + 関連ライブラリの公式ドキュメントを精読していく. これにより独自解法の実装に必要な実装力/知力/意欲を養う. 独自解法に沿った実装に着手するのは3月に入ってからとする.



2022-02-22

QAタスクの場合, tokenizerのtext(first sentence)にquestionを, text_pair(second sentence)にcontextを配置する.

        tokenized_examples = tokenizer(
            examples[question_column_name if pad_on_right else context_column_name],
            examples[context_column_name if pad_on_right else question_column_name],
            truncation="only_second" if pad_on_right else "only_first",
            max_length=max_seq_length,
            stride=args.doc_stride,
            return_overflowing_tokens=True,
            return_offsets_mapping=True,
            padding="max_length" if args.pad_to_max_length else False,
        )

https://github.com/huggingface/transformers/blob/0187c6f0ad6c0e76c8206edeb72b94ff036df4ff/examples/pytorch/question-answering/run_qa_no_trainer.py#L397-L406

一方, 参照中のNBME / Deberta-base baseline [train]では, tokenizerのtext(first sentence)にpn_historyを, text_pair(second sentence)にfeature_textを配置している.
https://www.kaggle.com/yasufuminakama/nbme-deberta-base-baseline-train?scriptVersionId=87264998&cellId=26

なぜか? 逆では無いのか?
恐らく, first sentenceに照合文たるpn_historyを配置しても何ら差し支えなく, どちらでも良いということだと思う. 面白い.
それどころか, それによりlabelにはpn_historyのみ供給すれば良く, locationがsecond sentenceの長さでoffsetされることが無いため, むしろ照合文はfirst sentenceに配置するほうが便利ですらあるのかも知れない.



2022-02-24

各feature_textについて, 複数のcase_numで同一feature_textが出現する頻度というのはどのくらいだろうか?
もしcase_numごとでfeature_textが全く共有されていないのであれば, case_numごとのモデルを作る意義はあるかも知れないが, かなり共有されているようであればむしろcase_numで分けずに一つのモデルを作る方が理に適っていると思われる.
exact matchではほとんど共有されていない.
それでも, catastrophy forgettingのこともあるので, case_numごとにモデルを作るというのは擬似ラベル学習をするならばやってみる価値はあるように思われる.

ところで自分で作ったEDA notebookはDiaryと同じく毎日見た方が良い. そうしないと忘れる.

Pseudo-labelingのアルゴリズムについて:
Step 1) case_numごとにモデル(弱学習器)を作り, pn_notes(unlabeld data)のcase_numごとに弱学習器で擬似ラベルを付与.
Step 2) 擬似ラベルが付与されたpn_notesをtrainに縦結合し, 擬似ラベルと通常ラベルを一緒に通常の学習(case_numごとではなく統一モデルの訓練)を開始.



2022-02-25

各case_numだけで訓練したモデルの当該case_numだけの評価はCVで以下の通り:

Score of case_num 0: 0.8497251859036535
Score of case_num 1: 0.8358820832321925
Score of case_num 2: 0.7897973324094926
Score of case_num 3: 0.8632173283033953
Score of case_num 4: 0.8268399541297892
Score of case_num 5: 0.7618812753214727
Score of case_num 6: 0.8425865038359166
Score of case_num 7: 0.7858024485438837
Score of case_num 8: 0.8301636199295346
Score of case_num 9: 0.8522291598203529

これに対して, 統一訓練モデルの, 各case_numごとの評価がCVでどうなっているのかについては以下の通り:
# trained on & evaluated by case_num all
========== CV ==========
Score of case_num 0: 0.8677
Score of case_num 1: 0.8708
Score of case_num 2: 0.8197
Score of case_num 3: 0.8936
Score of case_num 4: 0.8862
Score of case_num 5: 0.7970
Score of case_num 6: 0.8873
Score of case_num 7: 0.8433
Score of case_num 8: 0.8846
Score of case_num 9: 0.8934

これを見ると, 総じて統一訓練モデルの方が精度が高いようだ.
git commit SHAとwandbの連動については自動で行われることが分かった. wandb.run直前のgit SHAがwandb run pageに拾われるので, パラメータをfixさせたら実験を実行する前に必ずgit pushしておくこと.



2022-03-21

  • (1) ./src/001t_token_classifier.pyにてcase_num-allで訓練した弱学習器を使い,
  • (2)./notebooks/nb002i-token-classifier.ipynbでpatient_notesに擬似ラベルを付与し,
  • (3)その擬似ラベル付きpatient_notesをtrainに縦結合させてcase_num-allで(1)とは無関係に訓練したモデルを使い (なお, 1 epoch 240分ほどかかったため, fold 1以降は, 2 epochsまでとした.),
  • (4)kagglenb003i-token-classifier.ipynbで推論した結果をsubmitしたところPublic LB scoreが0.866だった.

擬似ラベルを使わない通常訓練ではPublic LB scoreは0.861なので, 擬似ラベル訓練をすると+0.005改善するようだ. なお, CVは各fold平均して0.88-0.89と更に高精度. (対して通常訓練のCVは概ね0.85未満だった.)

現在公開されているノートブックでbest scoreは0.882なので, これを擬似ラベル訓練に変更すれば0.887となり, 現時点で銀圏になる.



2022-03-29

DeBERTa Large V3を使うベストスコア公開ノートブックDeberta-v3-large baseline - DeepShare(LB: 0.883)を真似て./notebooks/001t-token-classifier.ipynbを改良, PL訓練では無い通常訓練でLB 0.882達成. これをベースにPL訓練版をsubmitしてみたい.



2022-03-30

PL学習手順整理:

  • [1] (Local) ./notebooks/001t-token-classifier.ipynbにてcase-num-allで通常訓練 (モデル名: model.pth)
  • [2] (Local) ./notebooks/002i-token-classifier.ipynbにてmodel.pthを使ったinference, 擬似ラベルデータ作成
  • [3] (Local) ./notebooks/001t-train-classifier.ipynbにてcase-num-allでPL訓練 (モデル名: model_pl.pth)
  • [4] (Local) ./notebooks/001t-train-classifier/をKaggle Datasetにアップロード
  • [5] (Kaggle Platform) kagglenb003i-token-classifier.ipynbにてmodel_pl.pthを使ったinference, submission.csv作成, submit



2022-04-09

予告通り, LB: 0.882を達成したdeberta-v3-largeのPL訓練版をsubmitした結果, LB: 0.885となり, 銅圏最後尾(97位)につけた. CVは0.9を超えていたので, trust CVならshake upを望めるが, どうするか.



2022-04-10

永らくPLに関する情報はコンペ内で大々的に共有されていなかったが, ここに来てディスカッションなどでPLの利点・難点について議論されるようになってきた模様.
こちらのディスカッション Pseudo labels make cv/lb uncorrelated? では, PLを普通にやるとCVがLBに比して優秀(>0.9)なのはPLによるリークが起きているに違いないという論点が共有されており, 過去コンペでそのようなリークを防ぐため, PLデータをfoldごとに作っておき, foldごとにconcatenateして訓練する方法が提案されていた. 1st place solution with code

We could expect a lot of very similar questions/answers in SO&SE data, so we clearly couldn’t rely on that sort of pseudolabels. In order to fix the problem, we generated 5 different sets of pseudolabels where for each train/val split we used only those models that were trained using only the current train set. This gave much less accurate pseudolabels, but eliminated any possible source of target leakage.

従って私もこの方法に従って実装を変更することにした.
なお, 図にすると以下のような流れになると思われ:
pl_fold


2022-04-27

ようやくリーク防止型のPL訓練が5 fold分完了した. なお, 4月26日に最後の5fold目を訓練する際, debertに起因するエラー TypeError: \_softmax_backward_data(): argument 'input_dtype' (position 4) must be torch.dtype, not Tensor に遭遇. 4fold目まではこんなことはなかったのに変だと思っていたら, どうやらGoogle ColabのPyTorchのバージョンが1.10から1.11に上がったことで, 🤗transformers側のバージョンチェッカーが反応していたらしい. その不具合はこちらで報告され, PRがなされfixした. しかし我がnb001tは訳あって:hugs:transformersをinputフォルダからインストールしているので, fixは反映されない. PyTorchのバージョンを1.10に下げることでエラー解消でき無事5fold目の訓練も完了した.
submitした結果, LB=0.887となり, リーク防止前の0.885と比べて0.002改善した.


2022-05-03

結果は277/1471だった.
private lb image

どのように取り組み, 何を反省しているか
今回のコンペはコンペ開始直後から参加することができ, 与えられた期間は3ヶ月だった. そのため期間を4フェーズに分け, 最初期フェーズではEDAをしつつ独自解法の考案, 次の初期フェーズでは公開notebookのうち気に入ったものを2,3精読する, 中期フェーズでは独自解放の実装, 後期フェーズで実験, と計画的に取り組めたが, 最後の実験フェーズで計算リソースの限界からか後述する気力減退に陥ってしまった. また考案した独自解法は1個では不十分で, 10種類くらい着想していく必要があり, 全て実装して結果を確認するだけのスピードも求められると感じた.

tokenizer(text, feature_text)について
textにpn_history (受験者が擬似患者に問診し記述したテキスト), feature_text に当該擬似患者の真の特性 (病歴情報) が入る. 一方, labelはspan ((start_position, end_position)) であり, text[span]がfeature_textに意味的に合致すれば正解となる.
Datasetを介して, textとfeature_textをinputs で受け, labelはそのままlabelで受け, modelに入力する. modelのoutputはtokenごとのlast_hidden_stateを元にした確率値のような値である. この値をlabelと同一の構造((start_position, end_position))に変換する処理はモデルの外で行い, lossは変換後の予測labelと真のlabelをBCEで計算し, 誤差逆伝播でtokenごとのlast_hidden_stateが最適化されるように仕向けている. QAタスクとして見るというのはナンセンスだった.
(参照: https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.PreTrainedTokenizer.__call__) tokenizerはデフォルトでtext(第1文)とtext_pair(第2文)の2つのtextを入力できる.

modelのoutputから予測label獲得までの処理について

# ====================================================
# Model
# ====================================================
class CustomModel(nn.Module):

    ... (省略) ...

    def feature(self, inputs):
        outputs = self.model(**inputs)
        last_hidden_states = outputs[0]
        return last_hidden_states

    def forward(self, inputs):
        feature = self.feature(inputs)
        output = self.fc(self.fc_dropout(feature))
        return output

last_hidden_states: (n_rows, seq_len, hidden_size)
(参照: https://huggingface.co/docs/transformers/main_classes/output#transformers.modeling_outputs.BaseModelOutput)
self.fcはhidden_size -> 1 とする線形写像なので, hidden_sizeは1となる.
次に, 0-1間に収めて確率のように扱えるよう, output.sigmoid()をvalid_fn (or inference_fn)の中で行い,
次に, valid_fn (or inference_fn)の外側(= train loop内)で output.reshape((n_rows, seq_len))とする.
reshape
これにより, 1インスタンス(1 text)ごとにtokenごとの"feature_text該当部分たり得る確率"が得られ, これをget_char_probs -> get_resultsの順に処理していくことで, 予測spanに変換している. lossはこの予測spanと真のspanの比較をすることで計算される.
get functions

リーク防止PL学習およびその他不首尾について
My submissions:
my submissions
自分で発想し実装したリーク防止PL学習の結果も, Private LBが通常のPLより悪くなっており, Public LBにオーバーフィットしていただけのようだったのは残念.
また大幅なshake down(138位下落)となったのも痛かった.
計算リソースはGoogle Colab Pro+を使用したものの, PL学習では1 foldにかかる時間が12時間と長く, 試行錯誤を繰り返す気力が萎えてしまった. これ以上の課金をしないという前提での解決策としてはPL学習に使う未ラベルデータをランダムサンプリングして減らすか, Deep Speedなどのメモリ効率化系ライブラリの実装に取り組むか, 辺りだと思う.


Back to Top

About


Languages

Language:Jupyter Notebook 95.8%Language:Python 4.2%