不注意でよく物を壊す

アクアリウムとかマイクロマウスとかアリュージョニストとかそのへん

Kaggle Competition Grandmasterになるまでの5年間を振り返る

はじめに

先日5枚目の金メダルを獲得し無事Kaggle Competition Grandmasterになることができました。5年前にKaggleを始めてからの目標を達成できたので、これまでを振り返ってみたいと思います。

Kaggleを始めるまで(~2019)

今では技術的な興味がCV中心とした深層学習技術周辺に集中していますが、深層学習に出会う前はサークルや研究室でロボットを作ったり、小学生にプログラミングを教えるバイトをしたりしていました。 深層学習を勉強し始めたのは研究室に配属されてからで、最初は松尾研主催のDL4USの2期生として講義を受講して基礎を学びました。
受講者にはiLectによるGPU環境が用意されており、毎週コンペ形式で宿題があったり最終課題では自分でテーマを設定してレポートを書いたりと基礎知識をつけるには打ってつけの経験でした。 現在では講義形式で開催されていないようですが、資料などは公開されておりgoogle colabで実行できる形になっているので初学者の方は参考になるかもしれません。

Kaggle初心者〜Expert時代 (2019~2020/1)

Kaggleのことは以前から知っていてアカウント登録はしていたのですが一人では手をつけようとは思えず、友人たちに誘われたのが本格的に始めたきっかけでした。
当初は誘ってくれた友人たちとplaygroundのテーブルコンペ主体で参加していたのですが、研究に支障がないのであれば研究室のGPUマシンを使って良いと許可が出たため画像コンペに参加することが多くなってきました。
この時期に参加したコンペで印象に残っているものとその結果をまとめてみます。

コンペ名 開催期間 結果
Humpback Whale Identification 2018/12~2019/3 メダル圏外
iMaterialist (Fashion) 2019 at FGVC6 2019/4~2019/6 メダル圏外
Recursion Cellular Image Classification 2019/6~2019/9 🥈(solo)
Understanding Clouds from Satellite Images 2019/8~2019/11 🥈(solo)
2019 Data Science Bowl 2019/10~2020/1 🥉(team)
浮世絵作者予測 2019/10~2020/1 3位(学生1位)

最初に参加した画像コンペはHumpback Whale Identificationでした。鯨の尾の画像から個体識別をするというコンペで、当時は距離学習?ナニソレ?な感じでひたすらResNetとSiamise Networkのチューニングをして終わった記憶があります。

次に参加したのがiMaterialist (Fashion) 2019 at FGVC6で、ファッションアイテムの領域を検出するというコンペでした。pix2pix likeなGAN構造を用いたUNetで中盤ですが初めて銀メダル圏内まで一時的に到達できたのを鮮烈に覚えています。結局、このコンペでは当時実装のハードルが高かったinstance segmentationのモデルがかなり強く、自分はついていくことができずメダル圏外で終わってしまいました。ですが、このコンペでLBを駆け上がる楽しみを初めて知ったように思います。

Recursion Cellular Image Classificationは細胞の種類を分類する内容でした。鯨コンペで学んだ距離学習の手法を工夫しながら、中盤から安定して銀メダル圏内のまま最後まで維持し、無事銀メダルを獲得しました。(雑な振り返り) この頃はChainerを使っており、論文をサーベイして手法を自前で実装したりしていました。また、このコンペの参加中にくるぴーさんのKaggleもくもく会に参加したり、Twitterで他のKagglerの方と接点を持ったりで知己を増やすことができました。

Understanding Clouds from Satellite Imagesは画像から雲の領域を検出するコンペでした。ラベルがそこまで詳細ではなく、Object detectionで解いたほうが良いんじゃないかなど序盤に議論があったのを覚えています。自分はさまざまな種類のsegmentation手法を実装してアンサンブルする方針で進めていました。
当時はCNNベースのsemantic segmentationの手法がたくさん発表されていて、SOTA手法を片っ端から実装して試していました。このとき実装したコード遺産は現在でもsegmentationコンペでの実装に生きています。また、PyTorchが論文実装が多くアツいということで、Catalystを用いて実装したりもしました。

こうしてメダルを2枚獲得してExpertになったのですが他の分野にも手を伸ばしてみようと思い、チームでテーブルコンペに参加したり、Kaggle以外のコンペに参加したりしていました。

DSB2019はログデータを扱うコンペで、バイト関係で知り合った方たちとチームを組んで参加し、銅メダルを取りました。自分達はkaggle notebookをコピーしてチューニングするだけで終わってしまったのですが、3rd place solutionのTransformer解法を読んで、自分もDNNをこのように綺麗に使えるようになりたいと思いました。

浮世絵作者予測ではその名の通り浮世絵画像から作者を予測するというオーソドックスなお題でした 。自分はsemantic segmentationのNN構造をクラス分類に用いるという工夫でなんとか3位を取ることができました。Kaggleではないコンペでしたが、国内の画像コンペに強い方と競い合うことができたり、自前の学習パイプラインを作り込んだりと結果以上に実りあるコンペでした。

新卒就活 (2020/1~2020/6)

