錨框(anchor box)理解和代碼實(shí)現(xiàn)

極市導(dǎo)讀
?本文對(duì)錨框這一概念進(jìn)行介紹和解釋?zhuān)⒔o出了相關(guān)的代碼實(shí)現(xiàn)。?>>加入極市CV技術(shù)交流群,走在計(jì)算機(jī)視覺(jué)的最前沿
目標(biāo)檢測(cè)算法通常會(huì)在輸入圖像中采樣大量的區(qū)域,然后判斷這些區(qū)域中是否包含我們感興趣的目標(biāo),并調(diào)整區(qū)域邊界從而更準(zhǔn)確地預(yù)測(cè)目標(biāo)的真實(shí)邊界框(ground-truth bounding box)。不同的模型使用的區(qū)域采樣方法可能不同。這里我們介紹其中的一種方法:以每個(gè)像素為中心,生成多個(gè)縮放比和寬高比(aspect ratio)不同的邊界框。這些邊界框被稱(chēng)為錨框(anchor box)。---- 《動(dòng)手學(xué)深度學(xué)習(xí)v2》
上文表明,錨框不過(guò)是圖像中采樣的區(qū)域,也介紹了最簡(jiǎn)單的一種生成這些區(qū)域的方法。此外,目標(biāo)檢測(cè)算法會(huì)判斷這些區(qū)域是否有目標(biāo),是分類(lèi)任務(wù)。調(diào)整這些區(qū)域到目標(biāo)真實(shí)框是回歸任務(wù)。
假設(shè)輸入圖像的高度為?,寬度為 。以圖像的每個(gè)像素為中心生成不同形狀的錨框:比例為 ∈(0,1],寬高比為 >0。要生成多個(gè)不同形狀的錨框,設(shè)置一系列刻度 和一系列寬高比 。為了減少計(jì)算復(fù)雜度,只考慮包含 或 的組合,如下圖所示。

