Kaggle画像コンペでやっていること②

前回の記事[『Kaggle画像コンペでやっていること①』](https://qiita.com/Kmat67916008/items/7aaa41be4e25bace43dc)では、どんなコンペでも大体やることをあげさせていただきましたが、残念ながらみなさん大体やりますんで勝つためにはもう一工夫ほしいところです！

ということで、kaggle advent calender 2024の14日目の記事は、**画像コンペで適用ドメインのことを考えましょう**というお話になります。数回にわけて書かせていただいており、基本的に初級者(Expertぐらい)向けですのでご了承ください。

8日目：[Kaggle画像コンペでやっていること① (タスク関係なくやること)](https://qiita.com/Kmat67916008/items/7aaa41be4e25bace43dc)
14日目：本記事
21日目：21日目：[Kaggle画像コンペでやっていること③](https://qiita.com/Kmat67916008/items/6db4446698a58a6b3f0d)
24日目：[Kaggle画像コンペでやっていること④](https://qiita.com/Kmat67916008/items/d7586a28e6ec8595d579)

# 前回記事の振り返り :information_desk_person:
- どのコンペでも多少のハイパラ調整やアンサンブル、モデル選択なんかはする
- 練度の違いこそあれみんなしている
- 勝つためには、そのコンペ特有の工夫も大事 (⇒本記事)

# ドメインを考えるとは
**深層学習で解きたいタスク固有の特徴を考えましょう**、というお話です。

例えば『画像からバナナを見つけてくれ』と言われたときに、人はどうするでしょうか。黄色いところを探すかもしれません、もしかすると青いバナナもあるかもしれないですし、むいた後の白いバナナを探すかもしれないですね。もしかするとカワも探す対象かもしれないので確認が必要です。

そういった事前知識を人間は持っていますが、深層学習モデルは必ずしも持っているとは限りません(※)。したがって、こういう知識をNNの前後処理やモデルや学習に反映することで、画像コンペマンとしては一皮むけることができます。バナナなだけに。
(※ とはいえ、簡単なタスクであれば、最近の基盤モデルはかなり強い能力を持っています)

ガチッとはまると他の参加者と一気に**差別化**することもできます。個人の主観ですが、『これはソリューションに是非書きたいな！』というぐらいの工夫が２つぐらいはいれば金圏を狙えます。もちろん、Kaggle画像コンペでやっときたいこと①に書いたことをキッチリおさえた前提です。

<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/a486106d-682a-3213-c96a-fa2d53b34b62.png">

# ドメインを考える例
以下のようなものがあると思います。
- **特徴量エンジニアリング (←本ページで紹介)**
- タスク特化のLoss
- タスク特化のAugmentation選定や作成
- タスク特化のモデルアーキテクチャ
- タスク特化のパイプライン

難易度も効果もピンキリですが、順番に紹介していきます。

# ドメイン意識①：特徴量エンジニアリング
深層学習・画像における特徴量エンジニアリングは簡単なようで難しいです。テーブルデータでGBDTなどを使用しているときには、比較的楽に『とりあえず突っ込んでみよう』ができるのですが、深層学習モデルは思ったほどやさしくディープでポンしてくれません。

なので、私は愛情をもってNNに接しています。皆さんはいかがでしょうか。
**①　わかっていることはしっかり入力に加える**
**②　NNにとってわかりやすく工夫する（NNのキモチを考える）**

<img width="520" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/d2003b19-fe7c-52f4-cc74-0e0ef6e38910.png">


#### NNへの優しい特徴量の与え方の例
デプス画像(奥行きを示す画像)一枚でも相当な量の情報があります。これをいちいち深層学習モデルに見つけさせるのは大変なので、重要なものは積極的に入れていくことも検討します。

**■　モデルは知らないが、自分は知っていること　⇒　積極的に与える**
- 奥行き0は数値ではなく、正しく数値が取れなかった欠損部分である
- 奥行き情報とカメラ幾何をうまく活用することで、xyzの三次元表現も可能である
- xyzの変化から、モノの向きに関する情報(法線方向など)を抽出できる

**■　モデルにとってわかりにくい部分　⇒　優しく加工する**
- 奥行きの広い数値レンジの扱い方。1mと2mの差よりも、0.1mと0.2mの違いの方が重要なケースがある
- カラー画像とデプス画像のどちらが重要か

あくまで一例ですが、いろんな工夫をもってNNに召し上がっていただきます。

<img width="640" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/843026d7-0b84-1943-7f0c-971247acb77d.png">

もう少し丁寧に補足していきます。

### 補足：わかっていることを入力に加える＠特徴量エンジニアリング
#### チョット難しい数値加工
X+Yなどの和差ぐらいで理解できる特徴量は勝手にやってくれることも多いと思いますが、sqrt(X2 + Y2)ぐらいになると、ちゃんと与える方が親切で学習が進みやすいケースも多い印象です。

『50ピクセルぐらい見渡さないとわからないけど大事な情報』なんかも、Convやtransformerでカバーできるものの、無駄な学習を減らす意味でも追加してもいいかもしれません。

#### 明示的に与えられていない情報の追加
たとえば画像系のコンペにおいては、**画像中の座標位置**が明確に意味を持つこともあります。例えば『人は地面を歩く』なども重要な事前知識で、画像における座標系を追加特徴にすることもアリです。Coord Conv, Positional encodingなどに相当するかと思います。
車載画像の検出などにpaddingからの位置情報を活用していると話題になったことがありますが、積極的に狙うのであれば、位置情報を入力に加えてもいいです。

画像をクロップすると注視点が変わる(明示的に画像座標を与えなくても、座標情報をつかっている)という話は有名ですね。
![1_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/8dc778ae-d091-c458-0821-9d0d80392b5c.png)

https://arxiv.org/abs/2001.08248

### 補足：NNにとってわかりやすく与える＠特徴量エンジニアリング
深層学習はGBDTとは異なり、与え方によってもパフォーマンスが変わります。**下手な方法で追加すると露骨に精度が落ちてしまう**ので、作成した特徴量はなるべくわかりやすく与える意識が必要だと思います。

#### ■　NNは数値スケールに敏感
連続値であっても、**歪な分布や極端な数値が混ざると学習しにくい**ことはよく知られています。また、0-1分布などにうまく調整したとしても、『0が欠損データで、0.001とは全く意味が違う』などがあればfloat(X==0)ぐらいのマスクを追加特徴にしてもいいと思います。**その微小値をNNに見つけてもらうのは大変**です。(決定木なら余裕ですが)

#### ■　NNは特徴量の数や強さに敏感
センサ値Aから作った特徴量が50個、センサ値Bから作った特徴量が2個で52chつくると、A系特徴量からの学習の方が進みやすくなります。B系特徴量にすごく自信があってどうしても見てほしい、というときは最初のレイヤで調整することもできます。

<img width="520" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/a2856de4-6700-18b2-8d36-bee84ac9c5b5.png">

やりすぎかもしれませんが、Dropoutやデータローダでランダムに片方の情報をそぎ落としたりしたときもありました。
```x_a = Dropout(0.5)(x_a)```
```x = concat(x_a, x_b)```

#### ■　特徴量の質によっても難しい
たくさんの入力があるときにそれをすべてチャンネル方向にスタックしてしまうかというと悩ましく、特徴量の質によって、適切な混ぜ方が少し違うこともあります。

**1. 同質のものを混ぜるとき、とりあえず試すとき**
：しょっぱなで適当に混ぜる。
```Inputs_NN = Concat(features_A, features_B)```

**2. 少し異質なものを混ぜるとき (たとえばAがRGBカラー画像、BがDepth画像)**
: 一層ぐらいおいて混ぜてもいいかもしれません。
```Inputs_NN = Concat(Conv(features_A), Conv(features_B))```
もしくは
```Inputs_NN = Add(Conv(features_A), Conv(features_B))```
たまに[そういう論文もあります](https://arxiv.org/abs/1807.00275)

<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/257349de-97f2-5524-95ab-bbe0486d08df.png">

**3. ランクの違うデータなどをまぜるとき(AがRGBカラー画像、Bが撮影者の特徴など)**
:上述1のように入力やボトルネックに次元を合わせてひっつけるのもいいですが、計算量的には微妙かもしれません。
```Inputs_NN = Concat(features_A, expand_dims(features_B))```

少し古いですが、FiLMや画像全体へのattentionとして与えるなどもありですね。
```x_a = Conv(out_ch=32)(features_A)```
```scale = Dense(out_ch=32)(features_B)```
```shift = Dense(out_ch=32)(features_B)```
```x_a = x_a * (1 + scale) + x_b```

https://arxiv.org/abs/1709.07871

といった感じで、特徴量を適当に作って与えるだけだとうまくいかないこともよくあります。

## 実施例 ＠ 特徴量エンジニアリング
### 論文から紹介
少し前に読んだ論文で、以下の論文はNNの特徴量(?)いじりとしてお気持ち感を強く感じました。

https://arxiv.org/abs/2402.10329

Stanford, Columbia, TRIからのロボティクス系論文で、手に付けたカメラ画像を用いてロボットを自律動作させるためのツールおよび手法を提案しています。

- 人の動きを記録してロボットの動作生成のためのデータとする取り組み
- カメラ1台での情報を増やすために**ミラーを左右に配置し、作業対象をいろんな角度で見える**ようになっていることも特徴 (疑似的なステレオ)

![1_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/a4f84a1a-b20c-c742-c668-986318a006f5.png)

さて、本論文ではこのミラー画像も含めた画像でのロボットの動きの学習をおこなうのですが、本文中に『**学習・推論時はミラーの画像を左右で入れ替えて用いることで性能が向上した**』との記述があります。
そのままの画像で学習すると、ミラー越しの視界と通常の視界とで状況が反転してしまうのですが、ミラー画像を左右入れ替えると、ミラー越しと通常の視界とで画像上での動きの方向が反転しなくなります。これによってNNが学習しやすく(混乱しにくく)なったのだろうと論文中では推測されています。
そこまでしないといけないの？と感じますが、確かにその方がNNにとって親切かもしれませんね。

### コンペから紹介
特に動画系コンペでは常套手段として、通常のカラー画像(or動画)に加えて
- **奥行き推定の活用：３次元的な位置関係が重要なケース**
- **オプティカルフローの活用：動きやイベント判定などのケース**

が見られます。いずれも人からすれば画像から容易に判断がつく内容ですが、親切に与えてあげることで精度を高められることがあります。[DFL(2位解法)](https://www.kaggle.com/competitions/dfl-bundesliga-data-shootout/discussion/360097)や[NFL(1位解法)](https://www.kaggle.com/competitions/nfl-impact-detection/discussion/209403)などのスポーツコンペではオプティカルフローが有効なことがあります。

RAFTなどを用いて画像全体のフローを予測することができれば、追加チャンネル的に扱うことが可能です。通常のカラー画像に加えてオプティカルフローの画像を入力することで、メインのタスクの予測精度が上がるケースがあります。

とはいえ、このまま特徴量として扱うよりも、この動きを踏まえた画像修正に活用したりする方が有効なことも多い印象です。特に動画においては、カメラ自身の動きと、撮影対象の動きを切り分けることが認識上重要なケースも多く、そういった意味でオプティカルフローは便利です。
(個人的にはデプス推定よりもオプティカルフロー推定結果を用いる方が有効なケースが多いです)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/2b81653e-0843-37a9-18ae-0bf0d57e7760.png)　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557686/ceaf5ccd-4e44-5294-8662-25b9beb231f1.png)



https://arxiv.org/abs/2003.12039


## 効果 ＠ 特徴量エンジニアリング
- ちょびっと効きます
  - なんだかんだでNNは賢いので、画像から読み取れる程度の特徴であれば効かないケースが多いです
  - とはいえ、差が出にくいコンペでは重要なのでしっかりやる
- 効く自信のある特徴量なら自分を信じたい。あきらめたら試合終了
  - 『えー、その特徴量も試したけどなぁ』という場合、もしかすると相手は自分よりスキルがあるのかもしれない
  - あれこれやったけど結局全く効いてくれない時間泥棒もよくある
- 比較的実装量は少なく簡単にできるので、初心者にもオススメ

# まとめ
ということで今回はドメインを考える話の１回目として、特徴量づくりの話をさせていただきました。私自身もいつもなんとなくやっているので、『そこまでやらんでええやろ』もしくは『もっとやっとるわ』という方もいるのではないかと思います。
初心者向けという意味では、**特徴量は作りっぱなしではなく効かせる努力もオススメですよ**、というぐらいのお気持ちで取っていただけると幸いです。

ということで、次回は『そのコンペだからやること。その③』の予定です。LossやAugmentationなど、さらなるコンペ固有の工夫で今度こそロマン砲を狙いましょう！


# 参考
- 画像座標位置を知っているCNNの話: https://arxiv.org/abs/2001.08248
- DepthとRGB画像の入力をわける例: https://arxiv.org/abs/1807.00275
- UMI (ミラー反転の話): https://arxiv.org/abs/2402.10329
- FiLMによるマルチモーダル入力対応：https://arxiv.org/abs/1709.07871
- RAFT. optical flow https://arxiv.org/abs/2003.12039