この時期は人生で初めての就活をやっていました。
ソロで銀メダルを2枚獲得していて、まあなんとかなるだろうと思っていましたが何も面接対策や自己分析をせず突っ込んでたくさんお祈りされました。
その時は訳もわからずなぜと憤慨したものでしたが、企業の方や友人からいただいたアドバイスは後の転職の際に活かすことができました。

Expert〜Masterになって転職活動を始めるまで (2020/1~2022/5)

新卒就活と並行してコンペへの参加も続けていました。しかしそこで自分を待っていたのは巨大なシェイクダウンの波でした。

コンペ名 開催期間 結果
Bengali.AI Handwritten Grapheme Classification 2019/12~2020/3 メダル圏外
Prostate cANcer graDe Assessment (PANDA) Challenge 2020/4~2020/7 メダル圏外
Cornell Birdcall Identification 2020/6~2020/9 🥈(solo)
Lyft Motion Prediction for Autonomous Vehicles 2020/8~2020/11 🥉(solo)
Rainforest Connection Species Audio Detection 2020/11~2021/2 🥉(solo)
BirdCLEF 2021 - Birdcall Identification 2021/4~2020/6 🥇(solo)
TensorFlow - Help Protect the Great Barrier Reef 2021/11~2022/2 🥈(solo)
凸版印刷株式会社 くずし字認識チャレンジ② 2021/3?~2022/5 4位(solo)

Bengali.AI Handwritten Grapheme ClassificationProstate cANcer graDe Assessment (PANDA) Challenge はどちらも問題設定を正しく理解して実装に落とし込んでいるかどうかで勝敗が分かれるコンペでした。前者はtrainデータにない未知のデータに対する汎化性能を高める必要があり、後者はtrainに含まれるnoiseを適切に除去しながら学習させる必要がありました。自分はどちらも愚直にクラス分類として問題設定を捉えてしまったため、適切なCVを切ることができず大幅にシェイクダウンさせてしまいました。
この頃から適切にCVを切ること、最終subを注意深く選ぶことを意識し始めました。

この時期で印象に残っているコンペとしてはLyft Motion Prediction for Autonomous Vehiclesが挙げられます。このコンペでは乗用車の過去の軌跡から現在以降の軌跡を予測するというお題で、他の乗用車の影響も考えないといけないという点がユニークな問題設定がされていました。主流なアプローチでは、hostのLyftが提供しているL5Kitと呼ばれるライブラリを用いて運転データを整形し画像化してCNNを用いたモデリングをするというアプローチが多く用いられていました。自分も例に漏れずそのアプローチを採用していたのですが、上位陣はhostから提供される追加データセットを利用して1カ月など長時間学習させることでさらにスコアを上げていました。他にも画像化せずにベクターデータとしてGNNを用いる解法などがありました。

BirdCLEF 2021 - Birdcall Identificationでは念願の金メダルを獲得し、Kaggle Competition Masterになりました。このコンペでは鳥の鳴き声を分類するという点で似たようなコンペのCornell Birdcall Identification が終わった頃から考えていたアイディアを用いて、参加序盤から金メダル圏内をキープし続け無事4位で終えることができました。実はこのコンペ参加中は新卒なのに家を決めれられておらず、また会社から関東圏内でリモートワークをすることが強制されていたため一カ月間、都内のホテルで暮らしていました。なのでギリギリで賞金を逃してしまったことは結構痛手でした......

TensorFlow - Help Protect the Great Barrier Reefでは、初めて物体検出に取り組みました。動画に対して物体検出を適用するコンペで、検出対象が小さいためKalman filterやOptical flowなどを駆使したtrackingを実装することで検出精度を上げることを試みました。また、Time-series APIと呼ばれる逐次的にデータが提供されるような制限がありました。個人的には時系列でリークを防ぐこのような仕組みはいろんな問題設定に適用できると考えているため、もっと増えても良いのではと思っています。(参加者としては実装が難しくなるため悩ましいですが)

凸版印刷株式会社 くずし字認識チャレンジ②では、浮世絵予測コンペ以来の賞金を獲得しました。OCRに取り組むことも初めてだったので、論文をサーベイした結果をもとに自分なりの工夫を組み込むことで精度を大幅に上げることができました。ディスカッションなどは活発ではなかったのですが、個人的には工夫しがいが多く楽しいコンペでした。

転職活動 (2022/6~2022/12)

当時の職場でのやらないといけないことと自分がやりたいことの方向性が異なると感じてきたため、転職活動を始めました。
新卒就活の時に採用エージェントに対して良い印象がなかったため、今回は興味がある企業に直接コンタクトをとってカジュアル面談を申し込みました。
友人が働いている企業やKagglerが在籍していて自分の強みが活かせそうな企業などの話を聞きながら、最終的に3社の採用に応募し2社から内定をいただきました。
2023年3月からは現職に勤務し始め、楽しくお仕事ができています。

Grandmasterになるまで(2023/1~)

転職活動が終わり、2023年になると画像コンペでもチームを組んで取り組むようになりました。