推導(dǎo)1:設(shè) w, h 為 圖像中錨框的實(shí)際寬高, W,H 為圖像的寬高。
由 和 和 。
對(duì) 和 歸一化 和 。
顯然,當(dāng) H = W 時(shí), , 。
推導(dǎo)2:設(shè) 和 為歸一化的小數(shù),可得到
公式1: 和 公式2:
和 。與推導(dǎo)1結(jié)論相同。
動(dòng)手學(xué)深度學(xué)習(xí)V2中的代碼,當(dāng)H = W 時(shí),和下面修改的結(jié)果是一致的。但當(dāng)H != W 時(shí), 二者結(jié)果并不相同。但是其實(shí)二者區(qū)別不大,不過(guò)是錨框的初始大小區(qū)別而已,而這不過(guò)是人自定義的。
import?torch
from?d2l?import?torch?as?d2l
#?torch.set_printoptions(2)??#?精簡(jiǎn)輸出精度
def?multibox_prior(data,?sizes,?ratios):
????"""生成以每個(gè)像素為中心具有不同形狀的錨框"""
????in_height,?in_width?=?data.shape[-2:]
????device,?num_sizes,?num_ratios?=?data.device,?len(sizes),?len(ratios)?#?3,?3
????boxes_per_pixel?=?(num_sizes?+?num_ratios?-?1)?#?每個(gè)像素的錨框數(shù)
????size_tensor?=?torch.tensor(sizes,?device=device)?#?list?轉(zhuǎn)為?tensor
????ratio_tensor?=?torch.tensor(ratios,?device=device)
????#?為了將錨點(diǎn)移動(dòng)到像素的中心,需要設(shè)置偏移量。
????#?因?yàn)橐粋€(gè)像素的的高為1且寬為1,我們選擇偏移我們的中心0.5
????offset_h,?offset_w?=?0.5,?0.5
????steps_h?=?1.0?/?in_height??#?在y軸上縮放步長(zhǎng)
????steps_w?=?1.0?/?in_width??#?在x軸上縮放步長(zhǎng)
????#?生成錨框的所有中心點(diǎn)
????center_h?=?(torch.arange(in_height,?device=device)?+?offset_h)?*?steps_h
????center_w?=?(torch.arange(in_width,?device=device)?+?offset_w)?*?steps_w
????shift_y,?shift_x?=?torch.meshgrid(center_h,?center_w)
????# center_h:tensor([0.1250, 0.3750, 0.6250, 0.8750])
????#?tensor([
????#???????[0.1250,?0.1250,?0.1250,?0.1250],
????#???????[0.3750,?0.3750,?0.3750,?0.3750],
????#???????[0.6250,?0.6250,?0.6250,?0.6250],
????#???????[0.8750,?0.8750,?0.8750,?0.8750]])?
????#?tensor([
????#???????[0.1250,?0.3750,?0.6250,?0.8750],
????#???????[0.1250,?0.3750,?0.6250,?0.8750],
????#???????[0.1250,?0.3750,?0.6250,?0.8750],
????#???????[0.1250,?0.3750,?0.6250,?0.8750]])
????shift_y,?shift_x?=?shift_y.reshape(-1),?shift_x.reshape(-1)
????#?全部每個(gè)像素中心點(diǎn)坐標(biāo)
????#?tensor([0.1250,?0.1250,?0.1250,?0.1250,?0.3750,?0.3750,?0.3750,?0.3750,?0.6250,
????#?????0.6250,?0.6250,?0.6250,?0.8750,?0.8750,?0.8750,?0.8750])?
????#?tensor([0.1250,?0.3750,?0.6250,?0.8750,?0.1250,?0.3750,?0.6250,?0.8750,?0.1250,
????#?????0.3750,?0.6250,?0.8750,?0.1250,?0.3750,?0.6250,?0.8750])
????#?生成“boxes_per_pixel”個(gè)高和寬,
????#?之后用于創(chuàng)建錨框的四角坐標(biāo)(xmin,xmax,ymin,ymax)
????##?動(dòng)手學(xué)深度學(xué)習(xí)V2?原始代碼
????#?w?=?torch.cat((size_tensor?*?torch.sqrt(ratio_tensor[0]),
????#????????????????sizes[0]?*?torch.sqrt(ratio_tensor[1:])))\
????#????????????????*?in_height?/?in_width??#?處理矩形輸入
????#?h?=?torch.cat((size_tensor?/?torch.sqrt(ratio_tensor[0]),
????#????????????????sizes[0]?/?torch.sqrt(ratio_tensor[1:])))
????#?#?除以2來(lái)獲得半高和半寬
????#?anchor_manipulations?=?torch.stack((-w,?-h,?w,?h)).T.repeat(
????#?????????????????????????????????????in_height?*?in_width,?1)?/?2
????##?更新后的代碼
????w_0?=?torch.cat((sizes[0]?*?torch.sqrt(in_height?*?ratio_tensor[:]?/?in_width),
?????????????????????size_tensor[1:]?*?torch.sqrt(in_height?*?ratio_tensor[0]?/?in_width)))
????h_0?=?torch.cat((sizes[0]?*?torch.sqrt(in_width?/?ratio_tensor[:]?/?in_height),?
?????????????????????size_tensor[1:]?*?torch.sqrt(in_width?/?ratio_tensor[0]?/?in_height)))
????#?除以2來(lái)獲得半高和半寬
????anchor_manipulations?=?torch.stack((-w_0,?-h_0,?w_0,?h_0)).T.repeat(
????????????????????????????????????????in_height?*?in_width,?1)?/?2
????#?每個(gè)中心點(diǎn)都將有“boxes_per_pixel”個(gè)錨框,
????#?所以生成含所有錨框中心的網(wǎng)格,重復(fù)了“boxes_per_pixel”次
????out_grid?=?torch.stack([shift_x,?shift_y,?shift_x,?shift_y],
????????????????dim=1).repeat_interleave(boxes_per_pixel,?dim=0)
????output?=?out_grid?+?anchor_manipulations
????return?output.unsqueeze(0)
img?=?d2l.plt.imread('d2l-zh/pytorch/img/catdog.jpg')
h,?w?=?img.shape[:2]
print(h,?w)
X?=?torch.rand(size=(1,?3,?4,?4))
Y?=?multibox_prior(X,?sizes=[0.75,?0.5,?0.25],?ratios=[1,?2,?0.5])
print(Y,?Y.shape)
顯示代碼修改
d2l.set_figsize()
bbox_scale?=?torch.tensor((w,?h,?w,?h))
fig?=?d2l.plt.imshow(img)
#?上述代碼按圖1 組合,故下面的順序作了調(diào)整。
#?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'])
show_bboxes(fig.axes,?boxes[250,?350,?:,?:]?*?bbox_scale,
????????????['s=0.75,?r=1',?'s=0.75,?r=2',?'s=0.75,?r=0.5',?'s=0.5,?r=1',
?????????????'s=0.25,?r=1'])

參考:
13.4. 錨框 - 動(dòng)手學(xué)深度學(xué)習(xí) 2.0.0-beta0 documentation(https://zh-v2.d2l.ai/chapter_computer-vision/anchor.html#id2)
2. 《動(dòng)手學(xué)習(xí)深度學(xué)習(xí)》13.4錨框
公眾號(hào)后臺(tái)回復(fù)“CVPR 2022”獲取論文合集打包下載~

#?CV技術(shù)社群邀請(qǐng)函?#

備注:姓名-學(xué)校/公司-研究方向-城市(如:小極-北大-目標(biāo)檢測(cè)-深圳)
即可申請(qǐng)加入極市目標(biāo)檢測(cè)/圖像分割/工業(yè)檢測(cè)/人臉/醫(yī)學(xué)影像/3D/SLAM/自動(dòng)駕駛/超分辨率/姿態(tài)估計(jì)/ReID/GAN/圖像增強(qiáng)/OCR/視頻理解等技術(shù)交流群
每月大咖直播分享、真實(shí)項(xiàng)目需求對(duì)接、求職內(nèi)推、算法競(jìng)賽、干貨資訊匯總、與?10000+來(lái)自港科大、北大、清華、中科院、CMU、騰訊、百度等名校名企視覺(jué)開(kāi)發(fā)者互動(dòng)交流~

