2021年の振り返り

2021年もあと少しということで、今年の自身の出来事について振り返ってみようと思います。

Kaggle

いくつかピックアップして振り返ります。

Notebook GrandMaster になる

2020/12/26時点でNotebook金メダル10枚で、2021/12/30時点でNotebook金メダル28枚なので、ここ1年で18個の金メダルNotebookを出した計算になります。数えてみるとめちゃくちゃ頑張っていてすごい。

Rainforest Connection Species Audio Detection (16/1143)

  • 結果 : 銀
  • メンバー : arai-san, kaeru-san, hiraiwa-san
  • ジャンル : 音声

チームメイトのベースラインが強すぎたので、それをベースに主にオンプレGPUでゴリゴリ殴るみたいなことをしていました。音声コンペに関する実力は伸ばしどころしかないなと感じました。

RANZCR CLiP - Catheter and Line Position Challenge (7/1547)

  • 結果 : 金
  • メンバー : kuma-san, raddar
  • ジャンル : 画像

DiscussionとNotebookを初期から頑張っていて、強力なチームメイトと組めたおかげで金メダルを取ることができました。この時のDiscussionが2021/12/30時点で一番多くupvoteをもらえているので、共有して良かったです。

Bristol-Myers Squibb – Molecular Translation (20/874)

  • 結果 : 銀
  • メンバー : anokas, Darragh, Dmitriy, Maxim
  • ジャンル : Image Captioning

マシンで殴るコンペだったので参加するんじゃなかった。

初めてのImage Captioningだったのでベースラインを作成するのに数日かけていました。Image Captioningができるようになったのも良かったですが、この時のDiscussionもNotebookも2021/12/30時点で二番目に多くupvoteをもらえているので、共有して良かったです。マシンで殴るコンペじゃなかったらさらに良かった。

CommonLit Readability Prize (23/3633)

  • 結果 : 銀
  • メンバー : yabea-kun, copasta-kun, oohara-san
  • ジャンル : NLP

色々なモデルを試すことができ、BERTまわりの知見が色々と得られたので良かったです。残念ながら Public 4th から shake down しました。