コンペ名 開催期間 結果
G2Net Detecting Continuous Gravitational Waves 2022/10~2023/1 🥈(team)
1st and Future - Player Contact Detection 2022/12~2023/3 🥈(solo)
Vesuvius Challenge - Ink Detection 2023/3~2023/6 🥇(team)
Google Research - Identify Contrails to Reduce Global Warming 2023/5~2023/8 🥇(team)
RSNA 2023 Abdominal Trauma Detection 2023/7~2023/10 🥇(team)
Stanford Ribonanza RNA Folding 2023/9~2023/12 🥇(team)

G2Net Detecting Continuous Gravitational Wavesではsqrt4kaidoさんとチームを組んで取り組みました。このコンペは重力波干渉計の時間周波数データノイズから重力波を検出するコンペで中盤以降、深層学習を用いた解法には限界があるんじゃないかとも話しながらももっと掘り下げることができませんでした。またsqrt4kaidoさんのCNNモデルが強かったため自分では満足できない結果に終わってしまいました。ただ、チームを組んで取り組むことで、自分が考えもできなかったであろう発想に直近に触れることができかなりの刺激を受けました。

Vesuvius Challenge - Ink Detectionは火山流によって炭化したパピルスの文字領域を検出するコンペでした。segmentationコンペだったのですが、ラベルをダウンサンプリングしても問題なく、既存のsegmentationのような複雑なDNN構造を用いなくても済むという仮説を立てて参加しました。
実際にはそれだけだと不十分で、中盤にチームを組んだろんさんのアイディアでData augmentationを強めにかけるとCVとLBが相関しつつ大幅に精度が上がるということに気づくことができました。そこからはさまざまな正則化を入れてさらに精度を上げることができました。
また、終盤にチームを組んだyukke42さんとも週2~3回の頻度でオンラインミーティングをして密にコミュニケーションをとりながらコンペに取り組みました。その甲斐もあって、最終的には準優勝することができました。

Google Research - Identify Contrails to Reduce Global Warming は衛星画像から飛行機雲を検出するコンペでした。
中盤からTawaraさんとチームを組み、それぞれ別々のパイプラインを育てる形で進めました。自分は火山コンペの経験と本コンペでも時系列の画像データがあることから、3DCNNを用いた2.5Dモデルを使用する手法を中心に学習させました。一方Tawaraさんの手法では、ベースライン手法よりも多くのchannel情報を用いて精度を向上させることができました。これらの系統が違うパイプラインのアンサンブルと、飛行機雲があるかどうかの2値分類とsegmentationの二段階の推論により汎化性能を高めることができ、public LBでは17位だったのがprivateでは6位入賞で終えられました。

RSNA 2023 Abdominal Trauma DetectionはCT画像から腸、血管外漏出、腎臓、肝臓、脾臓の外傷を検出するお題でした。このコンペでは同じ会社のyu4uさんと序盤からチームを組んで参加しました。 このコンペの難しい点として患者数に対してCT画像の枚数が多く、またその中でも外傷が含まれる画像・領域が少ないという点が挙げられます。また、腎臓・肝臓・脾臓に関しては臓器領域をある程度絞り込むことができるのですが、腸と血管外漏出に関しては外傷がある可能性がある範囲が大きくなるべく全てのCT画像を使ったモデリングをする必要があります。腎臓・肝臓・脾臓と腸と血管外漏出ではアプローチが異なると考え、自分は腸と血管外漏出に関して以前のRSNAコンペ解法を参考にしながら開発を進めました。結果的にyu4uさんの完成度が高いパイプラインと、自分の部分ではpositive sampleの少なさを克服するupsampleやtrainに対するpseudo labelを使用することでなんとか金メダルを獲得することができました。

2023年11月に開催されたKaggle Tokyo Meetup 2023では、前述したVesuvius Challengeの準優勝チームとして招待講演を行いました。(発表資料)

Stanford Ribonanza RNA FoldingRNAの塩基列に対して、それぞれの反応性を回帰予測するコンペでした。このコンペではRSNA2023の際も組んでいただいたyu4uさんと、同じ会社のmonnuさんとチームアップして参加しました。序盤からtransformerを用いたベースラインが共有されていたため、それを元にbp matrixと呼ばれる塩基対がどのように作用するかの行列などを用いたり、最新のLLMで用いられている手法を用いることや過去の似たようなコンペのコンペでの上位解法も参考にしつつ4位入賞することができました。また、monnuさんがこのコンペの直前に累計4枚目となる金メダルを獲得していたこともあり、このコンペで二人同時にKaggle Competition Grandmasterになることができました。

Kaggleに取り組むときに意識したこと

以下に自分がコンペ中に意識していることを書き出してみました。  

  • アイディアだしをこまめにやる
    • コンペの問題設定をまず理解して、どんなやり方があるかを書き出しそこにアイディアを継ぎ足す形でアイディアシートを作る
    • どんな小さいアイディアでも忘れないように書き留め(Twitterの自分宛のDMを使っていました)、時間があるときに実現できないかをじっくり考える
  • 普段から気になる論文やTwitterで流れてきた勉強会資料をためておく
    • 流し読みしておくとコンペ中に思い出して取ってこれる
    • 論文サーベイの起点にもなる
  • ベースライン作成の時点で信頼できるCVを設計する
    • CVが信頼できないことに気付いたり、バグに気づいたら優先して実装し直す
  • 実験間の差分がわかるように実験を管理する
    • wandbを用いて実験管理し、結果を再現できるようにする
    • 時間が許す限り、実験間の差分を小さく取り結果の変化が何に起因するかを明確にする
  • チームマージ
    • チームメイトがパイプラインを共有してくれる場合はコードを読んで気になるところなどを質問する
      • お互いのバグに気付きやすくなるし、意識していなかった改善点などが見つかる場合もある
    • できれば口頭で話すようにする

