🐳
kaggleクジラコンペ2022 上位者解法まとめ
はじめに
画像からクジラの個体識別を行うHappywhaleというkaggleコンペが2022/4/19まで開催されていました。
コンペ終了後に公開された上位者の解法からたくさん学びがあったので、備忘録も兼ねてまとめていきたいと思います。
上位者解法まとめ
1. Datasets
オリジナル検出器
- 多くの方が自分で学習させた検出器を使ってクジラ領域を切り出したデータセットを使用していました。
- 全身領域や背ビレ領域を切り出した公開データセットがありましたが、同じ領域を切り出すにしても、検出器が異なると多様性が生まれて精度が上がったようです。
- 公開されているデータセットの予測値をGTとして検出器を学習し、予測が外れているデータだけアノテーションし直して再学習を繰り返す工夫をしているチームもありました(引用:4th solution)
bounding box mix augmentation
- 1stチームが提案したAugmentation手法です。(引用: 1st solution)
- オリジナルの学習データセット(none)と公開されているデータセット(fullbody、backfin、detic)、自分でYolov5を学習して生成した全身データセット(fullbody_charm) を一定の割合でランダムに混ぜるAugmentaion手法です。
- backfinを加えることで背ビレのみの画像に対するロバスト性が高まり、性能が大幅に向上したそうです。
- オリジナルデータセット(none)もわずかに加えることで正則化として機能したとのこと。
- 推論時はfullbodyとfullbody_charmで予測を行い、予測値の平均を使用する。
Mix Dataset
- 様々な切り出し領域のデータセットを"混ぜて使う"というのが精度向上のキーポイントだったようです。(引用:8th solution、18th solution、etc...)
- 今回のコンペは過学習しやすかったので、混合してデータの多様性を上げることで精度が良くなったのかなと思います。
- 同じ個体で別な切り出し方をした画像をconcatして使っているチームもありました。(引用:2nd solution、7th solution)
DAIL
- 顔認識において、複数のデータセットを組み合わせて使う方法を提案した論文です。(リンク)
- 一般的に複数のデータセットを単純に混ぜると同一人物が別IDとして扱われてしまう問題がある
- ざっくりDAILでは、①ソフトマックス損失の計算対象にするデータを制限する、②データセット分類用のヘッドを追加して、Lossに組み込むことでデータセットへの依存度を弱める、ことで複数データセットを再ラベリングなしで使えるようにしている。
- 8thチームで紹介されていましたが、ディスカッションを見る限り、DAILそのものではなくBackfin用のヘッドとFullbody用のヘッドをそれぞれ準備して別なlossで学習していた?ように読めました(引用:8th solution)
- DAIL自体はかなり少ない労力でデータセットを組み合わせてデータ量を増やせるので、面白い論文だなと思います。
2. Model
BackboneとHead
- 基本的にはEfficientNetv1、v2、convnextをバックボーンとして、ArcFace、cosFaceをヘッドにしてタスクを解いているチームがほとんどでした。
- EfficientNet v1が最も精度が高かったというチームが多い印象ですが、チームによっては別なモデルが最も良かったと言っているのでデータセットやLossの設計などに依存するのかもしれません。
Batch Normalization
- 公開ノートブックには実装されていなかったのですが、ArcFaceヘッドの前の正規化層がとても重要だったようです。(引用:1st solution、36th solution)
- ちなみにコンペ中、ケロッピ先生ことhengck氏がディスカッションで言及されていました。やはりちゃんとディスカッションを追いかけるのは大事なんだと改めて感じました。(some of the modeling of arcface public kernel are wrong)
マルチタスク化
- かなりのチームが個体識別用の他に、種族(Species)分類用のヘッダを追加して同時に学習をさせる方法を採用していました。
- 複数のタスクを同時に学習させることで精度が上がると言われているので、今回のコンペでも効果があったのかと思います。
DOLG
- 通常のCNNで得られるグローバルな特徴量と、ネットワークを分岐させてMlti-Atrousとself-ATTに通して得られるローカルな特徴量を組み合わせて精度を上げる手法(リンク)
- ただ、DOLGが効果的だったというチームと全く機能しなかったというチームがいました。モデルの組み合わせ方や実装方法に何かコツが必要なのかなという気がします。
dynamic margin loss
- 以前のランドマークコンペで提案された方法で、クラスサイズに応じてマージンの値を設定することで、不均衡なデータでも学習をしやすくするための手法です。(リンク)
- 実装はこちらの方が公開してくれたNotebookが分かりやすかったです。
- 今回のコンペのデータはかなり不均衡なので、dynamic margin lossが有効だったのかと思います。
- ユニークなマージン調整方法として、エポックが進むにつれてマージンを徐々に大きくしていく"progressive dynamic margins"という方法を採用している方もいました。(引用:10th solution)
3. Train
Pseudo Labeling
- 今回のコンペでスコアを上げるキーになった手法でした。上位陣のほとんどがPseudoLabelingを導入していました。
- このコンペではデータ数が少ないクラスが多く、テストデータも含めて学習をすることで精度を上げることができたのかと思います。
- 擬似ラベルでモデルを学習し、そのモデルで更に擬似ラベルを生成する、のように繰り返しPseudoLablingをすることで精度を高めているチームが多かった印象です。(引用:2nd solution、4th solution、etc...)
- ちなみにPseudoLabelingを使わずに上位に入ったチームもいました。このチームはとてもシンプルな解法でスコアを上げており、本当にすごいと思いました。(引用:19th solution)
学習率
- Head部の学習率をBackbone部の10倍に設定することで精度が向上したそうです。(引用:1st solution)
データ拡張
- 今回のコンペは学習精度がほぼ100%になるくらい過学習しやすかったので、対策としてかなり多くのaugmentationを適用しているチームが多かったように思います。
- 珍しいデータ拡張手法として、embeddingのmixupを採用している方もいました。画像でmixupをした場合とどのような差があるのかまで分からなかったのですが、このような発想ができるところがやはり凄いなと思いました。ちなみに、こちらはディスカッションにソースコードも公開してくれています。(引用:10th solution)
- 3rdチームの解法では、「データを解析した結果、個体識別はテクスチャに依存していることが分かったので、シャープネス化とグレースケール化を適用することで色への依存度を下げた」とありました。このような考え方やプロセスは大変参考になりました。(引用:3rd solution)
4. Predict
種族ごとの閾値
- 種族ごとに新規個体の予測難度が異なるため、多くのチームが種族ごとに個別の閾値を設定する工夫を入れていました。
- 今回、テストデータに種族ラベルは含まれていなかったのですが、マルチタスクで得られた出力を使って予測したり、別に分類器を学習させて予測をする手段を取っているチームが多かったです。
- ちなみに全てのtrainデータセットを使って学習をするとCVスコアが分からなくなるので調整が難しいように思いましたが、4thチームの調整方法が参考になりました。(引用:4th solution)
SiameseNetによるリスコア
- 特にユニークな後処理として、SiameseNetを用いた類似度を使用しているチームがありました。(引用:11th solution)
- まず通常通り、ArcFaceで得られたテスト画像特徴ベクトルと学習データセットの特徴ベクトル間のコサイン類似度を計算してtop20の類似画像を抽出し、抽出した画像との類似度をSiameseNetで再計算します。最終的に特徴ベクトルのコサイン類似度とSiameseNetで計算した類似度の和を使って予測を行ったとのことです。
- SiameseNetはArcFaceの重みを事前重みとしてfinetuneしたそうです。
KNNとlogitsの混合予測
- もう一つユニークな推論方法として、KNNに加えてlogitを合わせて使用する方法を採用しているチームもありました。(1st solution)
- KNN:特徴ベクトルを用いてコサイン類似度を計算
- logit:マージンを取り除いたモデルの出力を使用
- KNNはtrainデータを多く持つクラスを出力する可能性が高いので、これを緩和するためにknn_ratio=0.5でそれぞれの予測値を混ぜて推論を行なったとのことです。(PseudoLabling後はknn_ratio=0.8で推論)
5. Other Tips
Gradient checkpoint
- 2ndチームがRTX3090でEfficientNet l2を学習させるために使用していた、少ないGPUメモリで大きなモデルを学習するためのテクニックです。(引用:2nd solution)
- 順伝播時に計算されて保持される勾配情報を逆伝播時に再計算することでメモリを節約する手法です。ただし再計算をするので、もちろん学習時間は増加します。(参考リンク)
- 初めて知ったテクニックでしたが、pytorchでの実装方法もいくつかサンプルもあったので、機会があれば今後のコンペや業務で使ってみたいと思いました。
まとめ
上位者解法を通して、コンペ中に自力では発想できなかった内容をたくさん知ることができて、大変勉強になりました。閃き力が凄いということも思いましたが、やっぱり過去コンペや論文情報などアイデアの引き出しの数が違うなと改めて感じました。
学んだことをこれからのコンペや業務に活かしていきたいと思います。
Discussion