CAFA 5 Protein Function Prediction 反省会(2023/09/01)


# はじめに
<!-- 発端や概要を記載 -->
[6/30](https://qiita.com/taichan003/items/e2ab1d4c70ff715faf05), [7/2](https://qiita.com/taichan003/items/ed365c6b2470d25a4a3f), [7/3](https://qiita.com/taichan003/items/39ff269e80752f9f0097), [7/10](https://qiita.com/taichan003/items/47fc81fd2bf6550f9037), [7/15](https://qiita.com/taichan003/items/f76b9d6c6da2a583e94c) のメモの続きです。
以下の kaggle コンペが終わったので反省中です。
コンペの概要は [6/30](https://qiita.com/taichan003/items/e2ab1d4c70ff715faf05) のメモに書いてあります。

https://www.kaggle.com/competitions/cafa-5-protein-function-prediction


# 結果
自力の最高スコアが 0.51481。
出発点の 0.47935 よりは上がったけど、大概の人が 0.55 くらいまでは自力でいけて、そこから 0.6 越えを目指していた中で全然ついていけなかった。
結局成績上位の人の公開ノートに自分の結果を蛇足のように付け加えただけで提出しちゃった。
そっちのスコアは 0.588 だけどわたしの力ではないし、最終結果ではだいぶ下がるのだろうと思う。


# 敗戦の弁
最初、データが理解できずに違うプログラムを参考にしようとして無意味に時間を費やした。プログラムをちゃんと読めば分かっただろうにと思う。
あとわたしは論文を読むのが下手。たぶん根性がない。

評価方法の確認が不十分だった。途中まで AUC スコアを伸ばそうと頑張っていたけど、F1 スコアが評価基準だった。これで 2, 3 週間無駄にしている。
せめて頻繁に提出するようにしていたら傷は浅かったはず。

仮提出の結果と最終の結果は違うから仮の結果は信じすぎずに自分で評価基準を作ろうという話はよく聞いていたけど、ほんとうにそうだった。
最終結果は 12 月まで開示されないからわからないけど、少なくとも上記のミスは自分で確認しておけば起きなかった。
結局手元で F1 スコアを確認できるようにはしたけど、評価基準は F1 スコアの重みづけの足し合わせなのでちょっと違うかも。
手元ではよくなったけど提出結果だと悪くなることがよくあったので、最後までこの部分の理解は甘かったと思う。

そもそも基本的なことだけど、ファイル整理のやり方がわからない。
1時間後には自分でも違いが判らなくなるような差分ファイルが大量にできる。
あとプログラムを複製して少し修正して計算しなおすとき、出力ファイルの名前の指定を変え忘れて上書きしちゃったり。
プログラムとモデルだけ保存してデータは消すのがいいのかな？でもモデル自体も結構なサイズになるよね。
今回は Google Drive にめっちゃ課金することで無理やり押し通した。

あとはもっと頻繁に code, discussion を覗くべきだった。
最初にがんばって読んだけど、途中から書いてあることが難しかったり自分のモデルをいじるほうが楽しかったりでないがしろになっていた。
最後のほうにわたしにもできるようなデータ処理の方法が提案されていたのに気づいたけど提出が間に合わなかった。
会社でもファイル整理できないとか掲示板見てないとかいつもやらかしてるから、当たり前の社会的能力の欠如が問題ってことだよね。つまんな:unamused:


# やったこと
自分のsubmission の順番に書くので、考えが右往左往してたりぐちゃぐちゃです。これも敗因のひとつなのかもしれない。

### DeepGOZero
最初に DeepGOZero のプログラムを真似しようと思った。これは前回の CAFA コンペをもとにしている。
https://github.com/bio-ontology-research-group/deepgozero

ただし、このプログラムは、InterProScan で得られたタンパク質配列の InterPro ドメイン注釈をもとにして GO term を予測したというもので、今回の FASTA 配列のみから予測しようという試みとずれていた。
いろいろ時間を使った割にとくに活用することなく終了。


### T5 embeddings
タンパク質を表す FASTA 形式をベクトル化して、各 GO term を持つ / 持たないを二値分類の機械学習で学習する。目的変数の次元は予測する GO term の次元だけあるから、GBDT ではなくて NN モデルを使った方がよさそう。
いろんな人が下のノートブックをもとにしていた。
https://www.kaggle.com/code/henriupton/proteinet-pytorch-ems2-t5-protbert-embeddings

このノート自体の点数は 0.47935。ここからしばらくこのベースラインが越えられない。


### DeepGOPlus
DeepGOZero のさらに前のコンペで作られた DeepGOPlus というモデルがあって、これは FASTA 形式を入力として GO term を予測する。
https://github.com/bio-ontology-research-group/deepgoplus

前に使った T5 embeddings とかは BERT を使った埋め込みだけど、こちらは配列の中に各アミノ酸が存在するかしないかの one-hot encoding によって行っているぽい。
それに加えて、教師データからアミノ酸配列の類似度(diamond) が高いものの GO term を取得して、それらを重ね合わせることによる推定と合わせて答えを出している。
これをコピペして算出したスコアが 0.35147。

今思うと結構シンプルな推定方法だし、点数が前より上がることはないのは当然だけど、前のノートコピペだけより苦労したのにーって思っちゃった。


### 教師データの制限
教師データは実験により確認されている Swiss-Prot データと、計算によって推定された TrEMBL データに分かれる。
計算による推定は手動によるアノテーションより大きく出る傾向があるので、Swiss-Prot データを教師データに制限して学習してみた。
正確には全部のデータで学習したあとに Swiss-Prot データに制限して再学習。
スコアは 0.40448、結局データ量が多い方がいいのかな。


### embeddings の方法
タンパク質のベクトル化について、前の T5 embeddings を使った人のノートの中で紹介されていた [ProtBERT](https://www.kaggle.com/datasets/henriupton/protbert-embeddings-for-cafa5), [EMS2](https://www.kaggle.com/datasets/viktorfairuschin/cafa-5-ems-2-embeddings-numpy) という別の埋め込み手法もある。
また、埋め込み後の機械学習についても MLP(2 layer), MLP(3 layer), CNN の 3 通りある。
これらをかけ合わせて 9 種類の予測を作り、これらを GBDT で組み合わせて最終的な予測を作った。
スコアは驚きの 0.22433。敗因は GBDT の評価指標を AUC にしていてコンペの評価基準である F1 が下がったこと。
多くの GO term はほとんど陰性で、データに偏りがあるためこのようなことが起きる。

ここら辺は頭がおかしくなっていて、自分のメモを見ると GBDT を LGBT って間違えている。ウケる:shamrock:


### 複数モデルの組み合わせ
これ以降は[公開ノートで成績のよかったもの](https://www.kaggle.com/datasets/siddhvr/blast-quick-sprof-zero-pred)を雑に結合している。基本的にはわたしの予測を優先し、わたしの考慮していない term についての予測を追加した。
公開ノートは [foldseek, blastp](https://www.kaggle.com/code/siddhvr/foldseek-blastp-ensemble), [quick-go](https://www.kaggle.com/datasets/mtinti/quick-go-2022-03-02), [SPROF-GO](https://www.kaggle.com/code/mtinti/sprof-predictions), [DeepGOZero](https://www.kaggle.com/datasets/liudacheldieva/submission-zero-predictions) を組み合わせたもの。なぜか予測値が 1 を超えるものがあるからそこだけ処理した。

まず前と同じ 9 種類の予測をもとに、F1 値を評価指標とする GBDT モデルを作り直した。
スコアはたぶん 0.36487、ここら辺は五月雨式に仮提出しまくっていてわかんなくなっちゃった。
次に、9 種類の予測に対して四分位数により結合することを検討した。
結局最小値をとるのが一番よくて、スコアは 0.50572 となった。ここでようやく最初のベースラインを超えた！！このとき残り 2 週間。

さらにここから予測精度がよかった 4 種類だけをベースにして、頻出 GO term に対しては最小値、レア GO term に対しては最大値(中間は線形補完)となるように出力を調整した。
一方でほかの人の公開ノートとは最大値により結合することにした。
これでスコアが 0.51481 となり、わたしの提出したノートの中では一番の成績となった。
ちなみに GO term ごとに望ましい分位数を決めて、それごとに結合する方式だと成績が上がらなかった(0.46535)。過学習なのかな。

また、他の人のデータ結合を見ると基本的に最大値をとる方が成績がよくなっているように見える。
一方わたしのモデルに限ると(レア GO term を除き)最小値をとる方がいい成績がとれる。
この違いがなんなのかはよく分からなかった。
他の人の公開ノートを使うと簡単に成績が上がるけど、このような検証ができないのは痛手だよね。


### GO term の親子関係を用いた予測
GO term には大分類・小分類があって、あるタンパク質が GO term A を持つ場合、A を包含するような GO term も必ずそのタンパク質に紐づけられる。
逆に、親の term をもたなければ絶対に子の term を持たない。
親の term をもつタンパク質に制限して、その中で子の term を持つかの判定を行う。
もとから予測対象の GO term は教師データ 142,246 件のうち 1,000 回以上登場するものに限っているが、親のデータに制限したほうが positive / negatve の割合が近くなるし、こっちのほうがいいんじゃないかなあ。

親の GO term ごとにデータを整えて、モデルを作って、予測して、予測を保存、というのを繰り返す。
ほとんどの GO term は複数の親をもつので、これらの予測を前と同様に最小値で組み合わせて最終的な予測とする。

ここら辺は提出の直前で焦っていて何が起きたかあまりはっきり覚えていない。
単体の T5-embedding , NN(2 layer) を転移元として転移学習したのだが、単体で見ると転移前より成績が上がっていて、他のモデルと組み合わせると手元ではあまり変わらず、仮提出したら成績が悪くなった。
スコア 0.47563、ただしこのときは GO term ごとに望ましい quantile の ratio を決めて、それごとに結合する方式。
前にモデルの組み合わせたときにこの方式はよくないことは分かっていたはずなので(0.51481 &rarr; 0.46535) もう少しざっくり ratio を決めた方がよかったのかもしれない。
でも分位数の位置を線形補完って意味分からないしやりたくなかったんだよね。


### 教師データの制限
締め切り 1 週間前くらいに投稿された discussion で成績改善のアイディアがいろいろ書いてあった。
わたしが気づいたのは締め切り 3 日前。早めに気づいていればやれることもあったかも。なかったかもだけど。
https://www.kaggle.com/code/szabo7zoltan/combineembeddings
https://www.kaggle.com/competitions/cafa-5-protein-function-prediction/discussion/431491

GO term は大元の親によって漏れなく重複なく 3 グループ(BP, MF, CC)に分けられる。
アイディアとしては以下の 3 つ。
・embeddings として　T5, EMS2, ProtBERT を横に並べて大きいベクトルを作る
・すべてのグループの GO term をもつタンパク質のみを教師データとして採用(43,000件)。ほかはアノテーションが欠落していると解釈
・予測対象の GO term をざっくり上から 1000 件とるのではなく、BPから 1100 件、MFから 450 件、CCから 300 件とする

一番上は以前に試したけどそこまでよくならなかった(MLP のノード数をケチったせいかもだけど)。
embeddings は T5 のみ、下二つはアイディア通りに実装してスコア 0.50328。
さらに今までの考え方を組み合わせられたらよかったけど時間がなくて諦めた。
というか教師データのとり方が変わると今までの手元の評価が変わるからどうしようって困っちゃった。

これでわたしの旅は終了。
submit ファイルは 2 つまで OK なので、もう一つは成績いい人のファイルにちょこっとだけ自分の予測を足してごまかしたものを提出した。ごめんなさい。



# 感想
kaggle はとりあえず参加ボタンを押すだけで提出すらしたことがなかったので、今回結成績は残念だけど最後まで遊べたのはよかったと思う。

今までやったことを復習したけど、このままやっても結局 0.55 みたいなすごい成績が出ることはなかったと思う。えらい人の[振り返りレポート](https://www.kaggle.com/competitions/cafa-5-protein-function-prediction/discussion/435042)を見たけれど、NNモデルでいろいろ工夫するべきだったらしい。そもそも FCNN ってモデルを初めて聞いた。
あと Pseudo-labeling と Quantile Transformer って言葉は次の機会のために覚えておく。

わたしが使ったのは MLP がメインだったけど、実はこのノード数の調整もわからなくて公開されていたノートをベースに 2, 3 通り試しただけだった。ここら辺もちゃんとできるように勉強してきます。

結果はダメダメだったけど楽しかったのでまた参加できそうなコンペがあるといいな。
できれば長期休みがとれるあたりで。