特にアイディアシートを作成して、コンペ中に逐次更新していくとチームメンバーへの共有や、コンペ後に解法を書いたり振り返ったりするときにも便利なのでおすすめです。

終わりに

特に最後の一年はチームを組んでKaggleに取り組むことを意識したおかげで、より多くの刺激をいただきKaggle Grandmasterになることができました。 今後もこれまで組んでくれた人とも組んだことがない人とも機会があればチームアップしてコンペ参加していきたいと思っています。
また、2023年はコンペの結果には満足できた反面、コンペ終わりには毎回と言っていいほど体調を崩していたので健康を維持できるように体力づくりなども行っていきたいと思っています。

今後ですが、興味がそそられるコンペに参加してベースラインや分析を人に見せられる形でアウトプットできるようにしたいというのと、久しぶりに面白そうな論文を読んで再実装をしたいと思っています。前者では自分のKaggle的なスキルセットの中でNNをこねくり回す職人芸的なスキルが強めになってしまっているので、本業の方でもKaggle Grandmasterの肩書きに恥じない働きができるように実装力や分析力、ソフトスキルも鍛えていきたいです。
後者では最近Kaggleにかかりっきりで最近の研究のトレンドなど把握できていないので論文読みを再開したいです。個人的には以前論文読み会で紹介した技術とのつながりでGaussian Splatting周りの技術や動画からの情報抽出などに興味があります。LLMもTwitterの話題に乗れたり、自身の開発業務に利用できるくらいには理解しておきたいですね。

2021年振り返り

達成できたこと

  • 就職
  • Kaggle画像コンペ 金メダル(ソロ)x1
  • Kaggle Master
  • 国際学会Oral発表 (IROS2021)

2022年にやりたい・達成したいこと

  • 英語・英会話練習
  • 数学 (線形代数統計学)の学び直し
  • Kaggle team 金メダル・prize
  • 画像コンペ以外で銀メダル以上
  • 業務で利益が出るプロジェクトを作る

今年はKaggleを始めてからの目標であったKaggle Masterになることができました。

また、修士論文の成果を国際学会で発表できたことも嬉しかったです。まだやり残したことはあるので古臭くなる前にいつかブラッシュアップできればなと思っています。

業務関連だと今年は目に見える成果を出すことはできていませんが、来年はよりチーム内の環境整備などを進めて利益に繋げることを目指します。

その他の来年の方針としては英語や数学の学び直しをしたり、勝てそうな機械学習コンペではなく得るものが多いものに参加することを意識するなど、基礎体力を増やすことに重点をおいて活動していきたいです。

2020振り返りエントリ/2021年の展望について

一昨年の終わりくらいからVolareという学生団体(学生じゃない人もたくさんいる)に参加していて、競技プログラミングをしたりWeb系物づくりやデザインの話を聞いたりしながらたまに機械学習やデータサイエンスの勉強会とかやったりチームでコンペに参加したりしている。 その新年会でLTをやる機会があり振り返りスライドを作ったので供養しておく。

www2.slideshare.net

自分が初めてメダルを取った頃(細胞コンペ)に比べてKaggleのタスクの内容が高度になっている印象があり、また高度人材が次々に参入してきてハードルがどんどん上がっているので負けないようにキャッチアップと研鑽を続けていきたい。

2019年振り返りエントリ

はじめに

去年書こうと思ったけど面倒くさくなって書かなかったので今年は振り返りエントリ書きます.

今年は大学院に入学したり競技プログラミングに触れてみたりKaggleをまともに始めたりといろんなことがありました.本記事では「今年やったこと」「来年やりたいこと」を書いていこうと思います.

今年やったこと

AtCoderを始めた

元々所属しているサークル周辺の界隈では競技プログラミングをやっている人は少なからずいて,腕試しがてら就活の助けになればいいなーというくらいの気持ちで始めたような気がします.

言語はNimというPythonに似た書き方ができる静的型付言語を使っていて,コンパイルすることでC言語が吐き出されるという特徴があります. サポーターズという就活生向けサービス主催の学生LT会などでも発表したりしました.

アカウント情報を見ると2月ごろから始めて,6月くらいに茶色と緑色の狭間をゆらゆらするようになったようです.
ABC(AtCoder Beginner Contest)が6問制になってから伸び悩み,新しいこと(DPとかグラフとか)を勉強しないと上に上がれないことを悟りました.
今は後述するKaggleが楽しく自分の興味にも合っているので停滞中です.来年は新しいアルゴリズム周りを勉強しないとなーと感じています.

Kaggleをまともに始めた