G2Net Gravitational Wave Detection (12/1219)

  • 結果 : 金
  • メンバー : arai-san, naoism-san, hirune-san, sinpcw-san
  • ジャンル : 波形(重力波

とりあえずベースラインを出したものの、重力波何もわからんという気持ちでチームメイトのおかげで金メダルを取ることができました。ベースラインにwandbとGrad-CAMを導入したおかげかDiscussionも2021/12/30時点で三番目に多くupvoteをもらえているので、共有して良かったです。

Google Brain - Ventilator Pressure Prediction (15/2605)

  • 結果 : 金
  • メンバー : takoi-san, pao-san, hakubishin-san, charm-san
  • ジャンル : 時系列

とりあえずPyTorchでベースラインを出したものの、TPUを使った方が良さそうだったのでTensorFlowに移植しました。細かいところまで手が届くのでPyTorchを使うようにしていましたが、案外TensorFlowでも細かいところまで手が届くことがわかったので良かったです(TensorFlow歴が短いだけですが...)。作成したTPU Baselineがチーム内で活躍して金メダルを獲得することができたのも良かったです。

atmaCup

atmaCup #9

atmaCup #6 で学生枠での優勝はありましたが、総合でのメダル獲得はこれが初めてだったので嬉しかったです。アプローチも人それぞれでとても楽しいコンペでした。

その他

W&B Dev Expert

Kaggle Notebook を頑張っていたおかげで、Weights & Biases の Developer Expert になりました。Kaggle Notebook を頑張ってきて良かったなと思いました。

おわりに

来年も良い年にしたいですね。

良いお年を。

 

Kaggle Notebooks Ranking TOP5 になるまでを振り返る

このたび Kaggle Notebooks Ranking で TOP5 になることができたので振り返ります。

https://www.kaggle.com/yasufuminakama

はじめに

この記事では、自分が投稿してきた Kaggle Notebooks を振り返っていきたいと思います。現行コンペの Notebooks に関してはコンペ終了後に追記することにします。

はじめて投稿した Notebook

はじめて投稿した Notebook は DSB2019 での順序尺度のラベルを回帰で解く Notebook でした。投稿時点で回帰で解くような Notebook がなかったので、あくまでサンプルとして、大したスコアが出ないような Notebook として出したことを覚えています。自分は PetFinder コンペでこのテクニックを学んだので、誰かがいずれ共有するなら先に自分が共有しようと思って投稿しました。

[Public] DSB2019 LGBM Regression Sample | Kaggle

わざわざ [Public] と書いているのに初々しさを感じます笑。

このはじめての Notebook 投稿以来、Notebook を投稿することのハードルが下がったと感じているので、一歩踏み出す勇気は大事だと思いました。

Notebook を投稿するときの心がけ

Notebook を投稿するときは、「このアプローチでこれくらいの CV が出てこれくらいの LB が出るという目安になる」ような Notebook であるように心がけています。当たり前のことではありますが、それができていない Notebook も見てきたので...

Image Notebooks

PANDA コンペ

順序尺度のラベルを Classification で解く Notebook と Regression で解く Notebook を共有しました。

Cassava コンペ

ベースラインとなりそうな Notebook を共有しました。

RANZCR コンペ

ベースラインとなりそうな Notebook を共有しました。

Discussion で出ていたアイデアを実装した Notebook も共有しました。Kaggle の Resource を最大限活用できるように training は TPU でも動作するようにしました。

BMS コンペ

初めて取り組む Image Captioning でしたが、数日かけて作成したベースラインとなりそうな Notebook を共有しました。

Tabular Notebooks

MoA コンペ

テーブルデータに対する PyTorch NN のベースラインを公開しました。ここまで Upvote をもらえると思っていなかったので感謝。

単純な LGB のベースラインを共有しました。

OSIC コンペ

このコンペでは LGB と Ridge のベースラインを投稿していて、このコンペのデータに対しては LGB よりも Ridge の方が精度が出るということを共有しました。

終わりに

ここまでたくさんの Notebook を投稿してきて、Kaggle Notebooks Ranking で TOP5 になることができました。感謝のコメントはもちろん励みになるのですが、指摘のコメントももらえるのがとてもありがたいと感じています。まだ投稿することのできていない分野もあるので、引き続き頑張っていきたいと思います。

Kaggle Grandmaster になるまでを振り返る

このたび Kaggle Grandmaster になることができたので振り返ります。

https://www.kaggle.com/yasufuminakama

はじめに

この記事では、自分が kaggle を始めてから Grandmaster になるまでの道のりを振り返りたいと思います。kaggle 始めたての時は機械学習初心者みたいなものだったので、どのように成長していったかをコンペごとに振り返っていけたらと思います。技術的なところまで掘り下げた内容ではないのでご注意ください。

Kaggle を始めたきっかけ

大学では理工学部管理工学科というところで、OR・IE・人間工学・統計学金融工学・情報システム・機械学習などを幅広く学んでいました。そして学部3年の3月あたり(つまり学部4年になる直前)に、3日間の短期インターンみたいなやつで kaggle の House Prices に取り組んだのが kaggle との初めての出会いでした。その時点では大学では、 R を使って train に fit させて test を predict するくらいしか経験していなかった(いわゆる機械学習初心者だった)ので、実データに対する Feature Engineering だったり、Validation の構築だったりと、初めて機械学習の実践というものをそこで体験して、kaggle を通してもっと知識を身に付けたい(あとは単純に競争が楽しい)と思ったのが、kaggle を始めたきっかけでした。

初期は何で勉強したのか

初期は python を扱うのも初めてだったので、まずは kaggle learn をやりました。

https://www.kaggle.com/learn/overview

また機械学習初心者向けの本でも勉強しました。

最近は kaggle 初心者向けの書籍もあるので、「kaggle を始めたい!」という方はこちらの書籍もいいと思います。

kaggle スタートブックの次のステップとしては、こちらの書籍がいいと思います。

メダルが取れない時期(学部3年3月〜学部4年2月)

Home Credit コンペや TGS Salt コンペや Elo コンペに出てみて、Public Notebook や Discussion を参考に試行錯誤するものの、試行錯誤するにもまだまだ経験不足でメダルも取れないような時期でした。いま振り返ると、当時は取れる手数も少なかったので、まあメダル取れないよねという感じです。ただ、コンペに参加するだけ経験知はたまっていくので(ちゃんとコミットすればの話ですが)、この時期は地道に経験知をためる時期だったと言えると思います。(ポケモンで例えると、アチャモのレベルが上がった程度のもの)

メダルが取れるようになってから(学部4年3月〜)

PetFinder コンペ(チーム銀メダル)

メダル獲得への転換点となったのが PetFinder コンペでした。Public Notebook や Discussion の特徴量を組み合わせたり、自身の EDA から編み出した特徴量を加えたりすることで、なんとかソロで銀圏につけていたところ、金メダルを目指してチームマージをすることになりました。結果は銀メダルでしたが、そのチームマージのおかげで学びのスピードが何倍にもなり、多くのことを学ぶことができました。(ポケモンで例えると、ここでアチャモからワカシャモに進化できたイメージ)

このコンペは以下の記事で振り返っています。

nmaviv.hatenablog.com

ここで一つ言えるのは、優秀な方とのチームマージは学びのスピードが何倍にもなるので、自分の学びになりそうなチームマージは積極的にした方が良いということです。

Santander コンペ(ソロ銀メダル)

PetFinder コンペの後は Santander のよくわからないコンペに出ました。Discussion や Public Notebook を注意深く追って Fake を除去する必要があるということに気づけば、あとは基本的な特徴量を作るだけで銀メダルを取ることができ、ここで Expert になることができました。

このコンペは終了後に上位勢のコードを見ることで NN のモデリングなど学ぶことができました。

壺コンペ(チーム銀メダル)

このコンペは以下の記事で振り返っています。

nmaviv.hatenablog.com

このコンペを始めようと思ったきっかけは、メダルを取りたかったからではなく PyTorch を書けるようになりたかったからです。ちなみにこの時 PyTorch の勉強には PyTorch Tutorials の他に以下の書籍を参考にしていました。

このコンペでは PyTorch の実践をしたいということで、最終的には以下のコードを参考に圧倒的成長が得られました。強者のベースラインはとてもありがたいです。

https://github.com/lopuhin/kaggle-imet-2019

チームメイトにも色々教わって、とても勉強させていただきました。

Jigsaw コンペ(チーム銀メダル)

このコンペも、メダルが取りたいというよりも NLP ができるようになりたいと思い参加していたものでした。結果的には PetFinder コンペでライバルとして競っていたチームの人たちとチームマージして、NLP 初心者の身で色々教えていただき、NLP で取り組むべき定番なアプローチなど、多くのことを勉強させていただきました。

またこのコンペで上位が使っていた手法を、後の Google Quest コンペなどでも試して精度を上げることができ、とても勉強になるコンペでした。上位の手法を拾って手札に入れておくのは大事ですね。

網膜コンペ(チーム金メダル)

このコンペは壺コンペで学んだことをそのまま活かせると思い参加しました。しかし CV はあてにならず、External Data を使って如何に汎化したモデルを作成できるかというところで、とにかく多くの実験を回してみて LB で検証するということをやっていました。チームメイトの力もあってなんとか獲得できた金メダルでした。詳しくは以下の記事で振り返っています。

nmaviv.hatenablog.com

チームの Solution は以下のリンクです。

https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107944

このコンペではデータセットの分析の必要性だったり、モデルの予測根拠の可視化だったり、なるべく汎化するような学習のさせ方だったり、データが少ないときの Pseudo Labeling の重要性だったりと、色々なことを学ぶことができました。

このコンペの結果から、Master になることができました。

TITAN RTX 購入

kaggle が GPU の制限を始めたこともあり、自由に使うことができる GPU があれば今後の学習が捗ると思い、先行投資の考えで TITAN RTX を購入しました。後の OpenVaccine コンペではフル稼働で活躍してなんとか金メダルをもぎ取ることができたので、購入してよかったなあと思います。

Kaggle Days Tokyo

kaggle days では強い人たちの発表を聞くことができ、とても勉強になりました。さらにそこで開催されたコンペの上位解法も学びが多く、早速実装して今後のコンペで活かせるようにしました。またここであらためて自分のパイプラインのようなものを整備し直し、今でもそこからコピペで取ってきて使ったりしています。みんなやっているとは思いますが、蓄積してきた任意のコードをどこかのタイミングで使い回せるようにまとめておくと、取ってきやすくて楽ができています。

2019 DSB(チーム金メダル)

 ブログで振り返っていないので当時のツイートを貼ります。

チームの Solution は以下のリンクです。

https://www.kaggle.com/c/data-science-bowl-2019/discussion/127500

このコンペでもチームメイトから多くを学びました、やはりチームを組むことで得られるものは多いです。また上位解法でユニークだった Transformer によるモデリングのコードもとても勉強になりました。

https://github.com/lime-robot/dsb2019

Google Quest(ソロ銀メダル)

このコンペは Jigsaw コンペで気になっていた解法を試したり、BERT などを回すということで自宅の GPU をコンペで初めて使ってみたりと、色々試してみたいことを試そうという思いで始め、それらが結果につながり銀メダルを獲得することができました。

このコンペは以下の記事で振り返っています。

nmaviv.hatenablog.com

このコンペも上位解法がとても勉強になりました。

Bengali コンペ(メダルなし)

データの説明もろくに読まずにやっていたので敗北しました。当たり前のことですが、データの説明はよく読んで適切なモデリングをしようという教訓を得ました。これが TReNDS コンペで活きました(?)

このコンペはコンペ初期に自分で Baseline Notebook を投稿してから放置していて、久しぶりにチェックすると有用な Notebook や Discussion が出てきていたので、それらをもとに再開しようと取り組んだコンペでした。

このコンペは以下の記事で振り返っています。

nmaviv.hatenablog.com

チームの Solution は以下のリンクです。

https://www.kaggle.com/c/trends-assessment-prediction/discussion/162799

このコンペは、これまでのコンペを通じて培ってきた知識を的確に使うことができた印象です。任意のコードをまとめておいたこともあり、コーディングにかけた時間も比較的少なかったです(自宅の GPU を他のコンペに使用していたので詰めるところが限られていたというのもある)。データの説明をよく読んで適切なモデリングをしようという教訓通り、データの説明を踏まえたモデリングができたかと思います。またこのコンペでは初めて海外の方と組んでみて、コミュニケーションもスムーズにいき、とてもいいチームワークができました。(ポケモンで例えると、このあたりでワカシャモからバシャーモに進化したかも)

OSIC コンペ(ソロ金メダル)

このコンペもコンペ初期に自分で Baseline Notebook を投稿してから放置していて、久しぶりにチェックすると有用な Notebook が出てきていたので、それをもとに再開しようと取り組んだコンペでした。 

このコンペでは念願のソロ金を獲得することができました。

Solution は以下のリンクです。

https://www.kaggle.com/c/osic-pulmonary-fibrosis-progression/discussion/189220

正直、このコンペは LB に Overfit している参加者があまりにも多かったことと、強者をあまり見かけなかったことから、金メダルのチャンスはあると思っていました。結果、CV と Private LB を連動させることができていた(差分がはっきりとしたサブしか投げていないというのもある)ので、とても満足な結果でした。効くモデルが金メダルを獲得した TReNDS コンペと似ていたので、そのあたりの勘があったのも良かったです。

Solution の一部は自分で投稿した Baseline Notebook に基づいたもので、役に立ったと言ってくださる人もいて、公開して良かったなあと思います。

OpenVaccine コンペ(チーム金メダル)

このコンペは開催期間が短かったこともあり、コンペ初期にチームマージをして取り組みました。All you need is diversity というチーム名の通り、とにかくモデルをたくさん作ってなんとかごり押して獲得できた金メダルでした。

チームの Solution は以下のリンクです。

https://www.kaggle.com/c/stanford-covid-vaccine/discussion/189728

このコンペは stacking の威力を実感したコンペで、CV 自体は weighted blending の方が良かったので weighted blending のサブしか投げていなかったところ、サブに余裕があるときに stacking のサブをチェックしてみると、weighted blending よりも良かったので、最終的には stacking model を複数作った後にそれらを weighted blending するというごり押しをしました。これをしなかったらギリギリ金メダルを逃していたので、ごり押しにごり押しておいて本当に良かったなと思います。

そして有用な Public Notebook が数多く投稿されたコンペで、とても勉強になりました。

振り返りまとめ

以上が kaggle を始めてから Grandmaster になるまでの振り返りになります。この振り返りから言えることは以下の事柄でしょうか。

  • チームを組むと学びのスピードが何倍にもなるので、自分の学びになりそうなチームマージは積極的にするのが良い
  • コンペ終了後は上位勢の解法やコードを見て、手札に加えておくと良い
  • 蓄積してきた任意のコードはどこかのタイミングで使い回せるようにまとめておくと良い
  • コンペに参加すればするほど経験知がたまるのでどんどん参加した方が良い

ありきたりな事柄にまとめられました。

終わりに

今までチームを組んでくださった方々と有用な解法やコードを共有してくださった方々のおかげで Competitions Grandmaster になることができました。Grandmaster と言ってもただの称号に過ぎず、まだできないことはたくさんあるので、これからもコンペに参加して自分に足りない部分を学んでいけたらと思います。

また kaggle は学びのプラットフォームとしてとても完成度が高く、たくさん学ばせてもらったので、自分も貢献していけたらと思い Baseline Notebook を投稿するようになりました。次は Notebooks Grandmaster になれたらいいなと思います。

 

 

TReNDSコンペ振り返り

kaggle の TReNDS Neuroimaging コンペに参戦したので、振り返ります。

www.kaggle.com

はじめに

結果から言うと、無事金メダルを獲得することができました。

solution は以下にあります。

www.kaggle.com

コンペの概要

予測対象:年齢とその他4つの数値(数値の内容については非公開)

評価指標:feature-weighted, normalized absolute errors

注意事項:

個人情報保護などの観点から train data の予測対象は少し加工されているとのこと

The scores (see train_scores.csv) are not the original age and raw assessment values. They have been transformed and de-identified to help protect subject identity and minimize the risk of unethical usage of the data. Nonetheless, they are directly derived from the original assessment values and, thus, associations with the provided features is equally likely.

Before transformation, the age in the training set is rounded to nearest year for privacy reasons. However, age is not rounded to year (higher precision) in the test set. Thus, heavily overfitting to the training set age will very likely have a negative impact on your submissions.

また train data には site1 のデータしかないが、test data には site2 のデータもあるとのこと

Models are expected to generalize on data from a different scanner/site (site 2). All subjects from site 2 were assigned to the test set, so their scores are not available. While there are fewer site 2 subjects than site 1 subjects in the test set, the total number of subjects from site 2 will not be revealed until after the end of the competition. To make it more interesting, the IDs of some site 2 subjects have been revealed below. Use this to inform your models about site effects. Site effects are a form of bias. To generalize well, models should learn features that are not related to or driven by site effects.

データ

  • fMRI_train - a folder containing 53 3D spatial maps for train samples in .mat format
  • fMRI_test - a folder containing 53 3D spatial maps for test samples in .mat format
  • fnc.csv - static FNC correlation features for both train and test samples
  • loading.csv - sMRI SBM loadings for both train and test samples
  • train_scores.csv - age and assessment values for train samples

  • sample_submission.csv - a sample submission file in the correct format

  • reveal_ID_site2.csv - a list of subject IDs whose data was collected with a different scanner than the train samples
  • fMRI_mask.nii - a 3D binary spatial map
  • ICN_numbers.txt - intrinsic connectivity network numbers for each fMRI spatial map; matches FNC names

チームマージ前

とりあえず LGB でベースライン作成

www.kaggle.com

CV: 0.1628 - LB: 0.162 と初期は CV と LB が一致するコンペだとか思っていました。

そして段々とハイスコアカーネルが出てきたので、それらをもとにブレンドしたものをサブミットしてみたところ、CV: 0.1581 - LB: 0.1593 という結果が出て、データ概要欄を改めて確認すると、train data の予測対象は少し加工されていると知りました。

この CV と LB の乖離の原因は、test data には train data にはない site2 が存在することの他に、この train data の予測対象の加工が少し関わっているのかなと思いつつ、ここで 3D map を使っている方々が上位にいるということに改めて気づき、ここで 3D map を使った NN を準備だけしてブレンドしていなかったので(CVが低かった)、ブレンドしてみると微動だにしなかった LB がようやく更新されます。

(チームマージありかもなんて呟いてますがこのあとにソロで行くとか呟きます)

そして NN 単体の精度をあげて NN の精度を確認してみると、CV: 0.1596 - LB: 0.1591と、3D map を使うことで CV と LB の乖離が抑えられることがわかりました。

NN は少しだけ時間がかかるので検証モデルを Ridge に乗り換え、CV: 0.1583 - LB: 0.1583 と LB が CV についていく形で順調にスコアが上がります。

(ソロで行くなんて呟いてますがこのあとにチームマージします)

チームマージ後

海外勢の Lightさん とチームを組むことにしました。

というのも、今回チームを組んでくださった Lightさん は 3D map 以外のところでスコアを上げているらしく、External Data Thread を見て 3D map で成功しているっぽい僕に声をかけたということでした。こちらとしては 3D map 以外のところでスコアを上げる糸口が見つかっていなかったので、お互いに win-win なチームマージになりました。

あとはお互いのアプローチを組み合わせて、改善できるところは改善して、以下のような solution になりました。最終的に NN を post-process なしで CV: 0.1578, LB: 0.1578 辺りまで改善出来たのが個人的に嬉しかったです。

f:id:NmaViv:20200702073439p:plain

最後に pseudo labeling も試しましたが、CV は改善するものの、train data に overfitting したのか LB は改善しませんでした。 

学んだこと

  • データの説明を読むのは大事(当たり前)
  • train と test で一癖あるとき post-process は大事
  • チームマージは偉大

終わりに

Bengaliコンペとionコンペで残念な結果に終わっていたので、ここで挽回して金メダルを取ることができて良かったです!

kaggleランクも自己ベスト更新してました(嬉しい)。

f:id:NmaViv:20200702063042p:plain

 

Google QUESTコンペ振り返り

kaggleのGoogle QUEST Q&A Labelingコンペに参戦したので、振り返ります。

www.kaggle.com

はじめに

結果から言うと、個人的に目標にしていた銀メダルを獲得することができました。

コードの一部をGitHubに上げています。

github.com

コンペの概要

f:id:NmaViv:20200213214138p:plain

コンペ概要

質問タイトル・質問文・回答文から30種類のTARGETを予測するコンペで、TARGETには、例えば「その質問が他人の興味を引くものか」や「回答が質問に対して満足なものか」などがありました。

評価指標はmean column-wise Spearman's correlation coefficient(各TARGETの順位相関係数の平均)でした。

今回のコンペでやりたかったこと

  • オンプレ初陣
  • BERTに慣れる
  • データ量が少なく比較的実験の回しやすいコンペなので、Jigsawコンペの解法で気になっていたBERT+LGBを試す
  • 銀メダルを取る

解法に加えて、これらの結果についても振り返っていきます。

オンプレ初陣

オンプレ、kaggleのGPUと比較しても、とても高速で快適でした。

Google Colaboratoryも使おうとしていたのですが、途中で落ちたりしたので結局モデル訓練はオンプレで回して、kaggleのGPUは推論カーネルを作成するためのGPU Quota Limitを確保しておきたかったので、訓練には使いませんでした。

オンプレ、これからも積極的に使っていきたいです。

BERTに慣れる

こちらのPyTorch BERTのカーネルをベースラインに進めていきました。

(TFのやつは再現性取れないのが嫌なので...) 

www.kaggle.com

このカーネルモデリングではスコアが他のカーネルに比べてまだ改善の余地があったので、他のカーネルを参考にしつつ、最終的には以下のようなモデリングになりました。

 

f:id:NmaViv:20200213225925p:plain

モデリング

モデルはBert-base-uncasedとBert-base-casedとBert-large-uncasedを回してみましたが、Bert-largeはパラメータの調整が難しすぎてまともな精度が出ず(ここらへんのお気持ちを知りたい)、また自身が終盤から参加したため実験を回す時間も確保したかったので、Bert-largeは捨てる方針で進めていきました。

結果的に、Bert-base-uncasedのモデルを5種類、Bert-base-casedのモデルを1種類、そして後述するBert-base-uncased+LGBのモデルを1種類作成してアンサンブルしました。

Bert-base-uncasedのモデル5種類の内訳としては

  1. [Q_title+Q_body]と[Answer]をinputとしたもの
  2. [Q_title+Q_body]と[Q_title+Answer]をinputとしたもの
  3. 2からMAX_LENを小さくしたもの
  4. 2からTARGETをランク化してそのmaxで割った値に置き換えたもの
  5. 2からいくつかのTARGETをnp.log1pしたもの

みたいな感じです(head_tailの割合とdrop_rateもちょっといじったりした)。時間も少なかったので、実験的に回したものを混ぜる感じになりました。

Bert-base-casedは1と同じ条件で回したものだったはずです。

コンペ参加前に比べると(取っ付きやすさという観点において)Bertに少しは慣れた気がしますが、上位の方のsolutionを見ると、Bertのこと何もわかっていないことを実感させられるので、上位の方のsolutionはちゃんと確認して次回のコンペに活かしたいです。

BERT+LGB

過去コンペの解法を活かすというところでは、Jigsawコンペの解法で見たBERT+LGBを試すことができたのはとてもよかったです。

www.kaggle.com

MultilabelStratifiedKFoldでのCVの比較になりますが(なぜGroupKFoldにしなかったのかはこの際置いておいて)、ClassifierをLGBにする前と後で、CV0.39754 → CV0.40056と向上し、単純なアンサンブルでは、Bert+LGBのモデルが加わることでCV0.41593 → CV0.41848と、単純な差分をとったBertを混ぜるよりも伸び幅が大きかったです。

後処理

最初はQWKコンペでよく使われるOptimizedRounderを使っていましたが、最終的には小さい値(または大きい値)からどこで閾値を設定すればスコアが最大になるか探索して、それを繰り返すような形で閾値を求めていきました。閾値ごとのサンプル数とかも見ないとCVにフィットしすぎた閾値になっていた気もしましたが、結局そこはそんなに詰めませんでした。

試したけど上手くいかなかったこと

  • Focal loss
  • Bert-large
  • 特定TARGETに対してunder-samplingして学習

終わりに

短い期間でのチャレンジでしたが目標としていた銀メダルに届いたのと、過去コンペの気になっていた解法を試すことができたのでよかったです。

kaggleランクも自己ベスト更新してました(嬉しい)。

f:id:NmaViv:20200214001458p:plain

 

 

 

 

網膜コンペ振り返り

kaggleのAPTOS 2019 Blindness Detectionコンペ(通称:網膜コンペ)に参戦したので、振り返ります。

www.kaggle.com

はじめに

結果から言うと、素晴らしいチームのおかげで無事金メダルを獲得することができました。

solutionは以下にあります。

www.kaggle.com

 cheaterがbanされて最終順位は10thでした。(持ちsubのbestは0.932503でした)

f:id:NmaViv:20190915023108p:plain

今回のコンペは正しいCVを構築できるようなコンペではなかったので、ほとんどLBを頼りにやっていきました(Private LBはCVに近い結果になりましたが)。なのでもちろんLBへのoverfittingの恐怖が大きかったです。対策としてはモデル数増やしてpreprocessも多様性持たせればある程度ロバストにならないかなという感じやっていました。あとはとにかくなんでも実験をたくさん回すのも大事だったのかなと思います。

コンペの概要

糖尿病網膜症の重症度を検出するコンペ

糖尿病網膜症については以下のスライドを参照してください(up主には感謝です)

www.slideshare.net

ラベルは0~4まで5種類あり、値が大きいほど重症

評価指標は quadratic weighted kappa

Synchronous Kernel Only Competition

データ

  • APTOS2019(今回のコンペ)
    APTOS2019のデータのみだとデータ数が少ないというのと、img sizeごとのcropのされ方とラベルの分布が極端でoverfittingしてしまうという問題から外部データをうまく活用してあげることが重要だったため、以下のデータもよく使用されていました。
  • APTOS2015(前回のコンペのデータ)
  • 他 external data (IDRIDやMessidor)

コンペを始めた理由

壺コンペに参戦したときのコードを流用してすぐできそうだと思ったので参戦してみました(ベースラインはすぐできました)

コンペ初期

f:id:NmaViv:20190909235448p:plain

コンペ初期、submissionエラーをかましまくって原因が突き止められずにいたのですが、カーネルで使用するデータセットに新しくファイルを上げた場合、そのデータセットカーネル上で再読み込みしないとPrivateではデータセットの更新がなされず、当然そこにあげたファイルをロードできなくなるので、このようなエラーが発生するということでした。

ここで、壺コンペでチームを組んでいたmhiro2さんがAPTOSをやりたそうな発言をしていらっしゃったので、また一緒に画像コンペどうでしょうかということでお誘いして、チームが結成されました。

そしてなんやかんやでいい順位でスタートダッシュを切ることができました。

(APTOS2015でpretrainしてからAPTOS2019でtrainしたもの)

ちなみにモデルはEfficientnet-b5でregressionでlossはMSEで解くやり方で最後までいきます。

(当時のEfficientnetのpretrained weightsはb5が最新でした)

  • preprocess検討

そしてtrain時のpreprocessを以下のようにいじってLB0.809まであげました。

# model = Efficientnet-b5
# img_size = 256
# 2015pretrain(2015valid) -> 2019train(2019valid)
Compose([ Resize(img_size), HorizontalFlip(), VerticalFlip(), Rotate(), RandomContrast(), IAAAdditiveGaussianNoise(), ])

網膜の画像なのでflipとrotateが効くのはなんとなくわかりますが(rotateは変な感じになるやつが実はあったりするんですが、それはそれでoverfitting抑える要因になっていたのかなというお気持ちで、とりあえず入れた方がLB良くなりました)、画像ごとに照明の明るさがバラついていたりするので、contrastなんかも効きました(brigtnessや他のものも試したけど少なくともCVは上がらなかった、cutoutは安定性はなかったが効くこともあったので後々一部のみ使った)

上記に加えて、少しCentercropしたもので学習させて、推論時の画像は特にCentercropしないというのでsubmitしたところLB0.811まで上がりましたが、別の網膜画像の黒いエリアは重症度に関係ないのでうまくCropして消そうという試みがうまくいってなかったという背景と、学習と推論で揃えないのもPrivateがどうなるかわからず気持ち悪かったので、採用しませんでした(Privateスコアは0.0004ほど上がってた)

  • 重複画像の処理

ちなみに、APTOS2019には重複画像が存在していましたが、重複画像についてはMD5で検出し、重複画像が同じラベルであれば一枚にするだけでいいのですが、重複画像でも異なるラベルの場合は、自分たちのモデルを使用してre-labelingしました(regressoinで解く場合はラベルの平均値を取るので良さそうですが、classificationのモデルも作成する場合その方がいいと思ったので)(ここを気にしすぎて足踏みするのも勿体無かったのでとりあえず暫定的にみたいな感じだったが、結局最後まで同じものを使用した)(というか、trainとtestで重複画像があって、それをリークとして扱ったものをサブしたところLBが下がったので、ラベルあまり信用できないじゃんwとなったのもあります)

  • img_sizeとcropのされ方のばらつき

img_sizeとcropのされ方のばらつきの問題があったので、cropの仕方をimg_sizeごとに決めてあげようみたいなことにもトライしてみていて、public-testに640*480が多かったので(一方で640*480はtrainには少なかった)、同じアスペクト比の2048*1536をアスペクト比保ったままcropしてあげて(cropしてあげないと黒いエリアが多い状態になっている)640*480に似たサンプルを増やしてあげれば...みたいなのが効果がなかったので(2048*1536は全てラベル0だったのもあったのかもしれませんが)、ここを深掘りするのはやめました。

コンペ中期

スコアが近かったかまろさんとマージして、[kaggler-ja] CMY が誕生しました。

メンバーのハンドルネームの頭文字をくっつけたら色の三原色になったのでそれを採用しました笑

かまろさんも同様にAPTOS2015でpretrainしてからAPTOS2019でtrainするというtraining methodで、モデルはSeResNext101で、解き方はregressionで、lossはRMSEで、preprocessはPublic kernelに上がっていたBensCropというのを使ってやっていて、僕らとは異なるアプローチでした。(アンサンブルしたら効きそう👀)

しかし、アンサンブルでスコアが上がらなかったり、しばらくの間「何もわからない」状態が続きます。

とりあえずここで一旦可視化をしてみようとclassificationのモデルを作成してGrad-CAMでモデルがどこを見てクラスを判断しているかをチェックしてみました。

とりあえず一番データ数の多いラベル0の例

【APTOS2015でpretrainしていない画像(LB低い方)】

f:id:NmaViv:20190912022216p:plain

APTOS2015でpretrainしていない画像は四隅と真ん中でラベル0と判断しているように見えます。

【APTOS2015でpretrainした画像(LB高い方)】

f:id:NmaViv:20190912022230p:plain

一方でAPTOS2015でpretrainした画像は上記の一部が緩和された結果として下隅でラベル0と判断しているように見えます。(つまり上に比べたら疎らになった印象)

APTOS2019は画像数も少なかったですし、img sizeごとのラベルの偏りやcropの違いもすごかったりしたので、こうしてAPTOS2015でpretrainしてからAPTOS2019でtrainしてあげてoverfittingを防ぐことでLBも上げることができたように見えます。

ただまだ下隅の暗闇の部分で判断しちゃっているようなので、もう一工夫してあげればまだスコアは伸びそう?

そうこうしているうちにかまろさんが活路を開きます。

 ちなみにこの後のチームslack

f:id:NmaViv:20190912030557p:plain

こうしてワイワイできるのもチームでコンペに取り組む醍醐味だなあと思いました笑

かまろさんが具体的に何をしたのかというと、pretrainは特にせずに、APTOS2015のデータセットとAPTOS2019のデータセットで同時にtrainしてAPTOS2019でvalidationしてあげたとのことでした。

そしてdefault coef = [0.5,1.5,2.5,3.5]を使ってLB0.820、optimized coefを使ってLB0.827になったとのことでした。

これまでの実験で、default coefとoptimized coefのどちらがいいか問題がありましたが、ここで明確にoptimized coefの方が高いスコアが出たのと、以降の僕の方のモデルでの比較でもoptimized coefの方が高いスコアが出たので、optimized coefを使う方針で固まりました。

ということでこのtraining methodに似たもの(色々なパターンで効果を検証したかったので)をEfficientnet-b5の方でも実験してみました。やり方としては、APTOS2015を5foldsに切ってその内の4foldsでpretrainして、残りの1foldはAPTOS2019の方と一緒にtrainしてあげるというのでやってみました。

trainの方のvalidationをAPTOS2019でやるのは当然ですが、pretrainの方のvalidationをAPTOS2019でやるのとAPTOS2015でやるのとではどちらがいいのか比較してみたところ、LB0.809のやつ(transforms: HFlip, VFlip, Rotate, RandomContrast, IAAAdditiveGaussianNoise,CV0.936)をベースとして、

  • 2015(4fold分)pretrain(validation=2015) -> 2015(1fold分)+2019train(validation=2019):LB0.814(CV0.932)
  • 2015(4fold分)pretrain(validation=2019) -> 2015(1fold分)+2019train(validation=2019):LB0.819(CV0.931)

この結果から

  • pretrainもvalidationは2015よりは2019でやる方がいい
  • 2015と一緒に学習させることでCV下がってるのはよりoverfitting防げてて,それでスコア上がった?

みたいなことがわかりました。

このtraining方法のもとであらためてBensCropではない方のCircleCropも試してみたり、IDRIDやMessidorも一緒に使ってみたりを試しますが、ダメでした。

なんとかCVとLBの相関も取れないかと、ここでCVをimg sizeごとにチェックしてみたりしましたがダメでした。

またかまろさんのものと同様にAPTOS2015のデータセットとAPTOS2019のデータセットで同時にtrainしてAPTOS2019でvalidationというのでやってみますが、LB0.807に下がるなどして、何もわからなかったので、とりあえず上記のLB0.819の方法で進めていきます。

一方でかまろさんはpseudo labelingで自身のモデルのスコアをLB0.835まで伸ばします。

ここでかまろさんが旅行に行くとのことだったので、その間になんとかEfficientnet-b5の方もスコアを上げたいなと思っていたところ、かまろさんがimage sizeを320から256にしたところLB0.827からLB0.813まで下がったという情報を共有してくださっていたので、今のEfficientnet-b5のimage sizeを256から320にして伸びてくれないかなーという淡い希望を抱いて回してみたところ・・・

f:id:NmaViv:20190912043859p:plain

この伸びには驚きましたが、image sizeを上げてスコアが上がること自体は納得できることなので、素直に喜びました。その後efficientnet-b5のdefalut sizeである456でも試してみましたが、LB0.820ということで256のときのLB0.819よりは上がったものの320の方が時間的にもスコア的にもよかったので320を採用しました。

(またこれは後から教えてもらったことですが、現在のimagenetのSOTAのfacebook aiのFixResNextも小さいimage sizeでpretrainしてから大きいimage sizeでtrainするみたいなことをしているらしく、それと似た効果があったのかはわからない)

pretrainのimage sizeも探ろうとしましたが、他の実験もあったのでそちらを優先して取りかかれませんでした。

そしてLB0.835のse_resnext101とLB0.830のefficientnet-b5をアンサンブルして

 LB0.842まで上がって、この時点でPrivate LBが0.930でした。

この後はpseudo labelingでスコアを少しずつ伸ばしていった感じになります。solutionの方に表と一緒にまとめてあるので残りはそちらをご覧ください。

学んだこと

  • データセットの分析も大事
  • Grad-CAM使えるようになってよかった
  • pseudo labeling強かった(今回のコンペでは特に)

終わりに

念願の金メダルとても嬉しいです!

おかげさまで無事Masterになることができました...!

チーム組んでくださったmhiro2さん、かまろさん、本当にありがとうございました!

 また何かあれば追記します

 

壺コンペ振り返り

kaggleのiMet Collection 2019 - FGVC6コンペに参戦したので、振り返ります。

www.kaggle.com

コンペの概要

FGVC6 のコンペで、美術品のラベル付けの精度を競う

ラベルは1103種類存在する

その中でも398種類がcultureに関するラベル(どの文化の美術品なのか)

残りの705種類がtagに関するラベル(どういう美術品なのか)

一つの美術品に対するラベルは当然複数存在しうる(いわゆるマルチラベル

評価指標は F2 score

データ

学習用の画像(/trainフォルダ)

学習用の画像に対応するラベル(train.csv

推論用の画像(/testフォルダ)

ラベルのidとnameを対応させた表(labels.csv

コンペを始めるにあたって

このコンペを始めようと思ったきっかけはPyTorchを書けるようになりたいなと思ったからです。一応PyTorchの本を読んではいましたが、コーディングは全然していなかったので実践するのに丁度いいコンペが来てくれました。

以下はコンペ初期のPyTorch何もわかっていない時の僕です。懐かしい。

 

また今回のコンペはマルチラベルのタスクで、僕はFashionMNISTでマルチクラス分類をやったことはありますが、マルチラベルの場合どうすればいいのか当時よくわかっていませんでした。

同じような方がDiscussionにもいて、ここでようやくマルチラベルのタスクに対するアプローチを理解しました。

www.kaggle.com

コンペ初期

自分でベースラインを実装する実力は当然なかったので、コンペ初期は以下のカーネルを参考にさせていただきました。

www.kaggle.com

このカーネルはpretrainedモデルを使って特徴抽出を行い、得られたtensorをinputとしてMultiLayerPerceptronで学習させるようなカーネルで、PyTorch初心者にも理解しやすい内容になっています。

このカーネルがあったおかげでスムーズにPyTorchに入門できたと思うのでとても感謝しています。

コンペ中期

上記のカーネルをもとに自分用のベースラインを作成したものの、まだ書き方が冗長でepochを全然回すことができていませんでした(カーネルGPUは9時間まで)。

そんなとき、fastaiでモデルを作成していたカーネルが自分のベースラインよりも高速にepochを回していることに気づき、ここでfastaiに移行しました。

www.kaggle.com

fastaiがその名の通り簡単にモデルを組むことができることは聞いたことがありましたが、このカーネルを見ても分かる通り、本当にお手軽にモデルが組めました。

fastaiで色々試行錯誤したところ、結局上記のカーネルのようにモデルを学習させて、ResNet50のモデルをアンサンブルしてようやく公開カーネルを超えるスコアが出せました。

チーム mhiro2 & Y.Nakama 

当時LBで0.63台につけていたmhiro2さんがチームメイトを募集していて、スコアがそこまで近くない身分でお声がけしたところ、とても丁寧なDMをいただきチームマージする運びとなりました。

mhiro2さんは以下のカーネルを参考にしていました。

www.kaggle.com

このカーネルは初期の頃からありましたが、僕は何をやっているか詳しく見ずにスルーしていました。

このカーネルが何をしているかと言うと、.pyファイルのソースコードbase64を使ってエンコードしたものをカーネル環境でデコードして、カーネルでそれぞれの.pyファイルを実行するというようなことをやっています。

これ、詳しく見てみたらソースコードとかめちゃくちゃ参考になるもので、作者さんには感謝しかないです。

しかもこのカーネルは僕が参考にしていたfastaiよりも多くepochを回せるようだったので、チームマージ後はこのカーネルとmhiro2さんによる追加実装を参考に作業を進めていきました。

チームマージしてから具体的にやったことは以下になります。

  • モデルの検討
  1. Discussionにもあった通りSEResNeXt101_32x4dが一番良かった
  2. アンサンブル時に多様性を出すために、ResNet101、SEResNet101、SEResNet152、DenseNet161なども用意した
  3. pretrainedが出たEfficientNet-b3も試したが、精度があまり出なかったので不採用
  • 2nd-trainの検討
  1. GPUは9時間までしか回せないので、9時間だけでは十分にモデルを学習させることができないモデルもあります
  2. そこで9時間学習させたモデル(1st-train)のweightを引き継いで、lrを調整して2nd-trainさせることで十分に学習させました
  • lossの検討
  1. BCELoss、FocalLoss、F2Lossから検討
  2. 上記の組み合わせを試したものの、最終的にはBCELossを使用
  • schedulerの検討
  1. CosineAnnealingLRも試したが、ReduceLROnPlateau方式を採用
  • batch sizeの検討
  1. batch sizeは基本的に大きい方が精度が出るイメージがありますが、32と64で比較してみたところ、32の方が精度が良かったので32を採用しました
  • transformの検討
  1. 縦長の画像もあれば横長の画像もあったので、transformを色々検討しました
  2. 90度回転させてみたりもしましたが、結局以下に落ち着きました
    # size == 320
    RandomResizedCrop(320, scale=(0.6, 1.0), ratio=(9/16, 16/9)),
    RandomHorizontalFlip()
    # size == 288
    RandomCrop(288),
    RandomHorizontalFlip()
  3. size=320のときのtransformの方がCVが高く出ましたが、LBではsize=288のときのtransformとほとんど変わらなかったので、もともと学習を回していたsize=288に追加する形で、size=320でtransformを変えてまたいくつかモデルを作ったという感じです
  4. TTAのときにもこれらを採用しました(TTA 4)
  • post-processの検討
  1. 予測結果も合わせてEDAしてみて、手元のvalidationでもスコアが改善されて根拠としても十分な以下を導入しました

 

  • アンサンブル
  1. 各モデルの予測値を等weightでブレンディング
  2. 閾値も各モデルでのベストな閾値を等weightでブレンディング

反省点

  1. cultureラベルとtagラベルでの閾値はそれぞれで検討すべきだった
  2. コンペ序盤では、閾値を一つに決めるのではなくclass-wiseな閾値も検討したが、精度が下がったので閾値は一つでいいかと思ったまま最後を迎えてしまった
  • stacking

終わりに

壺コンペはカーネルも充実していて本当に勉強になりました。

CVとLBで大きな差が出ることもなかったので良コンペだったと思います。

X5?知らない子ですね・・・

Discussionで公開されている解法も時間がある時に追いたいです。

最後に、mhiro2さんとチーム組ませていただいたおかげで様々な取り組みが出来るようになったので本当に感謝しています!ありがとうございました!

 

また何かあれば追記します