PetFinder2 振り返り
はじめに
2022年からは自分の備忘録も込みでコンペの振り返りを発信していこうと決めました。
どんなに成績が悪くても自分なりの学びを残せていけたらと思います。
PetFinder2 コンペとは
PetFinder.my - Pawpularity Contest | Kaggle
petfinder.myに登録されている犬と猫の写真から人気度を回帰予測するテーマでした。
人気度はPawpularityというスコアでPetFinder.myが独自に算出されている指標で、トラフィック情報を元に算出されているようです。
使用できるデータは犬や猫が映っている画像以外に、画像に関するメタデータが与えられていました。メタデータは全て0 or 1のフラグ情報のみとなっています。
このコンペ特有のポイントといえば、1日2subしか出来ないということが挙げられます。通常は1日5subまで出来ることが多いですが2subしか出来ないので、とりあえず実験回して出してみるということがやりづらかったです。
これまで以上にCVの重要性が大きかったように思います。
やったこと
コンペ初期
2021年はSwinTransformerの登場から、画像コンペではSwinTransformerを試すようになっていましたのでこのコンペでも初手としてSwinTransformerを試しました。
回帰問題ということもあって、Loss関数にはRMSEを使用していましたが思った以上にスコアが伸びず....
Discussionを眺めていると「targetの値を0~1に変換し、Loss関数にBinaryCrossEntropyを使用する」というアイデアが共有されていました。
回帰を分類問題のように解くこの手法は、3年前のコンペから使われている手法のようです。参考 Elo Merchant Category Recommendation | Kaggle
上位解法でもLoss関数にはBCE(BinaryCrossEntropy)を使っている人がほとんどで、回帰を解く方法の1つとして今後も試されるものと思います。
Loss関数にBCEを使えばいいと分かってからは、他の探索に入りました。
コンペ中期
メタデータは与えられているものの画像から得られる情報がメインとなっているのでこれまでの画像コンペの知見を活かしながら、CVを下げるように実験を回していました。
具体的にはDataset、Augmentation、Model、学習方法の観点で考えていました。
Dataset
Discussionを読んでいるといくつかDatasetに関するスレッドが建てられており、私がその中でも使用していたのは以下の2つです。
今回のデータセットの中で何かできることを終始探していたのですが、ここが大きな敗因だと考えています。
Augmentation
Albumentationに搭載されているAugmentationで意味ありそうなものは順々に試していきました。
独自でAugmentationを考えていたものとしては、アスペクト比が変わらないようにリサイズするような手法なども試していましたが精度向上には寄与していなかったように思います。
最終的に使用したAugmentationは以下の通りです。
A.Compose([ A.Resize(config.img_size, config.img_size), A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), A.Blur(p=0.3), A.RandomBrightnessContrast(p=0.5), A.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1), A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255.0, p=1.0), ToTensorV2(), ])
Model
SwinTransformerなどのVision Transformer系とCNN系を試していました。
基本的にはtimmに搭載されているモデルの中からImageNetの結果を見ながら試していました。
timm以外では、コンペ終盤に出てきたConvNextも最後の足掻きとして試してみました。
Ensembleに最後用いたモデルとその結果を紹介します。スコアが多少弱くてもEnsembleでいい感じにならないかと甘い考えを持っていました。
※通常のコンペであればとりあえずCVと比較するためにSubをしながらLBの値も確認していたと思いますが、2subしか出来ないのでCVしか出してないものもありますのでCV値のみ紹介します。
Model | Dataset | CV |
---|---|---|
swin_base_patch4_window12_384_in22k | 顔中心 | 18.10664 |
vit_base_resnet50_384 | 顔中心 | 18.01175 |
deit_base_patch16_384 | 顔中心 | 18.01672 |
swin_large_patch4_window12_384_in22k | 顔中心 | 17.77069 |
convnext_base | 顔中心 | 17.93557 |
tf_efficientnet_b5_ns | 顔中心 | 18.40857 |
dm_nfnet_f4 | 顔中心 | 18.47753 |
swin_large_patch4_window12_384_in22k | 重複削除 | 17.48302 |
swin_base_patch4_window12_384_in22k | 重複削除 | 17.58015 |
deit_base_patch16_384 | 重複削除 | 17.86186 |
vit_large_r50_s32_384 | 重複削除 | 17.74853 |
tf_efficientnet_b5_ns | 重複削除 | 18.40857 |
※使用したDatasetの違いで同じモデルでも複数存在しています
学習方法
画像コンペでよく見かけるSelf-Supervised Learningや、Mixupなどを試していました。
いくつか試したものを箇条書きでまとめます。精度向上に働かなかったものもありますが、私のやり方が間違っていると思いますので上位解法とソースを基に勉強させていただきます。
- Mixup
- TTA
- 最終的には時間の関係上外しました
- 最初2epochと最後2epochはAugmentationしない
- Label Distribution Loss
- 1つのバッチの中でランキングを当てるように学習
- 全く収束しませんでした
- 2つの画像を比較して、どちらが人気かを当てるように学習
- 試したのが終盤でSubの中には入れられなかったです
- 入れてもあまり寄与していなかっただろうと思います
コンペ終盤
Ensembleに使えるモデルをたくさん作っておいて最後にEnsembleを試しました。
公開CodeやDiscssionでSVRの話が出ていたので、Ensembleはできる限り弱学習器を使う方がいいように思っていました。
1st Stageでは上記のModelから予測値を算出し、2nd Stageでは各モデルの予測値をInputにSVR, Ridge, Lassoによる回帰予測を実施しました。最後、SVR、Ridge、Lassoから出てくる予測値は平均値にすることで出来る限り過学習がない方向で最終Subを作成しています。
結果
1694thで大惨敗です。Publicも1112thで公開Codeすら超えられませんでした。
ただ自分なりの意地で公開Codeをコピーする気にはなれず、最後まで自力でモデル作成と学習方法で何か工夫できないか模索していました。
この経験は次に活きると信じています.....!
上位解法
2021年1月16日時点でDiscussionに上がっていたものをいくつか紹介します。
1st Solution
ImageNetで学習した重みによる埋め込み次元をSVRで学習していたようです。
使用したモデルはtimmでViT系とCNN系、CLIPのようです。
ここからは所感ですが、CLIPを使う発想はなかったこととFineTuningすらしていないことが衝撃でした。
FineTuningすらしていないのは今回のコンペ特有だとは思いますが、
予測値を使うのではなく埋め込み次元を基にSVRを使うのは試すべきだったと反省しています。
2nd Solution
SwinTransformerをベースにViT系をいくつかEnsembleされているようです。
Loss関数にはBCE以外にPoisson、MSEやCEなども使われているのでこの辺りも自分と大きな違いかと思います。
また、前回のPetFinderコンペと重複している画像は前回コンペのメタデータをjoinしながら学習されていたようです。
その際にTargetの分布が崩れないようにjoin出来ないデータも全て学習したというのが2ndになった要因と考えられているようです。
Targetや予測分布を確認することや、前回コンペや類似テーマは追うべきということを教わりました。
3rd Solution
SwinTransformerとVision TransformerとCaitを使用しながら、SVRをHeadに学習をしたようです。
またStackingとして単純な線形モデルを使用して各モデルの予測値の重みを計算されたようです。
1stと同様、とてもシンプルな解法なのですが全結合層の前のEmbeddingからSVRに入れて学習するのがよかったのだろうと思います。
4th Solution
2nd Solutionと同様に前回コンペと重複している画像は前回のメタデータをjoinした後処理を実施されているようです。
ConvNextを使用しつつConvNextがかなり高いスコアを出しているのも特徴かと思います。
猫専用モデルや犬専用モデルなども作られていたようで、手数の多さやアイデア量もまだまだ足りないなと自覚しました。
6th Solution
6th Place - Multitask Learning
画像の前処理としてアスペクト比が崩れないように正方形にCropされていたようです。
CNNの学習ではHead層を学習するためにBackboneの重みは固定するという方法を紹介してくれています。
Codeのリンクも付いているので勉強します。
また画像サイズに合わせて、Augmentationを変えているのも非常に興味深い点です。
メタデータとしてCatDogラベルを追加しています。
Hill Climbingのところにとても重要なことが書かれています。この辺りはさすがChrisです。脱帽です。
Singleモデルで優れたCVを持っていなくてもこれまでのモデルとアンサンブルしてCVとLBが改善されればOKというのは
頭でわかっていてもなかなか実践することが難しかったです。
どうしてもSingleモデルでのベストを追い求めてしまうのですが、このHill Climbingのやり方で今後試していこうと思います。
9th Solution
DLDLモデルを使用していることが最も大きな違いですので紹介します。
ラベルの順序に意味があるようなケース(年齢など)では有効だと考えられますので、論文とソースをみたいと思います。
18th Solution
18th solution. Single swin transformer, with code.
CPMPさんによる解法紹介です。
ordinal regressionを用いたSwinTransformerのSingleモデルでこのスコアを達成されたようです。
今回のタスクにとてもfitする方法だと思いますし、さすがの引き出しの多さだと思います。
所感
今回のPetFinderコンペはCVもLBもあまり良くならない期間が非常に長く苦しいコンペでした。
結果も奮わず情けないですが、上位解法を基にまた勉強し直そうと思います。
今回の反省点はこちらです。
- 前回コンペや類似テーマはちゃんと追う
- 全結合からのEmbeddingを使う
- 毎回うまくいくわけではないと思いますが、Do Everythingの精神で試すべき
- Singleモデルの向上にとらわれず、Ensembleで上がれば良しとする
- テーマに沿ったLoss関数を考える
とても悔しいので次のコンペで挽回します。
最後まで読んでいただきありがとうございました。