Kaggle自体は大学の同期5人で去年に始めたのですが,予定が合わなかったり興味の方向が違っていたり研究に忙殺されたりなどの理由で徐々にチームでは取り組まなくなりました.
自分は大学院でも画像認識を専攻していることもあり,主に画像コンペに取り組んでいます. 今年取り組んだコンペは以下の5つです.

Humpback Whale Identification (2059th/2129)

www.kaggle.com

この頃の自分はResNetを知っているくらいでkernelのSiamese Networkを写経したりしていました.チューニングの勘所なども今に比べれば全然わかっていなかったためスコアが上がらず途中で気力切れしました.

Don't overfit II (211th/2330)

www.kaggle.com

このコンペは前述した同期5人で取り組みました. Kernelを読みながらパラメータをいじったりensembleしたりしていた記憶があります.

iMaterialist (Fashion) 2019 at FGVC6 (159th/241)

www.kaggle.com

このコンペで初めて開催期間中にメダル圏内に入りました.
セグメンテーションのタスクだったのでPix2Pixを改良したモデルで銀メダル圏内に一時入ってとても嬉しかったことを覚えています. しかし,コンペ中盤からMask-RCNNの方が向いているという情報が出回り始め,実装は間に合ったのですが実験回数を稼ぐことができず振り落とされてしまいました.

Recursion Cellular Image Classification (39th/866)

www.kaggle.com

Kaggleで初めてメダルを獲ることができました.
このコンペでKaggleのコンペの進め方を自分なりに固めることができたと思っています. まとめはこちら

tattakaaqua.hatenablog.com

にあるので興味がある方はぜひ読んでみてください.

Understanding Clouds from Satellite Images (59th/1538)

www.kaggle.com

このコンペで意識したことは

  • ChainerからPyTorchへの移行
  • 使い回しを意識したコーディング

の2点です.
segmentation_models.pytorchをベースとして実装されていないモデル(RefineNetやFastFCN,DeepLabv3+など)を新しく実装したり,チューニングを楽にするためにパラメータをどう管理するかなどを考えたりしていました.こちらもコンペに使ったコードをGitHubに公開しています.
github.com

本コンペではRecursion Cellular Image Classificationの時のようにEDAなどはあまりしても進展がありませんでしたが,ひたすらチューニング回数を稼いでこの順位に入ることができました.

大学・研究関係

研究

査読なし学会で2本発表しました.

ロボット周り

研究室からRobocup@HomeとWorld Robot Summit 2019に参加しました.Robocupの方はROSとMoveIt!を使ったマニピュレーションを中心に取り組み,WRSの方は自分の研究成果の実装をしていました.
どちらも賞状はもらえる悪くはない成績でしたが多少の悔いは残ったため来年も研究に支障がない程度に頑張ろうと思います.

その他技術系アウトプット

Kaggleをやっているからか研究分野以外の論文を読む習慣がついてきたのでいくつかまとめたり実装したりしました.

www.slideshare.net

www.slideshare.net

www.slideshare.net

github.com

github.com

なおFilter-Response-Normalization-PyTorchに関してはTwitterで反響をもらったり,paperswithcodeに載ったり前述のsegmentation_models.pytorchの作者さんからissueをもらって実装の議論をしたりなど貴重な経験をすることができました.

料理とかその他趣味

料理

前々から欲しかった蒸籠を購入しました.

パール金属 和の里 中華せいろ 18cm H-5713

パール金属 和の里 中華せいろ 18cm H-5713

  • メディア: ホーム&キッチン

用途としては主に蒸し野菜を多く作っていて「適当な季節の野菜+豚バラor胸肉+塩」の組み合わせで蒸しています.素朴な味であまり飽きることがないので後述のダイエットを意識していることもあり3日に1回ほどのペースで食べています.

ダイエット

今年の4月くらいからダイエットを始めました.
結果としては○○kg->△△kgでピーク時には13kgほど落とすことができました.(12月は外食が多かったので現在の通算は-10kgほどですが)
これまで鳥もも肉を使っていたところを胸肉を使うようになり,意識して炭水化物を避けるようになりました.(昼か夜のどちらかで炭水化物を抜くくらいの緩い糖質制限)
また,あまり気にしていなかった栄養バランスにも気を配るようになり健康に近づいているのを感じます.

筋トレ

上のダイエットと並行して軽い筋トレを始めました.
初心者用の腹筋ローラを購入し一時期3ヶ月間ほどは2日おきにやっていましたが,忙しい時期になり間が開いたりして徐々にやらなくなってきました.
最近はリングフィットアドベンチャーを購入したのでがんばっていきます.

store.nintendo.co.jp

来年やりたいこと

AtCoder

  • DPやグラフなどアルゴリズムの勉強
    あわよくば卒業までには水色になりたいなーと言うふんわりとした気持ちがあります.(あくまで優先度は低め)

Kaggle

  • 画像以外のコンペでメダル獲得
    現在知り合いに誘われてData Science Bowl2019に参加しているのでメダル獲りたい......
    手元にKaggle本があるので読んだり実践したりしていきたいです.

    Kaggleで勝つデータ分析の技術

    Kaggleで勝つデータ分析の技術

  • 画像コンペで金メダル(目指せMaster)
    現在開催されているのはベンガル語の分類コンペとDeepFakeコンペでDSB2019が落ち着いたらゆったり参加しにいきたいなと考えています.

