まだタイトルない

アウトプット用です

【Kaggle挑戦記】AI4Code振り返り【#15】

こんにちは

先日終了したkaggleのAI4Codeに参加してました。

やったことのないタスクだったためアプローチなどを知るために参加しました。少しでも自分のアイデアを使ったサブができたら良かったのですがローカルでスコアの再現が全く取れなかったりだらけきってしまったことにより、公開ノートのサブをする程度で終わってしまいました。

今回は自分が見た範囲のアプローチをメモとして残して、コンペ中うまくいかなかった部分を最後にちょこっとかきます。

コンペ内容

  • kaggle notebookに公開されてるノートのセルの正しい並び順を予測する
    • 正しい順序に並んでるCodeセルのどの位置にmarkdownセルが入るかを予測する

このように24個セルあるノートのデータは21個のcodeセルが上に順序どおり並んでおり、markdownセルは順不同で下に3つ並んでいるデータになります。trainデータは順序が与えられているためこのようにrankを付与できる。

アプローチ

1.GBDTのrankモデル

www.kaggle.com

  • hostsがチュートリアルとして公開してくれたもの
  • TF-IDFでベクトル化してXGBRankerで学習する

2.BERTモデルで回帰タスクとして解く(markdownデータのみ)

www.kaggle.com

  • rankを[0:1]で正規化して回帰として解く
  • markdownの情報だけで学習

このテキストは全体のうちどのくらいの位置にあるかを予測します。問題を既に知ってる別の問題に置き換えて?学習するアプローチの仕方で私はこの方法が好きです。

3.BERTモデルで回帰タスクとして解く2(code情報も使用)

github.com

  • 多分本コンペでの神カーネルはこれ
  • 上のモデルはmarkdown情報だけを用いてるためcodeセルの情報も使えば精度が上がることは明らか
  • ここのカーネルではcodeの情報を部分的に使用してモデルに入力している
    • [SEP] Markdown content [SEP] Code content 1 [SEP] Code content 2 [SEP] ... [SEP] Code content 20 [SEP]
  • 0.7534から0.84くらいまでスコアが上がる
    • 0.7534は少量データで1エポック、0.84は全データで3epochなのでちょっと条件は違う

4.Pairwiseでどこのコードに隣接してるか学習する

www.kaggle.com

  • 入力データは[CLS] + markdown + [SEP] + code + [SEP]
  • ラベルはmarkdownとcodeが隣接していれば1,してなければ0として学習する
  • 推論時間は長くかかる
  • 0.8171くらい

以上がコンペ期間中に私が確認したアプローチです。まだpublic上位の解放を確認してないのでこれから勉強しようと思います。

うまくいかなかった話

ローカルでスコアが出なかった

今回、2や3をローカルでpytorch lightningのコードとして実装し直して実験しましたが、2は0.65程度、3も0.635程度しかスコア出ず、公開ノートの再現すら全くできない状態でした。

本コンペはcv/publicの相関は比較的とれており、この低スコアのCVはpublicも低くただ学習がうまくできてない状態です。学習率やスケジューリングの誤差でここまで悪化するようにも思えず結局最後まで何が原因かわかりませんでした。なにか心当たりがあればtwitterでこっそり教えてほしいです(涙

ハイブリッドモデルができなかった

3はmarkdownもcodeも同じモデルに入力しているのですが、別々のモデルを使えないかと考えました

図にするとこんな感じ

コードだとこんな感じ

class HybridModel(nn.Module):
    def __init__(self, cfg):
        super(HybridModel, self).__init__()
        self.cfg = cfg
        self.code_model_name = 'microsoft/codebert-base'
        self.mark_model_name = 'distilbert-base-uncased'
        self.code_config = AutoConfig.from_pretrained(self.code_model_name, output_hidden_states=True)
        self.mark_config = AutoConfig.from_pretrained(self.mark_model_name, output_hidden_states=True)
        self.code_model = AutoModel.from_pretrained(self.code_model_name, config=self.code_config)
        self.mark_model = AutoModel.from_pretrained(self.mark_model_name, config=self.mark_config)
        self.fc = nn.Linear(self.code_config.hidden_size + self.mark_config.hidden_size, 1)
    def forward(self, ids, mask):
        mark_ids = ids[:self.cfg.md_max_len]
        mark_mask = mask[:self.cfg.md_max_len]
        code_ids = ids[self.cfg.md_max_len:]
        code_mask = mask[self.cfg.md_max_len:]
        code_outputs = self.code_model(code_ids, code_mask)[0]
        mark_outputs = self.mark_model(mark_ids, mark_mask)[0]
        outputs = self.fc(torch.cat((code_outputs[:,0,:], mark_outputs[:,0,:]),1))
        return outputs

これは普通にインスタンスを作って1バッチぶんいれたら動くけど、lightningで動かそうとするとエラーが出て直せませんでした。

RuntimeError: CUDA error: device-side assert triggered

このあたりも残課題として調べていこうと思います;;