Anchor Boxes示例实战
Anchor Boxes示例實戰
目標檢測算法通常對輸入圖像中的大量區域進行采樣,判斷這些區域是否包含感興趣的目標,并調整這些區域的邊緣,以便更準確地預測目標的真實邊界框。不同的模型可能使用不同的區域采樣方法。在這里,我們介紹一種這樣的方法:它生成多個大小和縱橫比不同的邊框,同時以每個像素為中心。這些邊界框稱為錨框。我們將練習基于錨盒的對象檢測。
首先,導入此部分所需的包或模塊。在這里,我們修改了NumPy的打印精度。因為打印張量實際上調用了NumPy的print函數,所以本節打印的張量中的浮點數更簡潔。
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import gluon, image, np, npx
np.set_printoptions(2)
npx.set_np()
- Generating Multiple Anchor Boxes
img = image.imread(’…/img/catdog.jpg’).asnumpy()
h, w = img.shape[0:2]
print(h, w)
X = np.random.uniform(size=(1, 3, h, w)) # Construct input data
Y = npx.multibox_prior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])
Y.shape
561 728
(1, 2042040, 4)
我們可以看到返回的錨框變量y的形狀是(批大小,錨框數量,4)(batch size, number of anchor boxes, 4)。將錨框變量y的形狀更改為(圖像高度、圖像寬度、以同一像素為中心的錨框數量,4)(image height, image width, number of anchor boxes centered on the same pixel, 4)后,我們可以獲得所有以指定像素位置為中心的錨定框。在下面的示例中,我們訪問位于(250,250)中心的第一個錨定框。它有四個元素:位于錨定框左上角的x、y軸坐標和右下角的x、y軸坐標。x軸和y軸的坐標值分別除以圖像的寬度和高度,因此值范圍在0和1之間。
boxes = Y.reshape(h, w, 5, 4)
boxes[250, 250, 0, :]
array([0.06, 0.07, 0.63, 0.82])
為了描述圖像中所有以一個像素為中心的錨框,我們首先定義show_bboxes函數來繪制圖像上的多個邊界框。
#@save
def show_bboxes(axes, bboxes, labels=None, colors=None):
"""Show bounding boxes."""def _make_list(obj, default_values=None):if obj is None:obj = default_valueselif not isinstance(obj, (list, tuple)):obj = [obj]return objlabels = _make_list(labels)colors = _make_list(colors, ['b', 'g', 'r', 'm', 'c'])for i, bbox in enumerate(bboxes):color = colors[i % len(colors)]rect = d2l.bbox_to_rect(bbox.asnumpy(), color)axes.add_patch(rect)if labels and len(labels) > i:text_color = 'k' if color == 'w' else 'w'axes.text(rect.xy[0], rect.xy[1], labels[i],va='center', ha='center', fontsize=9, color=text_color,bbox=dict(facecolor=color, lw=0))
正如我們剛才看到的,變量框中x軸和y軸的坐標值分別除以圖像的寬度和高度。在繪制圖像時,我們需要恢復錨定框的原始坐標值,從而定義變量bbox_scale。現在,我們可以在圖像中以(250,250)為中心繪制所有的錨框。你也可以看到一個0.75大小的錨框的圖像。
d2l.set_figsize((3.5, 2.5))
bbox_scale = np.array((w, h, w, h))
fig = d2l.plt.imshow(img)
show_bboxes(fig.axes, boxes[250, 250, :, :] * bbox_scale,
['s=0.75, r=1', 's=0.5, r=1', 's=0.25, r=1', 's=0.75, r=2','s=0.75, r=0.5'])
2. Intersection over Union
我們剛剛提到了錨盒很好地覆蓋了圖像中的狗。如果已知目標的真實邊界框,這里的“井”如何量化?相似性是一種直觀地度量盒與地之間的相似性的方法。我們知道Jaccard索引可以度量兩個集合之間的相似性。給定集合A和B,其Jaccard索引是其交集的大小除以其并集的大小:
J(A, B)= |A∩B|/ |A∪B|
實際上,我們可以將邊界框的像素區域視為像素集合。這樣,我們就可以通過像素集的Jaccard索引來度量兩個邊界框的相似度。當我們測量兩個邊界框的相似性時,我們通常將Jaccard索引稱為intersection over union(IoU),即兩個邊界框的相交面積與并集面積的比值,如圖1所示。IoU的值范圍在0到1之間:0表示兩個邊界框之間沒有重疊的像素,而1表示兩個邊界框相等。
Fig. 1. IoU is the ratio of the intersecting area to the union area of two bounding boxes.
我們將使用IoU來測量錨定框和真實邊界框之間以及不同錨定框之間的相似性。
- Labeling Training Set Anchor Boxes
在訓練集中,我們將每個錨盒視為一個訓練示例。為了訓練目標檢測模型,我們需要為每個錨框標記兩種類型的標簽:第一種是錨框中包含的目標的類別(類別),第二種是真實邊界框相對于錨定框的偏移量(offset)。在目標檢測中,首先生成多個錨框,預測每個錨框的類別和偏移量,根據預測的偏移量調整錨定框的位置,得到用于預測的邊界框,最后過濾出需要輸出的預測邊界框。
我們知道,在目標檢測訓練集中,每幅圖像都標有真實邊界框的位置和所包含目標的類別。錨盒生成后,我們主要根據與錨盒相似的真實邊界框的位置和類別信息對錨盒進行標記。那么,我們如何將真實邊界框指定給與它們類似的錨框呢?
Fig. 2 Assign ground-truth bounding boxes to anchor boxes
現在我們可以標記錨定框的類別和偏移量。如果錨箱A被指定為真實邊界框B,錨箱類別A設置為B類。以及錨箱A的偏移量,根據B的中心坐標的相對位置設置。還有一個以及兩個盒子的相對大小。由于數據集中不同方框的位置和大小可能不同,這些相對位置和相對大小通常需要一些特殊的轉換,以使偏移分布更加均勻,更易于擬合。
下面我們展示一個詳細的例子。我們為讀取圖像中的cat和dog定義了基本真實邊界框,其中第一個元素是category(0表示dog,1表示cat),其余四個元素是左上角x,y 軸坐標和右下角x、y的軸坐標(值范圍在0和1之間)。在這里,我們構造了五個錨框,用左上角和右下角的坐標來標記,它們被記錄為A0,…,A4。分別為(程序中的索引從0開始)。首先,畫出這些錨框和真實邊界框在圖像中的位置。
ground_truth = np.array([[0, 0.1, 0.08, 0.52, 0.92],
[1, 0.55, 0.2, 0.9, 0.88]])
anchors = np.array([[0, 0.1, 0.2, 0.3], [0.15, 0.2, 0.4, 0.4],
[0.63, 0.05, 0.88, 0.98], [0.66, 0.45, 0.8, 0.8],[0.57, 0.3, 0.92, 0.9]])
fig = d2l.plt.imshow(img)
show_bboxes(fig.axes, ground_truth[:, 1:] * bbox_scale, [‘dog’, ‘cat’], ‘k’)
show_bboxes(fig.axes, anchors * bbox_scale, [‘0’, ‘1’, ‘2’, ‘3’, ‘4’]);
可以使用multibox_target函數標記錨定框的類別和偏移量。此函數用于將背景類別設置為0,并將目標類別的整數索引從零遞增1(1表示dog,2表示cat)。我們在錨定框和真值邊界框中添加實例維數,并使用expand_dims函數構造形狀為(批次大小、類別數包括背景、錨框數量)的隨機預測結果。
labels = npx.multibox_target(np.expand_dims(anchors, axis=0),
np.expand_dims(ground_truth, axis=0),np.zeros((1, 3, 5)))
返回的結果中有三項,都是張量格式。第三項由標記為錨定框的類別表示。
labels[2]
array([[0., 1., 2., 0., 2.]])
根據錨框和真實邊界框在圖像中的位置來分析這些標記類別。首先,在所有“anchor box–ground-truth bounding box”對中,錨框A4的IoU對ground-truth盒的貓是最大的,所以錨盒類A4標記為cat。不考慮錨箱A4或者貓的ground-truth真實邊界框,在剩余的“nchor
box–ground-truth bounding box”對中,IoU最大的一對是錨框A1,而ground-truth盒的狗,則錨盒A1類被標記為狗。接下來,穿過剩余的三個未標記的錨箱。錨框A0最大IoU ground-truth包圍盒類別為dog,但IoU小于閾值(默認值為0.5),因此該類別被標記為背景;具有最大IoU的ground-truth真相邊界框的類別具有錨框A2是cat,IoU大于閾值,因此該類別被標記為cat;IoU最大的真相邊界框的類別,錨框A3是cat,但IoU小于閾值,因此該類別被標記為background。
返回值的第二項是一個mask變量,其形狀為(批大小,錨框數量的四倍)。mask變量中的元素與每個定位框的四個偏移值一一對應。因為我們不關心背景檢測,所以負類的偏移量不應該影響目標函數。通過乘以元素,mask變量中的0可以在計算目標函數之前過濾掉負的類偏移量。
labels[1]
array([[0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0.,1., 1., 1., 1.]])
返回的第一項是為每個定位框標記的四個偏移量值,負類定位框的偏移量標記為0。
labels[0]
array([[ 0.00e+00, 0.00e+00, 0.00e+00, 0.00e+00, 1.40e+00, 1.00e+01, 2.59e+00, 7.18e+00, -1.20e+00, 2.69e-01, 1.68e+00, -1.57e+00, 0.00e+00, 0.00e+00, 0.00e+00, 0.00e+00, -5.71e-01, -1.00e+00, -8.94e-07, 6.26e-01]])
- Bounding Boxes for Prediction
在模型預測階段,我們首先為圖像生成多個錨框,然后逐個預測這些錨框的類別和偏移量。然后,基于錨定框及其預測偏移量得到預測邊界框。當有多個錨盒時,同一個目標可以輸出許多相似的預測邊界框。為了簡化結果,我們可以去掉類似的預測邊界框。一種常用的方法稱為非最大抑制(NMS)。
讓我們來看看NMS是如何工作的。對于預測邊界框B,模型計算每個類別的預測概率。假設最大預測概率為p,與該概率相對應的范疇是B的預測范疇. 我們也指p作為預測邊界框B的置信水平. 在同一幅圖像上,我們對除背景外的其他預測類別的預測邊界框按置信度從高到低排序,得到列表L. 選擇預測邊界框B1以L的最高置信水平作為基線,并刪除所有帶有B1 IoU的非基準預測邊界框大于L的某個閾值. 這里的閾值是一個預設的超參數。在這一點上,我保留具有最高置信級別的預測邊界框,并刪除與之類似的其他預測邊界框。接下來,選擇預測邊界框B2以L的第二高信心水平作為基線,并使用B2刪除所有帶IoU的非基準預測邊界框大于L的某個閾值. 重復此過程,直到L中的所有預測邊界框被用作基線。此時,L中任意一對預測邊界框的IoU小于閾值。最后,輸出列表L中的所有預測邊界框.接下來,我們將看一個詳細的例子。首先,建造四個錨箱。為了簡單起見,我們假設預測的偏移量都為0。這意味著預測邊界框是錨定框。最后,我們為每個類別構造一個預測概率。
anchors = np.array([[0.1, 0.08, 0.52, 0.92], [0.08, 0.2, 0.56, 0.95],
[0.15, 0.3, 0.62, 0.91], [0.55, 0.2, 0.9, 0.88]])
offset_preds = np.array([0] * anchors.size)
cls_probs = np.array([[0] * 4, # Predicted probability for background
[0.9, 0.8, 0.7, 0.1], # Predicted
probability for dog
[0.1, 0.2, 0.3, 0.9]]) # Predicted
probability for cat
在圖像上打印預測邊界框及其置信級別。
fig = d2l.plt.imshow(img)
show_bboxes(fig.axes, anchors * bbox_scale,
['dog=0.9', 'dog=0.8', 'dog=0.7', 'cat=0.9'])
我們使用multibox_detection函數來執行NMS,并將閾值設置為0.5。這將向張量輸入添加一個示例維度。我們可以看到返回結果的形狀是(批量大小,錨框數量,6)。每行的6個元素表示同一預測邊界框的輸出信息。第一個元素是預測的類別索引,從0開始(0表示dog,1表示cat)。值-1表示NMS中的背景或刪除。第二個元素是預測邊界框的置信度。剩下的四個元素是x,y左上角和x、y軸坐標預測邊界框右下角的軸坐標(值范圍在0到1之間)。
output = npx.multibox_detection(
np.expand_dims(cls_probs, axis=0),np.expand_dims(offset_preds, axis=0),np.expand_dims(anchors, axis=0),nms_threshold=0.5)
output
array([[[ 0. , 0.9 , 0.1 , 0.08, 0.52, 0.92],
[ 1. , 0.9 , 0.55, 0.2 , 0.9 , 0.88],[-1. ,0.8 , 0.08, 0.2 , 0.56, 0.95],[-1. , 0.7 , 0.15, 0.3 , 0.62, 0.91]]])
我們移除了類別1的預測邊界框,并將NMS保留的結果可視化。
fig = d2l.plt.imshow(img)
for i in output[0].asnumpy():
if i[0] == -1:continuelabel = ('dog=', 'cat=')[int(i[0])] + str(i[1])
show_bboxes(fig.axes, [np.array(i[2:]) * bbox_scale], label)
在實際應用中,我們可以在執行NMS之前移除置信水平較低的預測邊界框,從而減少NMS的計算量。我們還可以過濾NMS的輸出,例如,只保留具有較高置信水平的結果作為最終輸出。
- Summary
We generate multiple anchor boxes with different sizes and aspect ratios, centered on each pixel.
IoU, also called Jaccard index, measures the similarity of two bounding boxes. It is the ratio of the intersecting area to the union area of two bounding boxes.
In the training set, we mark two types of labels for each anchor box: one is the category of the target contained in the anchor box and the other is the offset of the ground-truth bounding box relative to the anchor box.
When predicting, we can use non-maximum suppression (NMS) to remove similar prediction bounding boxes, thereby simplifying the results.
總結
以上是生活随笔為你收集整理的Anchor Boxes示例实战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 目标检测数据集The Object De
- 下一篇: Single Shot Multibox