大学・研究関係

研究

今年はロボットの大会に出場していたのでそちらの比重を来年は軽めにして研究に打ち込みたいです.

ロボット周り

比重を軽めにと書きましたが今年は若干悔いが残ったので来年はRobocupもWRSも優勝を狙いにいきたいです.
後輩がとても優秀なのでタスクをいっぱい投げれる今年よりは楽ができるだろうという目論見もあります.

その他技術系アウトプット

来年は今年にもまして論文を読んだり実装したり続けていきたいです.

料理とかその他趣味

ダイエット

あと5~6kgほどは痩せたいですね.

料理

痩せたいと書いておきながらなんですが,大学1年の頃くらいからの憧れで製麺を始めたいという気持ちがあります. 来年こそはしっかり機材を揃えて麺を打っていきたいです.

Recursion Cellular Image Classification振り返り(39th)

はじめに

まずは興味深く楽しいコンペティションを開催してくれたkaggleに感謝します. 今回のRecursion Cellular Image Classificationは自分にとって初めてメダルを獲得でき,またそれ以上に多くの学びを得られたコンペティションでした. 以下,時系列ごとにやったことをずらっと並べてみました(まとめだけ見たい人は下までスクロールしてください......).

試した手法一覧

ベースラインモデル作り

まずはsoftmax_cross_entropyを用いた単純な分類モデルを作成しました(LB:0.11).

ベースはDenseNet121で入力は3x256x256のRGBに変換された画像を用いていました.最適化にはCorrectedMomentumSGDを用いました.(このころの学習率の設定などは散逸していしまいました)
Data Augmentationはrandom_sized_croprandom_flipを用いており,特にデータの正規化などはしていませんでした.

このころdiscussionでは単純な分類モデルでLB:0.3くらいは出ると言われているのでloss関数を改良しはじめました.
またCross Validationはcell typeで3foldで分割していましたがCVとLBのスコアは乖離していました.

Focal Lossを実装し,スコアが少し改善されました.(CV0.27->LB0.124) この時期にAdaboundも試しましたが機能しませんでした.

次にRGBに変換されていない6chの画像を入力に取るようにしました. kernelを見ているとmixupしているものがあったのでmixupとcutmixを用いましたが精度向上しませんでした.

次に単純な方策として学習epoch数を70から90に増やしスコアを上げました(CV:0.32 -> LB:0.19).

2stage学習

某神discussionのやり方に乗っ取って実装しました.
stage2のみでのスコアはCV:0.52->LB:0.21でstage1との重み付きensemble(2:8)を行うとLBスコアは0.225に上昇しました.
このころ例のleakが発表されLBスコアが0.303に改善されました.

みんな大好きArcFace

この辺りとか神々のクジラ解法などを参考にしながらChainerで実装し直しました.
実際CVスコアは0.5あたり出ていたのですが,ソースコードにバグがあったようで結局正しいスコアは出ていません.(LB:0.06)

AdaCos

ArcFaceハイパラなんもわからんってなってる時にTwitterに流れてきて良さげだったのでこれもPyTorch実装を参考にして実装しました. stage1でLB:0.298(Leakなし)に改善されましたがstage2でNaNが発生し,適当にClipingして直しましたがstage1に比べてスコアは上昇しませんでした.これはstage1を90epoch回していたので過学習していたのではと思います.ここからはstage2の細胞別で学習を行なうことはしていません(学習時間が流石にかかりすぎだと感じたので).

AutoFocalLoss

FocalLossのハイパラなんもわからんだったのでハイパラ調整自動化してくれるのないかなーと思って探したら見つけました.
FocalLossのgammaをいい感じに適応的に動かすパラメータに置き換えるというもので,ざっくり見た感じGitHubに上がっている様子もなかったのでFocalLossを改造して論文読みながら実装しました.記録は残っていませんが0.01~0.02くらいのスコア改善がありました.

random_sized_cropからrandom_crop

細胞の大きさはtrainとtestで違ってこないだろう(顕微鏡写真だし)と考えて,scaleのバリエーションを増やすのは害にしかならないと考えrandom_cropで512x512から256x256を切り出すようにしました.これによりLBは0.428(Leak込み)に改善しました.

Label Smoothingとか色々

label smoothingしましたが特に精度向上はしませんでした.過学習が怖かったのでとりあえずお祈りがわりに最後まで使用しました.
細胞の種類を予測するヘッドを追加すると良いのではと考えましたが全てがバグって辛かったです(ものすごい勢いで過学習する).

Metric LearningとFocal Lossの学習比率チューニング

これまでは固定の割合で学習させていましたが学習曲線を眺めているとMetric Learningの比率が高い場合,収束が早く心なし精度の上限が低く,Focal Lossの比率が高い場合,収束が遅かったのではじめはMetric Learningの比率を高めにして(1.0:0.1)epoch数が進むごとにFocal Lossの比率を上げていく(最終的には0.1:1.0)のを実装したところ0.05ほどのスコア改善がありました.鯨7位解法でもMetric LearningしたものをFineTuningするとよかったという話はあったような気がするのでそんな感じです.

