（今さらだが）Mask R-CNNについて勉強したまとめ

# Mask R-CNNでは何ができるの？

画像中のどこに検出したい対象（e.g. 人、車）があるかを**ピクセル単位**で検出し、かつ、対象のクラス（e.g. 人）が複数個映っている場合はそれらを分けて判別する。

下図では、画像中に人が8人映っているが、その8人がそれぞれ別人であることを区別している（出展：参考文献[1]）。このようなタスクを**instance segmentation**という。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/aac39a5e-aa0d-6a1f-af6c-68fb271b8c59.png)

# Mask R-CNNの流れ

流れを下図に示す（出展：参考文献[2]の図をベースに少しアレンジ）。

![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/8b666b6e-33c8-8b09-b29e-a6ab072f75b4.png)

## ①backborn network
backborn networkでは分類タスクに用いられる一般的なCNN (e.g. VGG, ResNet) を用いて、**instance segmentationに使う特徴量**を抽出する。
特徴量として、VGGやResNetの出力層に最も近い畳み込み層のfeature mapを用いる。feature mapは畳み込みを何度も繰り返して得られたものなので、feature mapのサイズは入力画像のサイズより小さくなっていることに留意。

ここでは、入力画像のサイズが160*160pxで、feature mapはたて16 * よこ16 * 512chとなったとしよう。

## ②region proposal network (RPN)

Mask R-CNNは検出したい対象の位置を長方形で検出するobject detectionタスクを行うFaster R-CNNネットワークをベースにしている。
このRPNはFaster R-CNNで提案されたものであり、RPNはfeature mapから検出したい対象がありそうな**長方形領域**を見つける。対象がありそうな領域を**region proposal**とよぶ（直訳すれば候補領域）。

先にRPNの入力と出力を確認しよう。

- 入力：①のfeature map（16*16*512ch）
- 出力：注目している矩形領域に対象が存在する確率、および矩形領域の座標の補正値

RPNの中身は3*3の畳み込みと1*1の畳み込みから成る。
feature map上の3*3領域（下図でいう左の橙四角）に対応する入力画像の領域を下図の右橙四角で示した。
（説明を簡単化するため、チャネル方向の表現を省いている）。
なお、feature mapの値に寄与している入力画像の範囲を**受容野 (receptive field)** という。

![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/e2e2e89a-2ecf-9f4b-48ca-b9a3d20f690c.png)

いま、入力画像が3*3で、3*3の畳み込みと1*1の畳み込みから成るCNNを使って入力画像中に検出したい対象が映っているか否か、という問題を解いていると考える。
そうすれば、3*3の畳み込みをfeature mapの左上から右下までsliding windowの要領でくまなく走査すれば対象がありそうな矩形領域が見つけられそうなイメージがわくだろう。

しかし、この方法だと（正方形でなく）縦長や横長の対象や、さまざまな大きさの対象を検出するには課題がある。そこで、**anchor**という概念を導入する。

### anchorとは？

下図のように、3*3畳み込みの真ん中のピクセルに対応する受容野をanchor（黄丸）と呼ぶ。図では黄丸は2つしか描いていないが、実際にはfeature mapの左上から右下までの3*3の畳み込みの回数分だけanchorが存在することに注意。

![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/87155f4f-78cf-3339-f24a-6b61f3e570e5.png)

次に、下図のように、ある3*3の畳み込みに注目しよう。
この畳み込みに対応するanchorを中心として、色々な形の長方形を定義し、その長方形内に検出したい対象が映っているか否か、という問題に置き換える。この長方形のことを**anchor box**と呼んでいる。
論文では、anchor boxの形は、アスペクト比が異なる3通り（正方形/縦長/横長）と大きさが異なる3通り（大/中/小）の組合せである9通りを用意している。図では、2通りしか示していないことに注意。
また、anchor boxが受容野の範囲を超える場合もある。つまり、真の検出対象の特徴量が畳み込みの3*3に一部しか入っていないような場合でも検出できるようにすることを狙っている。

![キャプチャ6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/c30e05a0-af88-36ae-2d21-5fc40fbbbae8.png)

このようにいろんなアスペクト比/大きさのanchor boxを用意することで、（正方形でなく）縦長や横長の対象や、さまざまな大きさの対象を精度よく検出することを狙っている。
ただ、これだけでは対象がありそうな領域の座標を細かく検出することができない。
例えば、下図のようにanchor boxとanchor boxの間に対象が存在する場合、誤差なく対象がありそうな領域の座標を検出することができない。

![キャプチャ7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/0de47289-d18a-929d-93d6-3f25343e95a4.png)

そこで、いま注目しているanchor boxが正解位置と座標がどれぐらいずれているか、および、anchor boxの幅/高さと正解の幅/高さがどれぐらいずれているかを回帰問題として推定するタスクを追加する（論文中ではbounding box regressionなどと呼ばれている）。

以上により、region proposal（対象がありそうな領域）を正確に推定できるようになった。

なお、画像の端のanchorから大きなanchor boxを定義すると、下図のように入力画像をはみ出す場合がある。このようなanchor boxは無視する。

![キャプチャ8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/07a79922-6ef8-c11b-a30b-4cfaca885376.png)


ここでもう1度RPNの入力と出力を確認しよう。今なら、よりイメージがつかめるはず。

