- 改めてクロップした画像を見ていたところ、写ってる範囲が違う画像ペアだとクロップしても無駄な領域があることに気付きました
- 例えば↓みたいな画像ペアの場合、左の画像は右の画像よりも写っている範囲が広いので、建物部分だけをクロップしても無駄な領域が残ります
どんなコンペ?
ざっくり言うと、同じ建物を撮影した2枚の画像が与えられたときに、それぞれの画像を撮影したカメラの相対位置関係(F行列)の推定精度を競うコンペでした。
F行列を求める方法はいくつかありますが、基本的には2つの画像のマッチング点(同じ物体がそれぞれの画像に映る点)を求めて、RANSACで外れ値を除去して妥当なF行列を計算するという流れになります。外れ値の除去やF行列の計算はOpenCVの cv2.findFundamentalMat で行うことができるので、いかに上手くマッチング点を求めるかというところがこのコンペでは重要な部分になっていました。
もっと詳しいコンペの解説は@fam_taroさんが公開してくださっているQiitaの記事がとても分かりやすいので、興味がある方はぜひそちらの記事を見ることをオススメします。
1stソリューションの要点
- 通常画像でマッチング
- 得られたマッチング点をクラスタリングして2枚の画像の共通部分をクロップ
- クロップした画像同士で再マッチング
- 1で得られた通常画像のマッチング点と3で得られたクロップ画像のマッチング点を連結してF行列を計算
- 共通部分のクロップ(mkpt crop)
- 複数モデル(LoFTR、SuperGlue、DKM)のアンサンブル
- 入力解像度を複数使用
コンペ参戦記
- 前置きが長くなりましたが、ここからがこの記事を書いた目的になります
- 最終的なソリューションはすでに紹介した通りですが、コンペ中にどんなことを考えて試行錯誤していたか紹介できればと思います
1. コンペ参加〜基礎知識の勉強(4/25〜4/27)
- 4月末まで参加してたコンペが終わって、次のコンペを漁っている時にたまたま見つけました
- 画像マッチングは未知の領域でしたが、たまたま興味が湧いていたのと、言っても画像分野なのである程度戦えるだろうと思い、勉強の一環として参加することにしました
- 特にこちらのQiita記事がとても分かりやすく、F行列のイメージをつかむことができました。
2. CV検証環境の準備〜初サブミット(4/28〜5/5)
- 原因は参考にしていたノートブックに足りない処理(リサイズした画像同士で求めたマッチング点をリスケールせずにF行列計算していた)があったことでした
- 当時はすぐに気づけず色んな実験を繰り返してディスカッションに投げてました
- その時のやり取りはここで見れるので、興味のある方はご覧ください
- ここでだいぶ時間を使ってしまいましたが、マッチング結果を確認する簡易UIとか、その後の検証でも使えるコードを整備できたので、このタイミングで色々実験していたのは結果的に良かったと思います
- あまり期待していませんでいたが、当時の銀圏スコアが出て喜んでました
- ここで運よく良いスコアが出たので本腰を入れて取り組み始めました
3. 仮説を立てる(5/6〜5/7)
仮説1: スコアが低い画像はマッチングの誤対応が多い → (結果△)株の基礎知識
- スコアが低い画像ペアには何かしら共通点があるだろうという見込みから簡単な仮説を立てました
- スコアごとに画像ペアを集めてマッチング点を一つずつ目視で確認して検証をしました
- 結果は微妙で、たしかに誤対応もありましたが割合はそれほど多くなかったです(ただ、この発見は後々のアイデアに活きてきて優勝のキーになりました)
- 実際のマッチング結果を見てもスコアの良し悪しと結果の差が自分には分からなかったので、スコアが低いペアから共通点を見出すのは一旦諦めました
仮説2: 株の基礎知識 誤対応点を削除すればスコアが上がる → (結果○)
-
株の基礎知識
- 仮説1の検証の結果、スコアの大小に関わらず誤対応をしているケースは見受けられたので、手動で誤対応点を削除してスコアをいくつか出してみました
- 結果は例外はあるものの基本的には不要なマッチング点を削除するとスコアが上がる傾向を示しました
4. 仮説に基づいて改善案を検討〜高速化(5/8〜5/15)
改善案1: スコアが低いマッチング点を足切り → (結果×)
- 当時使用していたマッチングモデル(LoFTR)は各マッチング点の信頼度も出力していたのですが、外れ値は信頼度が低いと仮定して、信頼度の低い点を削除してみました
- 結果は全然ダメでスコアが下がりました
- そのあとの検証で分かりましたが、信頼度と外れ値かどうかにはあまり相関が無かったので、LoFTRの信頼度をベースに改善をするのは悪手だったと思います
改善案2: NMSでマッチング点を間引き → (結果×)
- まだ信頼度の検証をする前で、再び信頼度ベースの改善を試してました
- 改善案1と同じ理由で上手くいかなかったです
改善案3: セグメンテーションでクロップ → (結果○)
- 改めてマッチング結果を確認してみて、誤対応している多くは空や道路、人など本来一致しないはずの領域にマッチングしているパターンが多いことに気付きました
- セグメンテーションして不要な領域をあらかじめ除外すれば誤対応を抑制できるのではと考えます
- 全体的にかなり適当な実装をしていたので、一旦ここで最適化することにしました
- ボトルネックになってそうなところを片っ端から潰していったら約3倍くらい高速になりました
- ちなみにこの段階でRANSACのパラメータも精度がなるべく変わらずに高速になるよう調整したのですが、その後の検証も高速に回せるようになったので早めに調整して良かったと感じてます
- ただ、最初からスコアアップしたわけではなく、いくつか調整が必要でした
- 最初は不要な領域にマスクをかけた画像でマッチングをしてみたのですが、これだと大幅にスコアが下がっていました。おそらく、マスクをかけた時にオブジェクトのエッジ部分の情報を欠落させてしまったためだと思われます。
- そこで不要領域をマスクした画像ではなく、建物部分だけをクロップした画像でマッチングする方式に切り替えてスコアアップを実現しました
- ちなみに最終ソリューションでも採用しているオリジナル画像のマッチング結果もアンサンブルするというアイデアはこの時点で思い付きました
- 小さかったり複雑な形状をしているオブジェクトは上手くセグメンテーションできないことは学習データに対する結果で分かっていました
- セグメンテーション自体の性能向上をすることも考えましたが、少し試してみて一筋縄ではいかなそうなこと、そもそもコンペの本質から外れる気がしたのでこの方針は早々に止めました
- オリジナル画像のマッチング点を加えると誤対応点が増えるので仮説の方針と反するとも思いましたが、クロップ画像のマッチング点のおかげで正常対応点の割合が増えるので多少の誤対応は RANSACが弾いてくれるのでは?と思い、オリジナル画像のマッチング点を加えることを試してみました
- 結果、だいぶスコアが良くなったのでオリジナル画像を組み合わせる方針を採用していました
5. アンサンブル導入〜金圏突入(5/16〜5/19)
- セグメンテーションクロップの調整がひと段落して手持ちのアイデアが無くなったので、ディスカッションで紹介されていたIMC2021の上位者が公開している論文を読み漁ってました
- その中で紹介されていたLoFTRのマッチングにSuperPointを組み込む工夫が気になって実装にチャレンジしました
- が、上手く実装できずLoFTRにSuperPointを組み込むのは早々に諦めます
- ただ、実装に挑戦してる中でSuperPoint+SuperGlueの公開ノートブックを読み込んでいたので、せっかくなのでモデルをアンサンブルしてみることにしました
- このアンサンブルがかなり効果を発揮して当時のギリギリ金圏スコアを出せました(0.816くらい)
- 下手に金圏に入ったことで「順位を落としたくない」という心理が働いてパラメータ調整に執心していましたが、今思い返すとこれは悪手だったかなと思います
- 基本的にパラメータ調整で可能な上げ幅はたかが知れてるので、最上位と越えられない壁を感じたら自分が気づいていない何かがあるはずなので、それを探すことに注力した方が建設的だったかなと思います
6. 新たな改善案検討〜金圏復帰(5/20〜5/26)
パラメータ調整に必死になっていると、案の定銀圏に落ちました。
「最後に上位にいることが大事」と自分に言い聞かせて、新たな改善案の検討に着手します。
改めてマッチング結果や今までの実験結果を振り返って、2つの課題を洗い出しました。課題1: クロップしても無駄な領域が多い
- 改めてクロップした画像を見ていたところ、写ってる範囲が違う画像ペアだとクロップしても無駄な領域があることに気付きました
- 例えば↓みたいな画像ペアの場合、左の画像は右の画像よりも写っている範囲が広いので、建物部分だけをクロップしても無駄な領域が残ります
どんなコンペ?
ざっくり言うと、同じ建物を撮影した2枚の画像が与えられたときに、それぞれの画像を撮影したカメラの相対位置関係(F行列)の推定精度を競うコンペでした。
F行列を求める方法はいくつかありますが、基本的には2つの画像のマッチング点(同じ物体がそれぞれの画像に映る点)を求めて、RANSACで外れ値を除去して妥当なF行列を計算するという流れになります。外れ値の除去やF行列の計算はOpenCVの cv2.findFundamentalMat で行うことができるので、いかに上手くマッチング点を求めるかというところがこのコンペでは重要な部分になっていました。
もっと詳しいコンペの解説は@fam_taroさんが公開してくださっているQiitaの記事がとても分かりやすいので、興味がある方はぜひそちらの記事を見ることをオススメします。 株の基礎知識1stソリューションの要点
- 通常画像でマッチング
- 得られたマッチング点をクラスタリングして2枚の画像の共通部分をクロップ
- クロップした画像同士で再マッチング
- 1で得られた通常画像のマッチング点と3で得られたクロップ画像のマッチング点を連結してF行列を計算
- 共通部分のクロップ(mkpt crop)
- 複数モデル(LoFTR、SuperGlue、DKM)のアンサンブル
- 入力解像度を複数使用
コンペ参戦記
- 前置きが長くなりましたが、ここからがこの記事を書いた目的になります
- 最終的なソリューションはすでに紹介した通りですが、コンペ中にどんなことを考えて試行錯誤していたか紹介できればと思います
1. コンペ参加〜基礎知識の勉強(4/25〜4/27)
- 4月末まで参加してたコンペが終わって、次のコンペを漁っている時にたまたま見つけました 株の基礎知識
- 画像マッチングは未知の領域でしたが、たまたま興味が湧いていたのと、言っても画像分野なのである程度戦えるだろうと思い、勉強の一環として参加することにしました
- 特にこちらのQiita記事がとても分かりやすく、F行列のイメージをつかむことができました。
2. CV検証環境の準備〜初サブミット(4/28〜5/5)
- 原因は参考にしていたノートブックに足りない処理(リサイズした画像同士で求めたマッチング点をリスケールせずにF行列計算していた)があったことでした
- 当時はすぐに気づけず色んな実験を繰り返してディスカッションに投げてました
- その時のやり取りはここで見れるので、興味のある方はご覧ください
- ここでだいぶ時間を使ってしまいましたが、マッチング結果を確認する簡易UIとか、その後の検証でも使えるコードを整備できたので、このタイミングで色々実験していたのは結果的に良かったと思います
- あまり期待していませんでいたが、当時の銀圏スコアが出て喜んでました
- ここで運よく良いスコアが出たので本腰を入れて取り組み始めました
3. 仮説を立てる(5/6〜5/7)
仮説1: スコアが低い画像はマッチングの誤対応が多い → (結果△)
- スコアが低い画像ペアには何かしら共通点があるだろうという見込みから簡単な仮説を立てました
- スコアごとに画像ペアを集めてマッチング点を一つずつ目視で確認して検証をしました
- 結果は微妙で、たしかに誤対応もありましたが割合はそれほど多くなかったです(ただ、この発見は後々のアイデアに活きてきて優勝のキーになりました)
- 実際のマッチング結果を見てもスコアの良し悪しと結果の差が自分には分からなかったので、スコアが低いペアから共通点を見出すのは一旦諦めました
仮説2: 誤対応点を削除すればスコアが上がる → (結果○)
- 仮説1の検証の結果、スコアの大小に関わらず誤対応をしているケースは見受けられたので、手動で誤対応点を削除してスコアをいくつか出してみました 株の基礎知識
- 結果は例外はあるものの基本的には不要なマッチング点を削除するとスコアが上がる傾向を示しました
4. 仮説に基づいて改善案を検討〜高速化(5/8〜5/15)
改善案1: スコアが低いマッチング点を足切り → (結果×)
- 当時使用していたマッチングモデル(LoFTR)は各マッチング点の信頼度も出力していたのですが、外れ値は信頼度が低いと仮定して、信頼度の低い点を削除してみました
- 結果は全然ダメでスコアが下がりました
- そのあとの検証で分かりましたが、信頼度と外れ値かどうかにはあまり相関が無かったので、LoFTRの信頼度をベースに改善をするのは悪手だったと思います
改善案2: NMSでマッチング点を間引き → (結果×)
- まだ信頼度の検証をする前で、再び信頼度ベースの改善を試してました
- 改善案1と同じ理由で上手くいかなかったです
改善案3: セグメンテーションでクロップ → (結果○)
- 改めてマッチング結果を確認してみて、誤対応している多くは空や道路、人など本来一致しないはずの領域にマッチングしているパターンが多いことに気付きました
- セグメンテーションして不要な領域をあらかじめ除外すれば誤対応を抑制できるのではと考えます
- 全体的にかなり適当な実装をしていたので、一旦ここで最適化することにしました
- ボトルネックになってそうなところを片っ端から潰していったら約3倍くらい高速になりました
- ちなみにこの段階でRANSACのパラメータも精度がなるべく変わらずに高速になるよう調整したのですが、その後の検証も高速に回せるようになったので早めに調整して良かったと感じてます
- ただ、最初からスコアアップしたわけではなく、いくつか調整が必要でした
- 最初は不要な領域にマスクをかけた画像でマッチングをしてみたのですが、これだと大幅にスコアが下がっていました。おそらく、マスクをかけた時にオブジェクトのエッジ部分の情報を欠落させてしまったためだと思われます。
- そこで不要領域をマスクした画像ではなく、建物部分だけをクロップした画像でマッチングする方式に切り替えてスコアアップを実現しました
- ちなみに最終ソリューションでも採用しているオリジナル画像のマッチング結果もアンサンブルするというアイデアはこの時点で思い付きました
- 小さかったり複雑な形状をしているオブジェクトは上手くセグメンテーションできないことは学習データに対する結果で分かっていました
- セグメンテーション自体の性能向上をすることも考えましたが、少し試してみて一筋縄ではいかなそうなこと、そもそもコンペの本質から外れる気がしたのでこの方針は早々に止めました
- オリジナル画像のマッチング点を加えると誤対応点が増えるので仮説の方針と反するとも思いましたが、クロップ画像のマッチング点のおかげで正常対応点の割合が増えるので多少の誤対応は 株の基礎知識 RANSACが弾いてくれるのでは?と思い、オリジナル画像のマッチング点を加えることを試してみました
- 結果、だいぶスコアが良くなったのでオリジナル画像を組み合わせる方針を採用していました
5. アンサンブル導入〜金圏突入(5/16〜5/19)
- セグメンテーションクロップの調整がひと段落して手持ちのアイデアが無くなったので、ディスカッションで紹介されていたIMC2021の上位者が公開している論文を読み漁ってました
- その中で紹介されていたLoFTRのマッチングにSuperPointを組み込む工夫が気になって実装にチャレンジしました
- が、上手く実装できずLoFTRにSuperPointを組み込むのは早々に諦めます
- ただ、実装に挑戦してる中でSuperPoint+SuperGlueの公開ノートブックを読み込んでいたので、せっかくなのでモデルをアンサンブルしてみることにしました
- このアンサンブルがかなり効果を発揮して当時のギリギリ金圏スコアを出せました(0.816くらい)
- 下手に金圏に入ったことで「順位を落としたくない」という心理が働いてパラメータ調整に執心していましたが、今思い返すとこれは悪手だったかなと思います
- 基本的にパラメータ調整で可能な上げ幅はたかが知れてるので、最上位と越えられない壁を感じたら自分が気づいていない何かがあるはずなので、それを探すことに注力した方が建設的だったかなと思います
6. 新たな改善案検討〜金圏復帰(5/20〜5/26)
パラメータ調整に必死になっていると、案の定銀圏に落ちました。
「最後に上位にいることが大事」と自分に言い聞かせて、新たな改善案の検討に着手します。
改めてマッチング結果や今までの実験結果を振り返って、2つの課題を洗い出しました。課題1: クロップしても無駄な領域が多い
- 改めてクロップした画像を見ていたところ、写ってる範囲が違う画像ペアだとクロップしても無駄な領域があることに気付きました
- 例えば↓みたいな画像ペアの場合、左の画像は右の画像よりも写っている範囲が広いので、建物部分だけをクロップしても無駄な領域が残ります
どんなコンペ?
ざっくり言うと、同じ建物を撮影した2枚の画像が与えられたときに、それぞれの画像を撮影したカメラの相対位置関係(F行列)の推定精度を競うコンペでした。
F行列を求める方法はいくつかありますが、基本的には2つの画像のマッチング点(同じ物体がそれぞれの画像に映る点)を求めて、RANSACで外れ値を除去して妥当なF行列を計算するという流れになります。外れ値の除去やF行列の計算はOpenCVの cv2.findFundamentalMat で行うことができるので、いかに上手くマッチング点を求めるかというところがこのコンペでは重要な部分になっていました。
もっと詳しいコンペの解説は@fam_taroさんが公開してくださっているQiitaの記事がとても分かりやすいので、興味がある方はぜひそちらの記事を見ることをオススメします。1stソリューションの要点
- 通常画像でマッチング
- 得られたマッチング点をクラスタリングして2枚の画像の共通部分をクロップ
- クロップした画像同士で再マッチング
- 1で得られた通常画像のマッチング点と3で得られたクロップ画像のマッチング点を連結してF行列を計算
- 共通部分のクロップ(mkpt crop)
- 複数モデル(LoFTR、SuperGlue、DKM)のアンサンブル
- 入力解像度を複数使用
コンペ参戦記
- 前置きが長くなりましたが、ここからがこの記事を書いた目的になります
- 最終的なソリューションはすでに紹介した通りですが、コンペ中にどんなことを考えて試行錯誤していたか紹介できればと思います
1. コンペ参加〜基礎知識の勉強(4/25〜4/27)
- 4月末まで参加してたコンペが終わって、次のコンペを漁っている時にたまたま見つけました
- 画像マッチングは未知の領域でしたが、たまたま興味が湧いていたのと、言っても画像分野なのである程度戦えるだろうと思い、勉強の一環として参加することにしました
- 特にこちらのQiita記事がとても分かりやすく、F行列のイメージをつかむことができました。
2. CV検証環境の準備〜初サブミット(4/28〜5/5)
- 原因は参考にしていたノートブックに足りない処理(リサイズした画像同士で求めたマッチング点をリスケールせずにF行列計算していた)があったことでした
- 当時はすぐに気づけず色んな実験を繰り返してディスカッションに投げてました
- その時のやり取りはここで見れるので、興味のある方はご覧ください
- ここでだいぶ時間を使ってしまいましたが、マッチング結果を確認する簡易UIとか、その後の検証でも使えるコードを整備できたので、このタイミングで色々実験していたのは結果的に良かったと思います
- あまり期待していませんでいたが、当時の銀圏スコアが出て喜んでました
- ここで運よく良いスコアが出たので本腰を入れて取り組み始めました
3. 仮説を立てる(5/6〜5/7)
仮説1: スコアが低い画像はマッチングの誤対応が多い → (結果△)
- スコアが低い画像ペアには何かしら共通点があるだろうという見込みから簡単な仮説を立てました
- スコアごとに画像ペアを集めてマッチング点を一つずつ目視で確認して検証をしました
- 結果は微妙で、たしかに誤対応もありましたが割合はそれほど多くなかったです(ただ、この発見は後々のアイデアに活きてきて優勝のキーになりました)
- 実際のマッチング結果を見てもスコアの良し悪しと結果の差が自分には分からなかったので、スコアが低いペアから共通点を見出すのは一旦諦めました
仮説2: 誤対応点を削除すればスコアが上がる → (結果○)
- 仮説1の検証の結果、スコアの大小に関わらず誤対応をしているケースは見受けられたので、手動で誤対応点を削除してスコアをいくつか出してみました
- 結果は例外はあるものの基本的には不要なマッチング点を削除するとスコアが上がる傾向を示しました
4. 仮説に基づいて改善案を検討〜高速化(5/8〜5/15)
改善案1: スコアが低いマッチング点を足切り → (結果×)
- 当時使用していたマッチングモデル(LoFTR)は各マッチング点の信頼度も出力していたのですが、外れ値は信頼度が低いと仮定して、信頼度の低い点を削除してみました
- 結果は全然ダメでスコアが下がりました
- そのあとの検証で分かりましたが、信頼度と外れ値かどうかにはあまり相関が無かったので、LoFTRの信頼度をベースに改善をするのは悪手だったと思います
改善案2: NMSでマッチング点を間引き → (結果×)
- まだ信頼度の検証をする前で、再び信頼度ベースの改善を試してました
- 改善案1と同じ理由で上手くいかなかったです
改善案3: 株の基礎知識 セグメンテーションでクロップ → (結果○)
- 改めてマッチング結果を確認してみて、誤対応している多くは空や道路、人など本来一致しないはずの領域にマッチングしているパターンが多いことに気付きました 株の基礎知識
- セグメンテーションして不要な領域をあらかじめ除外すれば誤対応を抑制できるのではと考えます
- 全体的にかなり適当な実装をしていたので、一旦ここで最適化することにしました
- ボトルネックになってそうなところを片っ端から潰していったら約3倍くらい高速になりました
- ちなみにこの段階でRANSACのパラメータも精度がなるべく変わらずに高速になるよう調整したのですが、その後の検証も高速に回せるようになったので早めに調整して良かったと感じてます
- ただ、最初からスコアアップしたわけではなく、いくつか調整が必要でした
- 最初は不要な領域にマスクをかけた画像でマッチングをしてみたのですが、これだと大幅にスコアが下がっていました。おそらく、マスクをかけた時にオブジェクトのエッジ部分の情報を欠落させてしまったためだと思われます。
- そこで不要領域をマスクした画像ではなく、建物部分だけをクロップした画像でマッチングする方式に切り替えてスコアアップを実現しました
- ちなみに最終ソリューションでも採用しているオリジナル画像のマッチング結果もアンサンブルするというアイデアはこの時点で思い付きました
- 小さかったり複雑な形状をしているオブジェクトは上手くセグメンテーションできないことは学習データに対する結果で分かっていました
- セグメンテーション自体の性能向上をすることも考えましたが、少し試してみて一筋縄ではいかなそうなこと、そもそもコンペの本質から外れる気がしたのでこの方針は早々に止めました
- オリジナル画像のマッチング点を加えると誤対応点が増えるので仮説の方針と反するとも思いましたが、クロップ画像のマッチング点のおかげで正常対応点の割合が増えるので多少の誤対応は RANSACが弾いてくれるのでは?と思い、オリジナル画像のマッチング点を加えることを試してみました
- 結果、だいぶスコアが良くなったのでオリジナル画像を組み合わせる方針を採用していました
5. アンサンブル導入〜金圏突入(5/16〜5/19)
- セグメンテーションクロップの調整がひと段落して手持ちのアイデアが無くなったので、ディスカッションで紹介されていたIMC2021の上位者が公開している論文を読み漁ってました
- その中で紹介されていたLoFTRのマッチングにSuperPointを組み込む工夫が気になって実装にチャレンジしました
- が、上手く実装できずLoFTRにSuperPointを組み込むのは早々に諦めます
- ただ、実装に挑戦してる中でSuperPoint+SuperGlueの公開ノートブックを読み込んでいたので、せっかくなのでモデルをアンサンブルしてみることにしました
- このアンサンブルがかなり効果を発揮して当時のギリギリ金圏スコアを出せました(0.816くらい)
- 下手に金圏に入ったことで「順位を落としたくない」という心理が働いてパラメータ調整に執心していましたが、今思い返すとこれは悪手だったかなと思います
- 基本的にパラメータ調整で可能な上げ幅はたかが知れてるので、最上位と越えられない壁を感じたら自分が気づいていない何かがあるはずなので、それを探すことに注力した方が建設的だったかなと思います
6. 新たな改善案検討〜金圏復帰(5/20〜5/26)
パラメータ調整に必死になっていると、案の定銀圏に落ちました。
「最後に上位にいることが大事」と自分に言い聞かせて、新たな改善案の検討に着手します。
改めてマッチング結果や今までの実験結果を振り返って、2つの課題を洗い出しました。課題1: クロップしても無駄な領域が多い
- 改めてクロップした画像を見ていたところ、写ってる範囲が違う画像ペアだとクロップしても無駄な領域があることに気付きました
- 例えば↓みたいな画像ペアの場合、左の画像は右の画像よりも写っている範囲が広いので、建物部分だけをクロップしても無駄な領域が残ります
どんなコンペ?
ざっくり言うと、同じ建物を撮影した2枚の画像が与えられたときに、それぞれの画像を撮影したカメラの相対位置関係(F行列)の推定精度を競うコンペでした。
F行列を求める方法はいくつかありますが、基本的には2つの画像のマッチング点(同じ物体がそれぞれの画像に映る点)を求めて、RANSACで外れ値を除去して妥当なF行列を計算するという流れになります。外れ値の除去やF行列の計算はOpenCVの cv2.findFundamentalMat で行うことができるので、いかに上手くマッチング点を求めるかというところがこのコンペでは重要な部分になっていました。
もっと詳しいコンペの解説は@fam_taroさんが公開してくださっているQiitaの記事がとても分かりやすいので、興味がある方はぜひそちらの記事を見ることをオススメします。1stソリューションの要点
- 通常画像でマッチング
- 得られたマッチング点をクラスタリングして2枚の画像の共通部分をクロップ
- クロップした画像同士で再マッチング
- 1で得られた通常画像のマッチング点と3で得られたクロップ画像のマッチング点を連結してF行列を計算
- 共通部分のクロップ(mkpt crop)
- 複数モデル(LoFTR、SuperGlue、DKM)のアンサンブル
- 入力解像度を複数使用
コンペ参戦記
- 前置きが長くなりましたが、ここからがこの記事を書いた目的になります
- 最終的なソリューションはすでに紹介した通りですが、コンペ中にどんなことを考えて試行錯誤していたか紹介できればと思います
1. コンペ参加〜基礎知識の勉強(4/25〜4/27)
- 4月末まで参加してたコンペが終わって、次のコンペを漁っている時にたまたま見つけました
- 画像マッチングは未知の領域でしたが、たまたま興味が湧いていたのと、言っても画像分野なのである程度戦えるだろうと思い、勉強の一環として参加することにしました
- 特にこちらのQiita記事がとても分かりやすく、F行列のイメージをつかむことができました。
2. CV検証環境の準備〜初サブミット(4/28〜5/5)
- 原因は参考にしていたノートブックに足りない処理(リサイズした画像同士で求めたマッチング点をリスケールせずにF行列計算していた)があったことでした
- 当時はすぐに気づけず色んな実験を繰り返してディスカッションに投げてました 株の基礎知識
- その時のやり取りはここで見れるので、興味のある方はご覧ください
- ここでだいぶ時間を使ってしまいましたが、マッチング結果を確認する簡易UIとか、その後の検証でも使えるコードを整備できたので、このタイミングで色々実験していたのは結果的に良かったと思います
- あまり期待していませんでいたが、当時の銀圏スコアが出て喜んでました
- ここで運よく良いスコアが出たので本腰を入れて取り組み始めました
3. 仮説を立てる(5/6〜5/7)
仮説1: スコアが低い画像はマッチングの誤対応が多い → (結果△)
- スコアが低い画像ペアには何かしら共通点があるだろうという見込みから簡単な仮説を立てました
- スコアごとに画像ペアを集めてマッチング点を一つずつ目視で確認して検証をしました
- 結果は微妙で、たしかに誤対応もありましたが割合はそれほど多くなかったです(ただ、この発見は後々のアイデアに活きてきて優勝のキーになりました)
- 実際のマッチング結果を見てもスコアの良し悪しと結果の差が自分には分からなかったので、スコアが低いペアから共通点を見出すのは一旦諦めました
仮説2: 誤対応点を削除すればスコアが上がる → (結果○)
- 仮説1の検証の結果、スコアの大小に関わらず誤対応をしているケースは見受けられたので、手動で誤対応点を削除してスコアをいくつか出してみました
- 結果は例外はあるものの基本的には不要なマッチング点を削除するとスコアが上がる傾向を示しました
4. 仮説に基づいて改善案を検討〜高速化(5/8〜5/15)
改善案1: 株の基礎知識 スコアが低いマッチング点を足切り → (結果×)
- 当時使用していたマッチングモデル(LoFTR)は各マッチング点の信頼度も出力していたのですが、外れ値は信頼度が低いと仮定して、信頼度の低い点を削除してみました
- 結果は全然ダメでスコアが下がりました
- そのあとの検証で分かりましたが、信頼度と外れ値かどうかにはあまり相関が無かったので、LoFTRの信頼度をベースに改善をするのは悪手だったと思います
改善案2: NMSでマッチング点を間引き → (結果×)
- まだ信頼度の検証をする前で、再び信頼度ベースの改善を試してました
- 改善案1と同じ理由で上手くいかなかったです
改善案3: セグメンテーションでクロップ → (結果○)
- 改めてマッチング結果を確認してみて、誤対応している多くは空や道路、人など本来一致しないはずの領域にマッチングしているパターンが多いことに気付きました
- セグメンテーションして不要な領域をあらかじめ除外すれば誤対応を抑制できるのではと考えます
- 全体的にかなり適当な実装をしていたので、一旦ここで最適化することにしました
- ボトルネックになってそうなところを片っ端から潰していったら約3倍くらい高速になりました
- ちなみにこの段階でRANSACのパラメータも精度がなるべく変わらずに高速になるよう調整したのですが、その後の検証も高速に回せるようになったので早めに調整して良かったと感じてます
- ただ、最初からスコアアップしたわけではなく、いくつか調整が必要でした
- 最初は不要な領域にマスクをかけた画像でマッチングをしてみたのですが、これだと大幅にスコアが下がっていました。おそらく、マスクをかけた時にオブジェクトのエッジ部分の情報を欠落させてしまったためだと思われます。
- そこで不要領域をマスクした画像ではなく、建物部分だけをクロップした画像でマッチングする方式に切り替えてスコアアップを実現しました
- ちなみに最終ソリューションでも採用しているオリジナル画像のマッチング結果もアンサンブルするというアイデアはこの時点で思い付きました
- 小さかったり複雑な形状をしているオブジェクトは上手くセグメンテーションできないことは学習データに対する結果で分かっていました
- セグメンテーション自体の性能向上をすることも考えましたが、少し試してみて一筋縄ではいかなそうなこと、そもそもコンペの本質から外れる気がしたのでこの方針は早々に止めました
- オリジナル画像のマッチング点を加えると誤対応点が増えるので仮説の方針と反するとも思いましたが、クロップ画像のマッチング点のおかげで正常対応点の割合が増えるので多少の誤対応は RANSACが弾いてくれるのでは?と思い、オリジナル画像のマッチング点を加えることを試してみました
- 結果、だいぶスコアが良くなったのでオリジナル画像を組み合わせる方針を採用していました
5. アンサンブル導入〜金圏突入(5/16〜5/19)
- セグメンテーションクロップの調整がひと段落して手持ちのアイデアが無くなったので、ディスカッションで紹介されていたIMC2021の上位者が公開している論文を読み漁ってました
- その中で紹介されていたLoFTRのマッチングにSuperPointを組み込む工夫が気になって実装にチャレンジしました
- が、上手く実装できずLoFTRにSuperPointを組み込むのは早々に諦めます
- ただ、実装に挑戦してる中でSuperPoint+SuperGlueの公開ノートブックを読み込んでいたので、せっかくなのでモデルをアンサンブルしてみることにしました
- このアンサンブルがかなり効果を発揮して当時のギリギリ金圏スコアを出せました(0.816くらい)
- 下手に金圏に入ったことで「順位を落としたくない」という心理が働いてパラメータ調整に執心していましたが、今思い返すとこれは悪手だったかなと思います
- 基本的にパラメータ調整で可能な上げ幅はたかが知れてるので、最上位と越えられない壁を感じたら自分が気づいていない何かがあるはずなので、それを探すことに注力した方が建設的だったかなと思います
6. 新たな改善案検討〜金圏復帰(5/20〜5/26)
パラメータ調整に必死になっていると、案の定銀圏に落ちました。
「最後に上位にいることが大事」と自分に言い聞かせて、新たな改善案の検討に着手します。
改めてマッチング結果や今までの実験結果を振り返って、2つの課題を洗い出しました。課題1: クロップしても無駄な領域が多い
- 改めてクロップした画像を見ていたところ、写ってる範囲が違う画像ペアだとクロップしても無駄な領域があることに気付きました
- 例えば↓みたいな画像ペアの場合、左の画像は右の画像よりも写っている範囲が広いので、建物部分だけをクロップしても無駄な領域が残ります
どんなコンペ?
ざっくり言うと、同じ建物を撮影した2枚の画像が与えられたときに、それぞれの画像を撮影したカメラの相対位置関係(F行列)の推定精度を競うコンペでした。
F行列を求める方法はいくつかありますが、基本的には2つの画像のマッチング点(同じ物体がそれぞれの画像に映る点)を求めて、RANSACで外れ値を除去して妥当なF行列を計算するという流れになります。外れ値の除去やF行列の計算はOpenCVの cv2.findFundamentalMat で行うことができるので、いかに上手くマッチング点を求めるかというところがこのコンペでは重要な部分になっていました。
もっと詳しいコンペの解説は@fam_taroさんが公開してくださっているQiitaの記事がとても分かりやすいので、興味がある方はぜひそちらの記事を見ることをオススメします。1stソリューションの要点
- 通常画像でマッチング
- 得られたマッチング点をクラスタリングして2枚の画像の共通部分をクロップ
- クロップした画像同士で再マッチング
- 1で得られた通常画像のマッチング点と3で得られたクロップ画像のマッチング点を連結してF行列を計算
- 共通部分のクロップ(mkpt crop)
- 複数モデル(LoFTR、SuperGlue、DKM)のアンサンブル
- 入力解像度を複数使用
コンペ参戦記
- 前置きが長くなりましたが、ここからがこの記事を書いた目的になります 株の基礎知識 株の基礎知識
- 最終的なソリューションはすでに紹介した通りですが、コンペ中にどんなことを考えて試行錯誤していたか紹介できればと思います
1. コンペ参加〜基礎知識の勉強(4/25〜4/27)
- 4月末まで参加してたコンペが終わって、次のコンペを漁っている時にたまたま見つけました
- 画像マッチングは未知の領域でしたが、たまたま興味が湧いていたのと、言っても画像分野なのである程度戦えるだろうと思い、勉強の一環として参加することにしました
- 特にこちらのQiita記事がとても分かりやすく、F行列のイメージをつかむことができました。
2. CV検証環境の準備〜初サブミット(4/28〜5/5)
- 原因は参考にしていたノートブックに足りない処理(リサイズした画像同士で求めたマッチング点をリスケールせずにF行列計算していた)があったことでした
- 当時はすぐに気づけず色んな実験を繰り返してディスカッションに投げてました
- その時のやり取りはここで見れるので、興味のある方はご覧ください
- ここでだいぶ時間を使ってしまいましたが、マッチング結果を確認する簡易UIとか、その後の検証でも使えるコードを整備できたので、このタイミングで色々実験していたのは結果的に良かったと思います
- あまり期待していませんでいたが、当時の銀圏スコアが出て喜んでました
- ここで運よく良いスコアが出たので本腰を入れて取り組み始めました
3. 仮説を立てる(5/6〜5/7)
仮説1: スコアが低い画像はマッチングの誤対応が多い → (結果△)
- スコアが低い画像ペアには何かしら共通点があるだろうという見込みから簡単な仮説を立てました
- スコアごとに画像ペアを集めてマッチング点を一つずつ目視で確認して検証をしました
- 結果は微妙で、たしかに誤対応もありましたが割合はそれほど多くなかったです(ただ、この発見は後々のアイデアに活きてきて優勝のキーになりました)
- 実際のマッチング結果を見てもスコアの良し悪しと結果の差が自分には分からなかったので、スコアが低いペアから共通点を見出すのは一旦諦めました
仮説2: 誤対応点を削除すればスコアが上がる → (結果○)
- 仮説1の検証の結果、スコアの大小に関わらず誤対応をしているケースは見受けられたので、手動で誤対応点を削除してスコアをいくつか出してみました
- 結果は例外はあるものの基本的には不要なマッチング点を削除するとスコアが上がる傾向を示しました
4. 仮説に基づいて改善案を検討〜高速化(5/8〜5/15)
改善案1: スコアが低いマッチング点を足切り → (結果×)
- 当時使用していたマッチングモデル(LoFTR)は各マッチング点の信頼度も出力していたのですが、外れ値は信頼度が低いと仮定して、信頼度の低い点を削除してみました
- 結果は全然ダメでスコアが下がりました
- そのあとの検証で分かりましたが、信頼度と外れ値かどうかにはあまり相関が無かったので、LoFTRの信頼度をベースに改善をするのは悪手だったと思います
改善案2: NMSでマッチング点を間引き → (株の基礎知識 結果×)
- まだ信頼度の検証をする前で、再び信頼度ベースの改善を試してました
- 改善案1と同じ理由で上手くいかなかったです
改善案3: セグメンテーションでクロップ → (結果○)
- 改めてマッチング結果を確認してみて、誤対応している多くは空や道路、人など本来一致しないはずの領域にマッチングしているパターンが多いことに気付きました
- セグメンテーションして不要な領域をあらかじめ除外すれば誤対応を抑制できるのではと考えます
- 全体的にかなり適当な実装をしていたので、一旦ここで最適化することにしました
- ボトルネックになってそうなところを片っ端から潰していったら約3倍くらい高速になりました
- ちなみにこの段階でRANSACのパラメータも精度がなるべく変わらずに高速になるよう調整したのですが、その後の検証も高速に回せるようになったので早めに調整して良かったと感じてます
- ただ、最初からスコアアップしたわけではなく、いくつか調整が必要でした
- 最初は不要な領域にマスクをかけた画像でマッチングをしてみたのですが、これだと大幅にスコアが下がっていました。おそらく、マスクをかけた時にオブジェクトのエッジ部分の情報を欠落させてしまったためだと思われます。
- そこで不要領域をマスクした画像ではなく、建物部分だけをクロップした画像でマッチングする方式に切り替えてスコアアップを実現しました
- ちなみに最終ソリューションでも採用しているオリジナル画像のマッチング結果もアンサンブルするというアイデアはこの時点で思い付きました
- 小さかったり複雑な形状をしているオブジェクトは上手くセグメンテーションできないことは学習データに対する結果で分かっていました
- セグメンテーション自体の性能向上をすることも考えましたが、少し試してみて一筋縄ではいかなそうなこと、そもそもコンペの本質から外れる気がしたのでこの方針は早々に止めました
- オリジナル画像のマッチング点を加えると誤対応点が増えるので仮説の方針と反するとも思いましたが、クロップ画像のマッチング点のおかげで正常対応点の割合が増えるので多少の誤対応は RANSACが弾いてくれるのでは?と思い、オリジナル画像のマッチング点を加えることを試してみました
- 結果、だいぶスコアが良くなったのでオリジナル画像を組み合わせる方針を採用していました
5. アンサンブル導入〜金圏突入(5/16〜5/19)
- セグメンテーションクロップの調整がひと段落して手持ちのアイデアが無くなったので、ディスカッションで紹介されていたIMC2021の上位者が公開している論文を読み漁ってました
- その中で紹介されていたLoFTRのマッチングにSuperPointを組み込む工夫が気になって実装にチャレンジしました
- が、上手く実装できずLoFTRにSuperPointを組み込むのは早々に諦めます
- ただ、実装に挑戦してる中でSuperPoint+SuperGlueの公開ノートブックを読み込んでいたので、せっかくなのでモデルをアンサンブルしてみることにしました
- このアンサンブルがかなり効果を発揮して当時のギリギリ金圏スコアを出せました(0.816くらい)
- 下手に金圏に入ったことで「順位を落としたくない」という心理が働いてパラメータ調整に執心していましたが、今思い返すとこれは悪手だったかなと思います
- 基本的にパラメータ調整で可能な上げ幅はたかが知れてるので、最上位と越えられない壁を感じたら自分が気づいていない何かがあるはずなので、それを探すことに注力した方が建設的だったかなと思います
6. 新たな改善案検討〜金圏復帰(5/20〜5/26)
パラメータ調整に必死になっていると、案の定銀圏に落ちました。
「最後に上位にいることが大事」と自分に言い聞かせて、新たな改善案の検討に着手します。
改めてマッチング結果や今までの実験結果を振り返って、2つの課題を洗い出しました。課題1: クロップしても無駄な領域が多い
- 改めてクロップした画像を見ていたところ、写ってる範囲が違う画像ペアだとクロップしても無駄な領域があることに気付きました
- 例えば↓みたいな画像ペアの場合、左の画像は右の画像よりも写っている範囲が広いので、建物部分だけをクロップしても無駄な領域が残ります
関連記事
コメント