per-Image-Normalize

それでも上位陣のスコアに程遠く,データやdiscussionを見ているとtrainとtestで明るさがかなり違うことに気が付いたのでクジラコンペ3位解法で用いられている画像ごとにNormalizeする手法を使うことでCV:0.6 -> LB: 0.55 -> 0.65(Leak)に改善しました.このころからCVスコアがある程度信用できるようになりました.

Data Augmentationの再考

コントラストや明るさを使ったデータ増強を用いましたが精度が低下しました. また,試したのはこの時点ではないですがShiftScaleRotateなども試しましたが精度がよくありませんでした. 90, 180, 270, 360 rotateを追加し,多少のスコア向上を得ました.

Cell Typeの分布でFocal Lossを重み付け

機能しませんでした.

GlobalConcatPooling(GAP+GMP)の実装

機能しませんでした.おそらくパラメータ数を落としすぎたためな気がします.

EfficientNet・DenseNet169・SEResNext101

機能しませんでした.DenseNet169とSEResNext101は過学習していました.EfficientNetは学習率を変えたりしていましたがうまく学習させることができませんでした.

ベースモデルの学習率を落とす

学習時のCVの上限が明らかに低下したのでsubmissionを作成しませんでした.

random crop から 画像全体を見るためにresizeに

CVは向上しましたがLBは低下しました.

Pseudo Labeling

上記までのDenseNet121で推定した結果の確信度が高いものの上位をtrainデータの1/5のtestからtrainに加えました.CV:0.67 -> LB:0.6 -> 0.689(Leak)に改善されました.

線形割り当て

終了3日前、ダメもとでHungarian Algolismを用いた線形割り当てを試したところLB:0.822に改善することができました.これに気づかなかったら銅メダルで終わっていたと思います.

Test Time Augmentation

上記のrandom cropをTestの時も使用していたので常にinputが違う画像になっていました.そのためかTest Time Augmentationの効果が大きかったと考えられます.最終日はTTAを増やしてスコアを上げて遊んでいました.

最終的なモデルまとめ

  • input: 6x256x256
  • model: DenseNet121(Leak+Pseudo Labeling+線形割り当て)をPseudo Labelingに用いたSEResNext50(Leakと線形割り当て込み)
  • Data Augmentation:random_flip+random_crop(size=(256, 256))+90rotate
  • per-Image-Normalize
  • 4Fold
  • LR: 0.04(54epoch目、63epoch目で0.1倍)
  • 32TTA
    • trainと同じaugmentationを使用
    • 上記のrandom cropのおかげでTTAの効果が大きかった(と考えられる)
  • CV:0.72 -> LB0.869

ソースコード

GitHub上にあるのですが最終盤で崩壊しかけたので整理して後日上げます......

追記

ここにあげました.

github.com

最後に

とても色々な学びがあり,楽しいコンペティションでした.改めて全てのwinnerに賞賛を,何より開催してくれたkaggleチームの方々に感謝します.
次は雲か脳かをやると思いますがファッションコンペの復讐復習をしたいので雲に気持ちが傾いています.読んでいただいた方もリーダーボードで会えることを楽しみにしています.参加された皆さん、お疲れ様でした!!!

低温調理機『ANOVA』で樹脂を染色する

今年の11月に私の誕生日があったのですが、自分への誕生日プレゼントとして低温調理機『ANOVA』を購入しました.

New: Anova Precision Cooker - WIFI 2nd Gen (900 Watts)

New: Anova Precision Cooker - WIFI 2nd Gen (900 Watts)

自分が購入したのはBluetoothで通信するリンクより1段階下のグレードのものなのですが,主に肉を調理するのに使っています.
f:id:tattaka5X:20171224132350j:plain
f:id:tattaka5X:20171224132429j:plain
f:id:tattaka5X:20171224132435j:plain

この器具を使えば簡単に樹脂のパーツなどの染色ができるのではと考えたので,やってみました.

準備

染めるパーツ

自分が作っているマイクロマウスというロボットで用いるパーツです.DMM.makeの3Dプリントサービスに造形してもらいました.
f:id:tattaka5X:20171224133536j:plain
make.dmm.com

染料

樹脂用染料『SDN』を使いました.キッチンが汚い
f:id:tattaka5X:20171224133632j:plain
ジップロックでパッケージングし、パーツを入れます.
f:id:tattaka5X:20171224133659j:plain
寸胴鍋に水を入れて予備加熱していきます.
f:id:tattaka5X:20171224133824j:plain

染色

予備加熱が終わったら袋の口がちゃんと閉まっているのを確認してから鍋に入れます.
f:id:tattaka5X:20171224133810j:plain

今回は20分ほど加熱しました.
引き上げて触れる温度になるまで冷まし、取り出します.
f:id:tattaka5X:20171224135237j:plainf:id:tattaka5X:20171224135246j:plain

乾かします.
良いのでは
f:id:tattaka5X:20171224135419j:plain

