###背景
前章はSSDモデルから出力するOffset情報と信頼度情報の使い道について紹介しました。
Offset情報はデフォルトボックスをバウンディングボックスに変形するためなものです
信頼度情報はデフォルトボックスはどこカテゴリーに所属するかを表す数値です
実際に一つの画像の中に、教師データがあります。教師データとは物体を囲む正しい枠、物体の正しい所属カテゴリー
####目的####
Offset情報を訓練する目的は、変形されたバウンディングボックスはできるだけ教師データと近くすることです
図のように、たくさんのデフォルトボックスを一つの馬の教師データを目指して、近づこうとしています
図のように、ひとつのデフォルトボックスのoffset情報をたくさん訓練を受けて、offset情報がもっと有意になります。offset情報をつかって、デフォルトボックスから変形したバウンディングボックスが教師データと近づきました。
###Offset情報の訓練###
####IOU####
ここで、IOUの概念の引用します。ボックスAとボックスBがあります。ボックスAとボックスBの共通の部分Cがあります。ボックスAとボックスBのすべての部分Dがあります。IOUの値はC/Dです。
つまりIOUは二つのボックスがどれほど重ねってあることを表しています
図のように、オレンジの部分は重ねってある部分、赤の部分はすべての部分。
図のように、重ねってある部分がない、オレンジの部分がないです。赤の部分はすべての部分。
図のように、IOU = 重ねる部分の面積 / すべての部分の面積
####すべてのデフォルトボックスIOU計算####
我々はすでに8732個デフォルトボックスを用意しました。たとえここは一個教師データがあります。8732個デフォルトボックスは教師データにたいして、IOUを計算します。
図のように、教師データと全然重ねってないボックスのIOUは0になります。他に教師データと重ねってあるデフォルトボックスのIOUが重ねる程度によって、IOUの数値が異なります。
####すべてのデフォルトボックスをIOUからフィルタリング####
そしてつぎの3ステップがおこないます
- IOUが0より大きいデフォルトボックスを洗い出します。つまり教師データと重ねがあるデフォルトボックスを残らせます
- IOUはαより大きいデフォルトボックスを洗い出します。ここのαが我々が設定する数値です。通常は0.5です。つまり、まり教師データと重ねがあるだけではなく、まり教師データとある程度重ねがあるデフォルトボックスを洗い出します。
- 残りのデフォルトボックスをポジティブデフォルトボックスといいます
図のように、IOU>0、IOU>αのデフォルトボックスをスッテプずつ洗い出します。
####ポジティブデフォルトボックスの教師Offset情報の計算####
洗い出したポジティブデフォルトボックスはある程度教師データとかさねってありますが、実際にはまたまたすれています。そして、ポジティブデフォルトボックスから教師データに以下の算式で変形しようとしています。
cx = cx_d+0.1*△cx*w_d)
cy = cy_d+0.1*△cy*w_h)
w = w_d*exp(0.2*△w)
h = h_d*exp(0.2*△h)
左のcx,cy,w,hは教師データバウンディングボックスの座標情報。右側のcx_d,cy_d,w_d,h_dはデフォルトボックスの座標情報。
逆算すれば、教師データバウンディングボックスに変形するためなoffset情報を以下の算式から取り出せます。
△cx = (cx - cx_d) / (0.1 * w_d)
△cy = (cy - cy_d) / (0.1 * w_h)
△w = log(w / w_d) / 0.2
△h = log(h / h_d) / 0.2
以上の計算結果は教師データのOffsetTになります
ずのように教師データバウンディングボックスに変形するためなoffset情報を計算する
####ポジティブデフォルトボックスのSSDモデルOffset情報計算####
さっき、offsetTを計算しました。でも、あれは目指す目標です。実際につかうのはSSDモデルから出力したOffset情報です。
実際につかうのはSSDモデルから出力したOffset情報は教師データバウンディングボックスに変形するためなoffset情報を目指しています
ここはとても重要なものです。
Offset情報訓練の教師データはさっき計算したOffsetTになります
Offset情報訓練の訓練データはSSDモデルから出力したOffsetSになります
訓練するのは、変形したバインディングボックスと教師データボックスと比較することではなりません
訓練するのは、デフォルトボックスの変形するための材料Offset情報の訓練です
この図のように、38384のデフォルトボックス[一番右側の4個のデフォルトボックス][一番手前のデフォルトボックス]に対して、4個のoffset情報(△cx,△cy,△w,△h)を提供しています。デフォルトボックすは座標情報(cx_d,cy_d,w_d,h_d)を持ち、offset情報(△cx,△cy,△w,△h)を使い、赤いボックスに変形します
変形する算式は
####Offset情報の損失計算####
では、手元に用意したのは教師データOffsetTと変形データOffsetSです。Offset情報訓練の訓練データはSSDモデルから出力したOffsetSになります。そのため、OffsetTとOffsetSと比較するための損失関数を用意する必要があります
図のように、左側逆算で計算したOffsetTは△cx,△cy,△w,△hを提供しています。右側SSDモデルから出力したOffsetSは△cx,△cy,△w,△h。
OffsetTとOffsetSの比較は△cx,△cy,△w,△hの比較になります。
OffsetTとOffsetSとともに、損失関数に投げます
ここで少し損失関数を紹介します。
図のように、xは普通訓練データ、xtは教師データ。
xとxtの絶対差は1以下なら、損失値が0.5*(x-xt)**2です。
xとxtの絶対差は1以上なら、損失値はabs( x - xt ) - 0.5になります。
実際にxはSSDモデルから出力した△cx,△cy,△w,△h
xtは教師データから逆算で計算された△cx,△cy,△w,△h
代入したら、以下のことになります
図のようにoffsetSとoffsetTの計算は△cx,△cy,△w,△hになります。最後にsumします。
図のように△cx,△cy,△w,△h一対一でsmooth_l1_lossに代入して、最後にsumします
ずのように△cx,△cy,△w,△hの実際のデータを使って、計算する。
####ネガティブデフォルトボックスの教師Offset情報の計算####
以上をまとめてみると、IOUからポジティブボックスを洗い出し、そしてポジティブボックスにたいして、Offset損失を計算します
では、残るのネガティブデフォルトボックスはどうしますかというと、
結論はネガティブデフォルトボックスOffset損失を計算しません。
ネガティブデフォルトボックスはOffsetTとOffsetSもあります。Offset損失を計算しないことは、もともと教師データとのずれることが結構大きいため、
ネガティブデフォルトボックスを背景の予測とします
推論するときに、そのまま教師データとのずれて、背景として出力させないです
図のように、デフォルトボックスは教師データと重ねがありますが、IOUはαより小さいため、ネガティブボックスにさせて、背景ボックスとして取り扱います。
図のように、このデフォルトボックスは、教師データと重ねがないため、IOU=0,ネガティブボックスにさせて、背景ボックスとして取り扱います。
IOUは0ですが、重ねない教師ボックスは一番重ねがある教師データなので、OffsetTはこの教師データの座標から逆算で計算します
つまり、ネガティブデフォルトボックスはOffsetSとOffsetTを持っています。
図のように、ネガティブデフォルトボックスはoffsetの損失に参加しません。
####教師データが複数のある場合####
教師データが複数がある場合には、各デフォルトボックスに対して、IOUの計算はちょっとかんがえないといけないです。
図のように、教師データは馬ではなく、猫と犬もあります。
各デフォルトボックスに対して、IOUは教師データボックスと重ねる程度を表すものです。
複数教師データがある場合、各デフォルトボックスに対して、IOUは一番重ねってある教師データボックスとの重ねる程度を表しています
ここでは、馬、猫、犬三つの教師データがあります。デフォルトボックスを分身させ、三つのlayerに分身します。各layerに馬、猫、犬三つの教師データがそれぞれあります。
三つのlayerごとに、教師データとのIOUを計算します
そして、各デフォルトボックスは馬、猫、犬三つの教師データとのIOUから一番高いIOUだけ残らせます
そして、このデフォルトボックスとのIOUが一番高い教師データがこのデフォルトボックスのOffsetTの逆算ざいりょうになります。
図のように、このデフォルトボックスは馬とのIOUは0.14、猫とのIOUは0.39、犬とのIOUは0.52になります。
0.52が一番高くて、残ります。このデフォルトボックスはこれから犬の枠に変形しようと訓練します。
ずのように、複数の教師データの場合、ポジティブボックスも複数の教師データを目指して、変形しようとします。
###ソースコード###
####IOUの計算####
def jaccard(box_a, box_b):
inter = intersect(box_a, box_b)
area_a = ((box_a[:, 2]-box_a[:, 0]) *
(box_a[:, 3]-box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B]
area_b = ((box_b[:, 2]-box_b[:, 0]) *
(box_b[:, 3]-box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B]
union = area_a + area_b - inter
return inter / union # [A,B]
def intersect(box_a, box_b):
A = box_a.size(0)
B = box_b.size(0)
max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2),
box_b[:, 2:].unsqueeze(0).expand(A, B, 2))
min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2),
box_b[:, :2].unsqueeze(0).expand(A, B, 2))
inter = torch.clamp((max_xy - min_xy), min=0)
return inter[:, :, 0] * inter[:, :, 1]
####教師データからOffsetTの逆算####
def encode(matched, priors, variances):
# dist b/t match center and prior's center
g_cxcy = (matched[:, :2] + matched[:, 2:])/2 - priors[:, :2]
# encode variance
g_cxcy /= (variances[0] * priors[:, 2:])
# match wh / prior wh
g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:]
g_wh = torch.log(g_wh) / variances[1]
# return target for smooth_l1_loss
return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4]
####各デフォルトボックスのIOUを計算####
best_truth_overlap, best_truth_idx = overlaps.max(0, keepdim=True)
overlaps -> [n,8732]:すべてなデフォルトボックスから各教師データとのIOU
nは教師データの数
overlaps = tensor([[0.0000, 0.0000, 0.0000, ..., 0.0719, 0.1068, 0.0991],
[0.0000, 0.0000, 0.0000, ..., 0.1028, 0.1526, 0.1526],
[0.0000, 0.0000, 0.0000, ..., 0.1574, 0.2337, 0.2167]],
device='cuda:0')
best_truth_overlap->[1,8732]:8732個デフォルトボックス、各デフォルトボックスから一番大きいIOU
best_truth_overlap = tensor([[0.0000, 0.0000, 0.0000, ..., 0.1574, 0.2337, 0.2167]],
device='cuda:0')
best_truth_idx->[1,8732]:8732個デフォルトボックス、各デフォルトボックスから一番大きいIOUの教師データID
best_truth_idx = tensor([[0, 0, 0, ..., 2, 2, 2]], device='cuda:0')
####各デフォルトボックスの一番重ねってある教師データの座標####
matches = truths[best_truth_idx]
best_truth_idxは教師データのID、そして、truthsは教師データの座標をもっています。通常はcx1,cy1,cx2,cy2です。
truths = tensor([[0.2342, 0.1980, 1.3273, 0.6320],
[0.5435, 0.1000, 1.0721, 0.4720]], device='cuda:0')
8732個のデフォルトボックスはそれぞれの教師データに対して、IOUが一番高い教師データを選びます。そうしたら、matchesに納めます。matchesはたくさんの重複なデータがあります。それは、たくさんのデフォルトボックスから同じ教師データを選んだからです。
このmatchesは教師データの座標をもっているため、デフォルトボックスの座標と比較して、教師offset情報をencode関数で逆算します
matches = tensor([[0.2342, 0.1980, 1.3273, 0.6320],
[0.2342, 0.1980, 1.3273, 0.6320],
[0.2342, 0.1980, 1.3273, 0.6320],
...,
[0.2342, 0.1980, 1.3273, 0.6320],
[0.2342, 0.1980, 1.3273, 0.6320],
[0.2342, 0.1980, 1.3273, 0.6320]], device='cuda:0')
###まとめ###
デフォルトボックスを変形させるためのOffset情報を訓練する方法を紹介しました
IOUを使う目的は以下です
- 使えそうなデフォルトボックスを洗い出します
- デフォルトボックスの変形目標を探します
Offset情報を計算するための損失関数はsmooth_l1_lossとします
次の章は信頼度訓練を紹介したいと思います。