- 入力：①のfeature map（16*16*512ch）
- 出力：注目している矩形領域に対象が存在する確率、および矩形領域の座標の補正値

## RPN architecture

RPNにはいろいろバージョンがあるみたいで、畳み込みのカーネルサイズなどのパラメータは以下と異なる場合があることをあらかじめ断っておく。

- 入力はfeature mapの16*16*512ch。
- 3*3の畳み込みにより得られるfeature mapは14*14*512ch。論文中ではintermediate layerと呼ばれる。ここで、14*14はanchorの数に相当していることに留意。
- ここから、検出したい対象が映っているか否かを識別するclassification branchとanchor boxと真の対象との座標/大きさのずれを回帰するregression branchに枝分かれする。なお、論文にしたがいanchor1つから作成するanchor boxの数は9とする。
  - classification branch：すべてのanchor boxの数は14*14*9であり、1つのanchor boxにつき対象が映っているか否かの2クラス問題を解きたい。なので、14*14*512のfeature mapに1*1の畳み込みを行って14*14*(9*2)とする。ch方向を512次元から18次元に落としているという操作である。
  - regression branch：1つのanchor boxにつきx, y座標と幅、高さw, hをどれだけ補正するかの4次元値を出力させたい、なので、14*14*512のfeature mapに1*1の畳み込みを行って14*14*(9*4)とする。ch方向を512次元から36次元に落としているという操作である。


## ③RoIAlign

RPNにより、region proposalが求まった。オリジナル画像上のregion proposalに対応するfeature mapの位置は計算により求めることができる。

![キャプチャ9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140135/baa9f7e4-e073-0d0b-6890-7bb95de5288f.png)

feature map上のregion proposalを最終的な判定を行うネットワークに入力してinstance segmentationを行いたいが、anchor boxの影響でregion proposalの大きさ/アスペクト比がまちまちである。
つまり、最終的な判定を行うネットワークに入力するデータの次元がまちまちとなってしまい、扱いにくい。
そこで、任意の大きさのfeature map上のregion proposalを固定次元に変換する操作を行う。この操作が**RoIAlign**である。

### RoIPoolingとRoIAlign

yu4uさんのQiita記事がとても分かりやすいです。
https://qiita.com/yu4u/items/5cbe9db166a5d72f9eb8#roi-pooling

Mask R-CNNの前身であるFaster R-CNNはピクセル単位の識別を行うsegmentationタスクでなく、物体がある位置を矩形で囲うdetectionタスクであった。
なので、多少のピクセルずれが発生するRoIPoolingでも大きな問題ではなかった。

一方、segmentationタスクでは少しのピクセルずれが判定精度に大きな影響を及ぼすので、RoIPoolingの改善版であるRoIAlignが使われている。

backbornネットワーク出力のfeature mapである16*16*512chからregion proposalの領域（e.g. 10*8*512ch）を取り出し、固定サイズ（e.g. 7*7*512ch）に変換する。

*（不明）固定サイズより小さいregion proposalが選ばれた場合はどうするのだろう？*

# ④classification

RoIAlignにより、任意のサイズのregion proposalを固定サイズに変換できた。論文に従い、7*7*512chとする。
classificationでは2つのタスクを解く。

1. **bounding box prediction branch**
7*7*512chを入力として、region proposalに映る物体が何であるかを識別する。車か人か犬を識別したい場合は出力次元は3となる。
全結合層を数回いれて、7*7*512次元の入力から(識別クラス数)次元の出力を行う。

2. **mask branch**
7*7*512chを入力として、region proposalのクラス及び位置をピクセル単位で識別する。畳み込みとdeconvolutionを数回繰り返すことで7*7のサイズを2倍（14*14）か4倍（28*28）に大きくするようだ。また、ch方向は識別したいクラス数となる。
車か人か犬の3クラスを識別したい場合は、出力は14*14*3 or 28*28*3となる。各チャネルの出力（14*14 or 28*28）は各クラスに属する確率を推定している。つまり、1チャネルめの14*14は（ピクセル単位の）車である確率で、3チャネルめの14*14は犬である確率である。
region proposalごとにこの識別を行っているので、画像内に同じクラスの物体が複数存在してもそれらを区別することができることに注意。なので、instance segmentationタスクとなっている。

# 損失関数

以下の3つの損失$ L_{cls}, L_{box}, L_{mask} $をまとめたものを$L$とし、この$L$を勾配法で小さくするようなパラメータを求める。

- $L_{cls}$：注目しているbounding boxがある物体か背景かをclassificationする2クラス分類問題の損失。2クロスエントロピー損失関数を使う
- $L_{box}$：注目しているbounding boxが正解の座標、サイズとどれぐらいずれているかを示す損失。ただし、ground truthが物体であるのみ（not 背景）が損失計算の対象
- $L_{mask}$：segmentationがどの程度外れたかを示す損失。mask branchの出力をピクセルごとにシグモイド関数にかける。これにより、値が0～1になる。後はground truthとのクロスエントロピーを求める。

# 参考文献

1. Mask R-CNN 論文
https://arxiv.org/abs/1703.06870
2. Chanuk Limさんのslideshare資料
https://www.slideshare.net/windmdk/mask-rcnn
3. yu4uさんのQiita記事
https://qiita.com/yu4u/items/5cbe9db166a5d72f9eb8