OSNet: 画像を "Omni" な "scale" で処理する手法？

# 原著論文
### Omni-Scale Feature Learning for Person Re-Identification
>Zhou, Kaiyang, et al. "Omni-scale feature learning for person re-identification." Proceedings of the IEEE/CVF International Conference on Computer Vision. 2019.
論文URL: https://arxiv.org/pdf/1905.00953.pdf

監視カメラの人物を照会したい時に，同じような服装とかの人を同一人物と見做してしまうと厄介でしょ？だから **再度画面内に映った時に人物を同定するためにどうやって特徴を取り出しましょうか？** という手法を紹介した論文．

# OSNetのすごいポイントってどこにあったの？
1. Convolutions を Depth と Point に分割しました
2. Omni-Scale Residual Block を利用しました
    a. 複数の規模の受容野で画像を処理する
    b. 多様な受容野から獲得した情報をマージする手法
3. ネットワーク構造

## 1. Convolutions を Depth と Point に分割しました
ここでも計算コストを削減するための手法を検討している．以前紹介した [SqueezeNet](https://qiita.com/lucasta1/items/53b4b69fd5a563d980fb) でも CNN における計算コスト削減の手法を色々検討されていたが，本論文では "Depth-wise separable convolutions" というものを採用している．この概念の理解が多少難しいので，数学的にちゃんとした説明と感覚的な説明の 2 つを用意したので，自分に合った方で理解していただければと思います．

#### ● 数学的にちゃんと説明する Ver
フィルタの重みを $\boldsymbol{w}\in{\mathbb{R}^{k×k×c×c{'}}}$，入力されてくる特徴マップを $\boldsymbol{x}$ とした時に，多くの場合では Convolution の過程で $\mbox {ReLU}(\boldsymbol{w}*\boldsymbol{x})$ を用いるのだが，この研究では **depth-wise** と **point-wise** の 2 種類にこれを$\mbox {ReLU}((\boldsymbol{v}\circ\boldsymbol{u}) *\boldsymbol{f})$　のような形に分けて考えることにする．ちなみに $\circ$ は合成関数のことです．

つまり， **depth-wise**では，$\boldsymbol{u}\in{\mathbb{R}^{k×k×\boldsymbol{1}×c{'}}}$
そして **point-wise**では，$\boldsymbol{v}\in{\mathbb{R}^{\boldsymbol{1}×\boldsymbol{1}×c×c{'}}}$ を用いて計算をするのである．
なお，ここでの $k$ とはカーネルサイズのことを指し，$c$ とは input チャンネルの width，$c{'}$ とは output チャンネルの width を指している．

ここまでの説明で怪しかった人も次の瞬間はっきりと理解できるだろう．そもそも，この Convolution の導入理由は **「計算コストの削減」** であったはずだ．つまり，[SqueezeNet](https://qiita.com/lucasta1/items/53b4b69fd5a563d980fb) の時もそうだったように，「**パラメータ数を減らせれば成功**」なのである．
さて，ここでパラメータ数を確認しよう．
```math
h・w・k^2・c・c{'} → (h・w・k^2・1・c{'}) + (h・w・1・c・c{'})
```
つまり，畳み込みを分割することでパラメータ数の削減に成功しているのである．
さらに，本論文では畳み込みの順番を「Point-wise → Depth-wise」として採用している．逆の順番と精度を比較した時に，より Omni-Scale に効果的だった方を採用したとのころだそうである．

#### ● 感覚的に説明する Ver
一つの難しいタスクを一気にまとめて考えるより，順番に少しずつ処理して行った方が簡単に解けるんじゃないの？という発想に基づいている．
直感的な例になるが，今から単純な塗り絵をするとする．100個の塗られていない場所を10色で塗り分けることにする．よーいドンで塗る時に，赤鉛筆や青鉛筆を持ったり何回も持ち替えるよりも，最初っから赤鉛筆で赤いところを塗ってしまって，次に青鉛筆で...とした方がなんとなく頭のリソースも使わなそうだし，手の動きも最小限で済みそうじゃないだろうか？
本論文でも同様に，通常の Convolution のタスクを 2 つに分割して，必要なパラメータ数を抑えた，というのがポイントである．

## 2. Omni-Scale Residual Block を利用しました
過学習を防ぐためによく用いられる ResNet だが，基本的に 2 種類存在している．
![ResNetblock](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1711990/0e0b88d7-454f-4397-3b92-7a36d1095227.png)
(画像は [原著論文](https://arxiv.org/pdf/1512.03385.pdf) より引用)
上記引用画像の左の Block では Basic な Skip connection を持っている形式だが，右の Bottle Neck と呼ばれる種類の Block では Skip connection に加えてカーネルサイズやチャンネル数が異なっていることとが分かる．本論文では後者が採用されている．

### a. 複数の規模の受容野で画像を処理する (Omni-Scale Residual Block)
もしも CNN の受容野について忘れてしまっている場合は [こちら](https://qiita.com/lucasta1/items/ebd0f9b1fa37db5af780) を参照ください．
ResNet は簡単な数式で表すと，
```math
\boldsymbol{y} = \boldsymbol{x} + \boldsymbol{\tilde{x}}, \;\; \mbox{s.t.} \;\;\tilde{x}=F(\boldsymbol{x})
```
であるが，3×3 の層を重ねることで結果として受容野の大きさは $(2t+1)×(2t+1)$ となる．つまり，4 層重ねると 9×9となる．重ねる数を $T$ とした時，これを数式で表すと，
```math
\boldsymbol{\tilde{x}}　= \sum_{t=1}^{T} F^{t}(\boldsymbol{x}), \;\; \mbox{s.t.} \;\; T\geq 1.
```
と表すことができる．
![network_res](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1711990/67e7b96f-dff3-8774-7172-ee59c32357e1.png)

(画像は [原著論文](https://arxiv.org/pdf/1512.03385.pdf) より引用)
※画像内の "AG" については以下，b 項にて説明．

### b. 多様な受容野から獲得した情報をマージする手法 (Unified aggregation gate)
さて，a. 項にてそれぞれのストリームで特徴量を，同じスケールで取得できることは分かった．しかし，学習するためには各々のストリームで獲得できた結果を組み合わせる必要がある．様々なスケールで特徴量を取得した後に，どうやってそれらの情報をマージするのかというのがこの "ゲート" の役割となる．

この "ゲート" で用いられている数式は以下のように表される．
```math
\boldsymbol{\tilde{x}}　= \sum_{t=1}^{T} G(\boldsymbol{x}^{t})\odot\boldsymbol{x}^{t}, \;\; \mbox{s.t.} \;\; \boldsymbol{x}^{t}\triangleq F^{t}(\boldsymbol{x}).
```
なお，$\odot$ は[アダマール積](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%80%E3%83%9E%E3%83%BC%E3%83%AB%E7%A9%8D)を表しており，$\triangleq$ は左辺を右辺で定義する時に用いる記号である．率直に自分でこれらの数学記号を Markdown で扱ったことがなかったので，後の人のためにメモとして残しておく...
```equation.md
アダマール積: \odot
定義:        \triangleq
```
さて，厳しい (イカメしい) 数式が出てきたが，一つ一つ解説する．先述の AG ネットワークで行う処理は関数 $G$ として表現され， $G$ の持つ役割は， 
1. ノンパラメトリックな Average Pooling layer
2. ReLU による Multi Layer Perceptron

ということらしい．
例えば，それぞれのストリームでの出力に対して $w$ などで重みづけをしてマージするというアイデアも可能性として挙げられるだろうが，**この関数 $G$ の出力はベクトルであって，スカラーではない**という点がポイントである．つまり，出力をベクトルそれぞれのストリームの出力の，チャンネルに対しても重みをつけることができるのである．
ただし，この重みは全てのストリームで共有される． [CNN でパラメータ共有をする](https://qiita.com/lucasta1/items/ebd0f9b1fa37db5af780)のと目的は同じなのである．もしも CNN のパラメータ共有について忘れてしまっている場合は [こちら](https://qiita.com/lucasta1/items/ebd0f9b1fa37db5af780) を参照ください．これにより Backpropagation が効果的に働くということらしい．
そして，この損失関数は
```math
\frac{\partial \mathcal {L}} {\partial G} = \frac{\partial \mathcal {L}} {\partial \boldsymbol{\tilde{x}}}\frac{\partial \mathcal {\boldsymbol{\tilde{x}}}} {\partial G} = \frac{\partial \mathcal {L}} {\partial \boldsymbol{\tilde{x}}}(\sum_{t=1}^{T}\boldsymbol{x}^{t})
```
によって定義される．
つまり，全てのストリームから獲得される教師信号によってこの "異なるストリーム出力を統一するため関数"の $G$ が獲得されるのである．(ややこしいが，要は Backpropagation によって $G$ を調整していくということ．)

## 3. ネットワーク構造
本論文と比較されて用いられているのが [Inception](https://arxiv.org/pdf/1409.4842.pdf) と [ResNeXt](https://arxiv.org/pdf/1611.05431v2.pdf) である．大きな違いとして，OSNet では同じ層を重ねて "Omni" を実現していることが挙げられる．
![Inception](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1711990/3fdff0cb-c7b5-18ce-9072-4f42d41eeed4.png)
(画像は [Inception](https://arxiv.org/pdf/1409.4842.pdf) より引用)
![ResNeXt](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1711990/a9b2d087-5ef3-ba12-5e29-0430c95fa556.png)
(画像は [ResNeXt](https://arxiv.org/pdf/1611.05431v2.pdf)より引用)

結論として， 256*256 の入力画像を用いる場合の OSNet のネットワーク構造は以下の画像のようになっている．
![OSNet256256](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1711990/bed24e28-49f7-d8cb-a3d0-e7f4db60335b.png)

# 参考リンク
- [Omni-Scale Feature Learning for Person Re-Identification](https://arxiv.org/pdf/1905.00953.pdf)
- [ResNeXt](https://arxiv.org/pdf/1611.05431v2.pdf)
- [Inception](https://arxiv.org/pdf/1409.4842.pdf)