最後に、新しいジップロックに染料を詰め直し、大きめのジップロックに入れて保存します.
f:id:tattaka5X:20171224135654j:plain

反省点

→次からは袋を二重にしてやりましょう(泣きながら鍋を洗剤で洗った)

  • 造形する時に底になってた部分の染めムラがひどい

f:id:tattaka5X:20171224135937j:plain
→紙やすりでやすったらマシになるのでは?

まとめ-低温調理機で染色をやると何が嬉しいか-

  • 使う染料の量を最低限にできる
  • 手をあまり汚さずに作業できる

自分が良く使うHALの関数について自分なりの解説(というかメモ書き)

この記事はstm32 Advent Calendar 2017の10日目の投稿です.
自分が普段よく使うHALの関数について、使い方を忘れてもここを見ればわかるよう備忘録がわりに記していきます。

GPIO

関数 HAL_GPIO_WritePin (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
ヘッダ stm32f4xx_hal_gpio.h
型名 void
機能 Pinstate(High: GPIO_PIN_SET, Low: GPIO_PIN_RESET)を操作する
HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, GPIO_PIN_SET)
関数 HAL_GPIO_TogglePin (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
ヘッダ stm32f4xx_hal_gpio.h
型名 void
機能 Pinstateを反転させる
HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_1)
関数 HAL_GPIO_ReadPin (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
ヘッダ stm32f4xx_hal_gpio.h
型名 GPIO_PinState
機能 指定したピン(インプットモード)の状態を読み取る
HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1)

Timer

ベース
関数 HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 指定した構造体でタイマを設定する
HAL_TIM_Base_Init(&htim1, TIM_CHANNEL_1)
関数 HAL_TIM_Base_Start (TIM_HandleTypeDef *htim)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 指定したタイマを有効にする(割り込みは有効にならない?)
HAL_TIM_Base_Start(&htim1)
関数 HAL_TIM_Base_Stop (TIM_HandleTypeDef *htim)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 指定したタイマをストップさせる
HAL_TIM_Base_Stop(&htim1)
関数 HAL_TIM_Base_Start_IT (TIM_HandleTypeDef *htim)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 割り込みを有効にしてから指定したタイマを有効にする
HAL_TIM_Base_Start_IT(&htim1)
関数 HAL_TIM_Base_Stop_IT (TIM_HandleTypeDef *htim)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 割り込みを無効にしてから指定したタイマをストップさせる
HAL_TIM_Base_Stop_IT(&htim1)
PWM
関数 HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef* sConfig, uint32_t Channel)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 指定したタイマ・チャンネルでPWMを設定する
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1)(sConfigOCはPWM設定のための構造体)
関数 HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 指定したパルスとデューティでPWM波を出力する
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1)
関数 HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 出力されているPWM波を止める
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1)
ADC
関数 HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 指定したADCを設定する
HAL_ADC_ConfigChannel(&hadc1, &sConfig)(sConfigOCはADC設定のための構造体)
関数 HAL_ADC_Start(ADC_HandleTypeDef* hadc)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 ADCをスタートさせる(割り込みは有効化されない)
HAL_ADC_Start(&hadc1)
関数 HAL_ADC_Stop(ADC_HandleTypeDef* hadc)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 ADCをストップさせる
HAL_ADC_Stop(&hadc1)
関数 HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 ADCをスタートさせ割り込みを有効化する
HAL_ADC_Start_IT(&hadc1)
関数 HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 ADCをストップさせ割り込みを無効化する
HAL_ADC_Stop_IT(&hadc1)
関数 HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 ADCをDMAモードでスタートさせる
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)sensor_value, SENSOR_NUM)(sensor_valueは格納用の配列、SENSOR_NUMは行うADCの数)
関数 HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc)
ヘッダ stm32f4xx_hal_adc.h
型名 HAL_StatusTypeDef
機能 DMAモードで動いているADCをストップさせる
HAL_ADC_Start_DMA(&hadc1)
Encoder Interface

エンコーダの値を知りたければTIMx->CNTにアクセスする

関数 HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
ヘッダ stm32f4xx_hal_tim.h
型名 HAL_StatusTypeDef
機能 エンコーダインフェース有効化し読み取りをスタートさせる
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL)(2相エンコーダの場合両方読み取る)

SPI

関数 HAL_SPI_Init(SPI_HandleTypeDef *hspi)
ヘッダ stm32f4xx_hal_spi.h
型名 HAL_StatusTypeDef
機能 指定した構造体でSPIを設定する
HAL_SPI_Init(&hspi1)
関数 HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
ヘッダ stm32f4xx_hal_spi.h
型名 HAL_StatusTypeDef
機能 Sizeで送信するデータ数を決め、pTxDataをスレーブに送り、帰ってきたデータをpRxDataに格納する
HAL_SPI_TransmitReceive(&hspi1, send_data, rcv_data, size, 100)

UART

関数 HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
ヘッダ stm32f4xx_hal_uart.h
型名 HAL_StatusTypeDef
機能 Sizeで送信するデータ数を決め、pTxDataをスレーブに送る
HAL_UART_Transmit(&huart1, &char, 1, 1)