ひとことで言うと
物体検出は、画像全体を1つのラベルにする分類と違い、何が写っているかと、どこに写っているかを同時に出すタスクです。出力はクラス名やスコアだけでなく、左上と右下などで表す矩形(bounding box)を含みます。したがって、分類の誤差に加えて矩形のずれを学習する回帰が必要です。
写真の受付で「犬がいます」と答えるだけなら分類ですが、「犬はこの範囲です」と写真上に枠を引くなら検出です。枠が少しずれても犬だとは分かりますが、検出器の評価ではそのずれを数値化して合否を決めます。
なぜ必要か
画像分類は、画像に対してクラスを1つ、または複数返します。しかし、同じ画像に複数の物体があり、それぞれの位置を使いたい場面では分類だけでは情報が足りません。物体ごとに候補領域を作り、各領域についてクラスと矩形を予測する必要があります。
基本構成は次の流れです。
| 段階 | 入力と出力 | 役割 |
|---|---|---|
| 候補領域 | 画像から複数の矩形 | 物体がありそうな場所を絞る |
| 特徴抽出 | 各領域の画像特徴 | 形状や見た目を表現する |
| 2つの予測 | クラススコアと矩形の補正量 | 何か、どこかを出す |
R-CNN は、候補領域に CNN の特徴を適用する構成を示し、従来の複雑な組み合わせに対して高い検出性能を狙いました。一方、候補領域ごとに深い CNN を繰り返し通す初期構成は計算コストが大きく、Fast R-CNN は畳み込み特徴を画像側で共有して学習・テストを高速化しました。ここで大切なのは、方式名を暗記することではなく、候補領域をどう作り、特徴計算をどう共有するかが速度を左右するという見方です。
仕組み
2つの矩形 と の重なりを測る基本量が IoU(Intersection over Union)です。 は予測矩形、 は正解矩形を表します。
は共通部分の面積、 は和集合の面積です。完全一致なら1、重なりがなければ0になります。左上を 、右下を とする矩形なら、共通部分の幅と高さをそれぞれ最大0で切り、面積を計算します。
学習時には、候補領域と正解矩形の IoU を使って、その候補を物体の正例として扱うか、背景の負例として扱うかを割り当てます。推論時には、同じ物体に対する似た矩形が複数出るため、NMS(Non-Maximum Suppression)を使います。クラスごとにスコア最大の矩形を残し、それと IoU が大きい他の矩形を捨てる処理です。つまり NMS は矩形を改善する回帰ではなく、重複した予測を整理する後処理です。
矩形回帰は、候補矩形を正解矩形へ移す補正量を学習します。候補の中心 、幅と高さ 、正解の中心 、幅と高さ に対して、典型的には次のような相対量を教師にします。
予測側の補正量を とすると、分類損失と矩形回帰損失を合わせて最適化します。クラスを当てても枠がずれていれば検出として弱く、枠が合っていてもクラスが違えば別の誤りです。
mAP(mean Average Precision)は、クラスごとの検出結果をスコア順に並べ、IoU などの判定基準で正解と対応付けたときの precision と recall の関係を評価し、その平均を取る指標です。したがって、単に分類精度を平均した値ではありません。スコアのしきい値を動かして、見逃しを減らすと誤検出が増える関係まで含めて、位置とクラスの両方を見ています。
試験でどう問われるか
| 問われ方 | 正解に寄る条件 | 引っかけ |
|---|---|---|
| 分類との違い | クラスだけでなく物体ごとの矩形位置を出す | 画像全体のクラスを当てれば検出になる |
| IoU の意味 | 交差領域を和領域で割る。正例割り当てや重複判定に使う | 交差面積だけ、または予測面積だけで割る |
| NMS の処理 | 高スコアを残し、IoU の大きい重複矩形を抑制する | 回帰値を再学習して枠を正解へ動かす |
| 矩形回帰の役割 | 候補から正解への中心・幅・高さの補正量を予測する | クラス確率を出す処理と同一視する |
| mAP の評価対象 | クラスごとの precision–recall と、位置の正しさを反映する | 分類正解率の単純平均だと考える |
| R-CNN 系の速度差 | 初期構成の候補ごとの CNN 計算を共有で減らす方向 | 候補領域そのものが不要になったと考える |
実装で確かめる
小さな例で IoU と NMS を動かします。1番目と2番目は大きく重なるため、スコアの低い2番目が抑制されます。
import numpy as np
def iou(a, b):
lo, hi = np.maximum(a[:2], b[:2]), np.minimum(a[2:], b[2:])
inter = np.prod(np.maximum(0, hi - lo))
area = np.prod(a[2:] - a[:2]) + np.prod(b[2:] - b[:2]) - inter
return inter / area
boxes = np.array([[0, 0, 10, 10], [1, 1, 11, 11], [20, 20, 30, 30]])
scores = np.array([0.9, 0.8, 0.7])
indices = np.arange(len(boxes))
keep = []
while scores.size:
i = scores.argmax(); keep.append(indices[i])
overlap = np.array([iou(boxes[i], b) for b in boxes])
mask = overlap <= 0.5; mask[i] = False
boxes, scores, indices = boxes[mask], scores[mask], indices[mask]
print(list(map(int, keep)))
実行結果は [0, 2] です。これは元配列の添字で、1番目と2番目の矩形のうちスコアの高い0番目と、重複していない2番目が残ったことを示します。この短い実装でも、最大スコアを選ぶ、重複を IoU で判定する、残った候補から繰り返す、という NMS の順序を確認できます。
取り違えやすいもの
| 用語 | 物体検出との切り分け |
|---|---|
| 画像分類 | 画像または決められた入力領域のクラスを予測する。物体ごとの位置は出さない |
| セマンティックセグメンテーション | 画素ごとにクラスを割り当てる。物体ごとの矩形とは出力の粒度が違う |
| インスタンスセグメンテーション | 物体インスタンスごとの画素領域を出す。検出は矩形で位置を表す |
| 矩形回帰 | 候補を正解位置へ補正する予測。分類スコアや NMS そのものではない |
| IoU | 2つの矩形の重なりの尺度。正例割り当てや NMS の条件に使う |
| NMS | 推論後の重複除去。IoU を使うが、矩形回帰の学習ではない |
想起チェック
分類だけでは物体検出にならない理由は
物体検出はクラスに加えて物体ごとの位置を出すためです。位置を表す矩形の推定には、候補から正解へ移す矩形回帰が要ります。
IoU の分母と、NMS での使い方は
分母は2矩形の和集合の面積です。NMS では高スコアの矩形を残し、それとの IoU が大きい重複矩形を抑制します。
NMS と矩形回帰の違いは
矩形回帰は候補の座標を補正する学習上の予測、NMS は重複した予測を推論後に整理する処理です。
mAP が分類正解率の平均ではない理由は
クラスごとにスコア順の検出結果を評価し、precision と recall の関係を通じて、クラスと位置の両方を反映するからです。