CenterNet算法详解
Objects as Points-論文鏈接-代碼鏈接
目錄
- 1、需求解讀
- 2、CenterNet算法簡介
- 3、CenterNet算法詳解
- 3.1 CenterNet網(wǎng)絡(luò)結(jié)構(gòu)
- 3.2 CenterNet實(shí)現(xiàn)細(xì)節(jié)詳解
- 3.2.1 訓(xùn)練階段Heatmap生成
- 3.2.2 Heatmap上應(yīng)用高斯核
- 3.3 CenterNet損失函數(shù)
- 3.3.1 Heatmap損失函數(shù)
- 3.3.2 中心點(diǎn)偏移損失函數(shù)
- 3.3.3 目標(biāo)長寬損失函數(shù)
- 3.4 CenterNet推理階段
- 4、CenterNet網(wǎng)絡(luò)代碼實(shí)現(xiàn)
- 5、CenterNet效果展示與分析
- 5.1 CenterNet客觀效果展示與分析
- 5.2 CenterNet主觀效果展示與分析
- 6、總結(jié)與分析
- 參考資料
- 注意事項(xiàng)
1、需求解讀
??隨著基于Anchor的目標(biāo)檢測性能達(dá)到了極限,基于Anchor-free的目標(biāo)檢測算法成為了當(dāng)前的研究熱點(diǎn),具有代表性的工作包括CornerNet、FOCS與CenterNet等。除此之外,基于Anchor的目標(biāo)檢測算法存在著一些嚴(yán)重的問題,具體包括:(1)Anchros的定義在一定程度上會限制檢測算法的性能;(2)NMS等后處理操作會降低整個(gè)檢測算法的速度。為了解決這些問題,基于Anchor-free的目標(biāo)檢測算法應(yīng)運(yùn)而生,本文對CenterNet目標(biāo)檢測算法進(jìn)行詳細(xì)的剖析。
2、CenterNet算法簡介
??CenterNet是一個(gè)基于Anchor-free的目標(biāo)檢測算法,該算法是在CornerNet算法的基礎(chǔ)上改進(jìn)而來的。與單階段目標(biāo)檢測算法yolov3相比,該算法在保證速度的前提下,精度提升了4個(gè)百分點(diǎn)。與其它的單階段或者雙階段目標(biāo)檢測算法相比,該算法具有以下的優(yōu)勢:
- (1)該算法去除低效復(fù)雜的Anchors操作,進(jìn)一步提升了檢測算法性能;
- (2)該算法直接在heatmap圖上面執(zhí)行了過濾操作,去除了耗時(shí)的NMS后處理操作,進(jìn)一步提升了整個(gè)算法的運(yùn)行速度;
- (3)該算法不僅可以應(yīng)用到2D目標(biāo)檢測中,經(jīng)過簡單的改變它還可以應(yīng)用3D目標(biāo)檢測與人體關(guān)鍵點(diǎn)檢測等其它的任務(wù)中,即具有很好的通用性。
3、CenterNet算法詳解
3.1 CenterNet網(wǎng)絡(luò)結(jié)構(gòu)
??上圖展示了CenterNet網(wǎng)絡(luò)的整體結(jié)構(gòu),整個(gè)網(wǎng)絡(luò)結(jié)構(gòu)比較簡單。
- (1)最左邊表示輸入圖片。輸入圖片需要裁減到512*512大小,即長邊縮放到512,短邊補(bǔ)0,具體的效果如下圖所示,由于原圖的W>512,因而直接將其縮放為512;由于原圖的H<512,因而對其執(zhí)行補(bǔ)0操作;
- (2)中間表示基準(zhǔn)網(wǎng)絡(luò),論文中嘗試了Hourglass、ResNet與DLA3種網(wǎng)絡(luò)架構(gòu),各個(gè)網(wǎng)絡(luò)架構(gòu)的精度及幀率為:Resnet-18 with up-convolutional layers:28.1% coco and 142 FPS、DLA-34:37.4% COCOAP and 52 FPS、Hourglass-104:45.1% COCOAP and 1.4 FPS。
??上圖展示了3中不同的網(wǎng)絡(luò)架構(gòu),圖(a)表示Hourglass網(wǎng)絡(luò),該網(wǎng)絡(luò)是在ECCV2016中的Stacked hourglass networks for human pose estimation論文中提出的一種網(wǎng)絡(luò),用來解決人體位姿估計(jì)問題,其思路主要通過將多個(gè)漏斗形狀的網(wǎng)絡(luò)堆疊起來,從而獲得多尺度信息,具體的細(xì)節(jié)請參考該博客。圖(b)表示帶有反卷積的ResNet網(wǎng)絡(luò),作者在每一個(gè)上采樣層之前增加了一個(gè)3*3的膨脹卷積,即先使用反卷積來改變膨脹卷積的通道個(gè)數(shù),然后使用反卷積來對特征映射執(zhí)行上采樣操作。圖?表示用于語義分割的DLA34網(wǎng)絡(luò);圖d表示改變的DLA34網(wǎng)絡(luò),該網(wǎng)絡(luò)在原始的DLA34網(wǎng)絡(luò)的基礎(chǔ)上增加了更多的殘差連接,該網(wǎng)絡(luò)將Dense_Connection與FPN的思路融合起來,前者源于DenseNet,可以用來聚合語義信息,能夠提升模型推斷是“what”的能力;后者源于聚合空間信息,能夠提升模型推斷在“where”的能力,具體的細(xì)節(jié)如下圖所示。
- (3)最右邊表示預(yù)測模塊,該模塊包含3個(gè)分支,具體包括中心點(diǎn)heatmap圖分支、中心點(diǎn)offset分支、目標(biāo)大小分支。heatmap圖分支包含C個(gè)通道,每一個(gè)通道包含一個(gè)類別,heatmap中白色的亮區(qū)域表示目標(biāo)的中心 點(diǎn)位置;中心點(diǎn)offset分支用來彌補(bǔ)將池化后的低heatmap上的點(diǎn)映射到原圖中所帶來的像素誤差;目標(biāo)大小分支用來預(yù)測目標(biāo)矩形框的w與h偏差值。
3.2 CenterNet實(shí)現(xiàn)細(xì)節(jié)詳解
3.2.1 訓(xùn)練階段Heatmap生成
??CenterNet將目標(biāo)檢測問題轉(zhuǎn)換成中心點(diǎn)預(yù)測問題,即用目標(biāo)的中心點(diǎn)來表示該目標(biāo),并通過預(yù)測目標(biāo)中心點(diǎn)的偏移量與寬高來獲取目標(biāo)的矩形框。Heatmap表示分類信息,每一個(gè)類別將會產(chǎn)生一個(gè)單獨(dú)的Heatmap圖。對于每張Heatmap圖而言,當(dāng)某個(gè)坐標(biāo)處包含目標(biāo)的中心點(diǎn)時(shí),則會在該目標(biāo)處產(chǎn)生一個(gè)關(guān)鍵點(diǎn),我們利用高斯圓來表示整個(gè)關(guān)鍵點(diǎn),下圖展示了具體的細(xì)節(jié)。
??生成Heatmap圖的具體步驟如下所示:
-
步驟1-將輸入的圖片縮放成512*512大小,對該圖像執(zhí)行R=4的下采樣操作之后,獲得一個(gè)128*128大小的Heatmap圖;
-
步驟2-將輸入圖片中的Box縮放到128*128大小的Heatmap圖上面,計(jì)算該Box的中心點(diǎn)坐標(biāo),并執(zhí)行向下取整操作,并將其定義為point;
-
步驟3-根據(jù)目標(biāo)Box大小來計(jì)算高斯圓的半徑R;
??關(guān)于高斯圓的半徑確定,主要還是依賴于目標(biāo)box的寬高, 實(shí)際情況下通常會取IOU=0.7,即下圖中的overlap=0.7作為臨界值,然后分別計(jì)算出三種情況的半徑,取最小值作為高斯核的半徑R,具體的實(shí)現(xiàn)細(xì)節(jié)如下圖所示:
(1)情況1-預(yù)測框pred_bbox包含gt_bbox框,對應(yīng)于下圖中的第1種情況,將整個(gè)IoU公式展開之后,成為一個(gè)二元一次方程的求解問題。
(2)情況2-gt_bbox包含預(yù)測框pred_bbox框,對應(yīng)于下圖中的第2種情況,將整個(gè)IoU公式展開之后,成為一個(gè)二元一次方程的求解問題。
(3)情況3-gt_bbox與預(yù)測框pred_bbox框相互重疊,對應(yīng)于下圖中的第3種情況,將整個(gè)IoU公式展開之后,成為一個(gè)二元一次方程的求解問題。
-
步驟4-在128*128大小的Heatmap圖上面,以point為中心點(diǎn),半徑為R計(jì)算高斯值,point點(diǎn)處數(shù)值最大,隨著半徑R的增加數(shù)值不斷減小;
??上圖展示了一個(gè)樣例,左邊表示經(jīng)過裁剪之后的512512大小的輸入圖片,右邊表示經(jīng)過高斯操作之后生成的128128大小的Heatmap圖。由于圖中包含兩只貓,這兩只貓屬于一個(gè)類別,因此在同一個(gè)Heatmap圖上面生成了兩個(gè)高斯圓,高斯圓的大小與矩形框的大小有關(guān)。
3.2.2 Heatmap上應(yīng)用高斯核
??Heatmap上的關(guān)鍵點(diǎn)之所以采用二維高斯核來表示,是由于對于在目標(biāo)中心點(diǎn)附近的一些點(diǎn),其預(yù)測出來的pre_box和gt_box的IOU可能會大于0.7,不能直接對這些預(yù)測值進(jìn)行懲罰,需要溫和一點(diǎn),所以采用高斯核。該問題在Corner算法中就已經(jīng)存在,如下圖所示,我們在設(shè)置gt_bbox的heatmap時(shí),不僅僅只在中心點(diǎn)的位置設(shè)置標(biāo)簽1,圖中紅色的矩形框表示gt_bbox,但是綠色的矩形框其實(shí)也可以很好的包圍該目標(biāo),即我們在檢測的過程中如何獲得像綠色框這樣的矩形框時(shí),我們也要保存它。通俗一點(diǎn)來講,只要預(yù)測的corner點(diǎn)在中心點(diǎn)的某一個(gè)半徑r內(nèi),而且該矩形框與gt_bbox之間的IoU大于0.7時(shí),我們將這些點(diǎn)處的值設(shè)置為一個(gè)高斯分布的數(shù)值,而不是數(shù)值0。
3.3 CenterNet損失函數(shù)
??整個(gè)CenterNet的損失函數(shù)包含3個(gè)部分,LkL_{k}Lk?表示 heatmap中心點(diǎn)損失,LoffL_{off}Loff?表示目標(biāo)中心點(diǎn)偏移損失,LsizeL_{size}Lsize?表示目標(biāo)長寬損失函數(shù)。
3.3.1 Heatmap損失函數(shù)
??上圖展示了Heatmap損失函數(shù),該函數(shù)是在Focal Loss的基礎(chǔ)上進(jìn)行了改進(jìn),其中的α\alphaα與β\betaβ是兩個(gè)超參數(shù),用來均衡難易樣本;YxycY_{xyc}Yxyc?表示GT值,Y^xyc\hat{Y} _{xyc}Y^xyc?表示預(yù)測值;N表示關(guān)鍵點(diǎn)的個(gè)數(shù)。
- 當(dāng)Y^xyc\hat{Y} _{xyc}Y^xyc?=1時(shí),易分類樣本的預(yù)測值接近為1,此時(shí)(1?Y^xyc)α({1-\hat{Y} _{xyc}})^{\alpha }(1?Y^xyc?)α就表示一個(gè)很小的數(shù)值,此時(shí)損失函數(shù)的數(shù)值就比較小,起到了降低該樣本權(quán)重的作用。
- 當(dāng)Y^xyc\hat{Y} _{xyc}Y^xyc?=1時(shí),難分類樣本的預(yù)測值接近為0,此時(shí)(1?Y^xyc)α({1-\hat{Y} _{xyc}})^{\alpha }(1?Y^xyc?)α就表示一個(gè)較大的數(shù)值,此時(shí)損失函數(shù)的數(shù)值就比較大,起到了增加該樣本權(quán)重的作用。
- 當(dāng)Y^xyc\hat{Y} _{xyc}Y^xyc?!=1時(shí),為了防止預(yù)測值Y^xyc\hat{Y} _{xyc}Y^xyc?過高的接近于1,利用(1?Y^xyc)α({1-\hat{Y} _{xyc}})^{\alpha }(1?Y^xyc?)α來充當(dāng)懲罰項(xiàng),而(1?Yxyc)β({1-{Y} _{xyc}})^{\beta }(1?Yxyc?)β這個(gè)參數(shù)距離中心點(diǎn)越近,其數(shù)值越小,用來進(jìn)一步減輕這個(gè)懲罰力度。
3.3.2 中心點(diǎn)偏移損失函數(shù)
??上圖展示了LoffL_{off}Loff?損失函數(shù),其中O^p~{ \hat{O} \tilde{p} }O^p~?表示網(wǎng)絡(luò)預(yù)測的偏移量數(shù)值,p表示圖像中心點(diǎn)坐標(biāo),R表示Heatmap的縮放因子,p~\tilde{p}p~?表示縮放后中心點(diǎn)的近似整數(shù)坐標(biāo),整個(gè)過程利用L1 Loss計(jì)算正樣本塊的偏移損失。由于骨干網(wǎng)絡(luò)輸出的 feature map 的空間分辨率是原始輸入圖像的四分之一。即輸出 feature map 上的每一個(gè)像素點(diǎn)對應(yīng)到原始圖像的一個(gè)4x4 區(qū)域,這會帶來較大的誤差,因此引入了偏置的損失值。
??假設(shè)目標(biāo)中心點(diǎn)p為(125, 63),由于輸入圖片大小為512*512,縮放尺度R=4,因此縮放后的128x128尺寸下中心點(diǎn)坐標(biāo)為(31.25, 15.75), 相對于整數(shù)坐標(biāo)(31, 15)的偏移值即為(0.25, 0.75)。
3.3.3 目標(biāo)長寬損失函數(shù)
??上圖展示了目標(biāo)長寬損失函數(shù),其中N表示關(guān)鍵點(diǎn)的個(gè)數(shù),Sk表示目標(biāo)的真實(shí)尺寸,S^pk{\hat{S} pk}S^pk表示預(yù)測的尺寸,整個(gè)過程利用L1 Loss來計(jì)算正樣本塊的長寬損失。
3.4 CenterNet推理階段
??CenterNet網(wǎng)絡(luò)的推理階段的實(shí)現(xiàn)步驟如下所述:
- 步驟1-首先將輸入圖片縮到512*512大小;
- 步驟2-然后對輸入圖片執(zhí)行下采樣,并對下采樣后的圖像執(zhí)行預(yù)測,即在128*128大小的Heatmap上執(zhí)行預(yù)測;
- 步驟3-然后在128*128大小的Heatmap圖上面采用一個(gè)3*3大小的最大池化操作來獲取Heatmap中滿足條件的關(guān)鍵點(diǎn)(類似于anchor-based檢測中nms的效果),并選取100個(gè)關(guān)鍵點(diǎn);
- 步驟4-最后根據(jù)confidence閾值來過濾出最終的檢測結(jié)果。
4、CenterNet網(wǎng)絡(luò)代碼實(shí)現(xiàn)
1、Hourglass網(wǎng)絡(luò)部分代碼
class convolution(nn.Module):def __init__(self, k, inp_dim, out_dim, stride=1, with_bn=True):super(convolution, self).__init__()pad = (k - 1) // 2self.conv = nn.Conv2d(inp_dim, out_dim, (k, k), padding=(pad, pad), stride=(stride, stride), bias=not with_bn)self.bn = nn.BatchNorm2d(out_dim) if with_bn else nn.Sequential()self.relu = nn.ReLU(inplace=True)def forward(self, x):conv = self.conv(x)bn = self.bn(conv)relu = self.relu(bn)return reluclass fully_connected(nn.Module):def __init__(self, inp_dim, out_dim, with_bn=True):super(fully_connected, self).__init__()self.with_bn = with_bnself.linear = nn.Linear(inp_dim, out_dim)if self.with_bn:self.bn = nn.BatchNorm1d(out_dim)self.relu = nn.ReLU(inplace=True)def forward(self, x):linear = self.linear(x)bn = self.bn(linear) if self.with_bn else linearrelu = self.relu(bn)return reluclass residual(nn.Module):def __init__(self, k, inp_dim, out_dim, stride=1, with_bn=True):super(residual, self).__init__()self.conv1 = nn.Conv2d(inp_dim, out_dim, (3, 3), padding=(1, 1), stride=(stride, stride), bias=False)self.bn1 = nn.BatchNorm2d(out_dim)self.relu1 = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(out_dim, out_dim, (3, 3), padding=(1, 1), bias=False)self.bn2 = nn.BatchNorm2d(out_dim)self.skip = nn.Sequential(nn.Conv2d(inp_dim, out_dim, (1, 1), stride=(stride, stride), bias=False),nn.BatchNorm2d(out_dim)) if stride != 1 or inp_dim != out_dim else nn.Sequential()self.relu = nn.ReLU(inplace=True)def forward(self, x):conv1 = self.conv1(x)bn1 = self.bn1(conv1)relu1 = self.relu1(bn1)conv2 = self.conv2(relu1)bn2 = self.bn2(conv2)skip = self.skip(x)return self.relu(bn2 + skip)def make_layer(k, inp_dim, out_dim, modules, layer=convolution, **kwargs):layers = [layer(k, inp_dim, out_dim, **kwargs)]for _ in range(1, modules):layers.append(layer(k, out_dim, out_dim, **kwargs))return nn.Sequential(*layers)def make_layer_revr(k, inp_dim, out_dim, modules, layer=convolution, **kwargs):layers = []for _ in range(modules - 1):layers.append(layer(k, inp_dim, inp_dim, **kwargs))layers.append(layer(k, inp_dim, out_dim, **kwargs))return nn.Sequential(*layers)class MergeUp(nn.Module):def forward(self, up1, up2):return up1 + up2def make_merge_layer(dim):return MergeUp()# def make_pool_layer(dim): # return nn.MaxPool2d(kernel_size=2, stride=2)def make_pool_layer(dim):return nn.Sequential()def make_unpool_layer(dim):return nn.Upsample(scale_factor=2)def make_kp_layer(cnv_dim, curr_dim, out_dim):return nn.Sequential(convolution(3, cnv_dim, curr_dim, with_bn=False),nn.Conv2d(curr_dim, out_dim, (1, 1)))def make_inter_layer(dim):return residual(3, dim, dim)def make_cnv_layer(inp_dim, out_dim):return convolution(3, inp_dim, out_dim)class kp_module(nn.Module):def __init__(self, n, dims, modules, layer=residual,make_up_layer=make_layer, make_low_layer=make_layer,make_hg_layer=make_layer, make_hg_layer_revr=make_layer_revr,make_pool_layer=make_pool_layer, make_unpool_layer=make_unpool_layer,make_merge_layer=make_merge_layer, **kwargs):super(kp_module, self).__init__()self.n = ncurr_mod = modules[0]next_mod = modules[1]curr_dim = dims[0]next_dim = dims[1]self.up1 = make_up_layer(3, curr_dim, curr_dim, curr_mod, layer=layer, **kwargs) self.max1 = make_pool_layer(curr_dim)self.low1 = make_hg_layer(3, curr_dim, next_dim, curr_mod,layer=layer, **kwargs)self.low2 = kp_module(n - 1, dims[1:], modules[1:], layer=layer, make_up_layer=make_up_layer, make_low_layer=make_low_layer,make_hg_layer=make_hg_layer,make_hg_layer_revr=make_hg_layer_revr,make_pool_layer=make_pool_layer,make_unpool_layer=make_unpool_layer,make_merge_layer=make_merge_layer,**kwargs) if self.n > 1 else \make_low_layer(3, next_dim, next_dim, next_mod,layer=layer, **kwargs)self.low3 = make_hg_layer_revr(3, next_dim, curr_dim, curr_mod,layer=layer, **kwargs)self.up2 = make_unpool_layer(curr_dim)self.merge = make_merge_layer(curr_dim)def forward(self, x):up1 = self.up1(x)max1 = self.max1(x)low1 = self.low1(max1)low2 = self.low2(low1)low3 = self.low3(low2)up2 = self.up2(low3)return self.merge(up1, up2)class exkp(nn.Module):def __init__(self, n, nstack, dims, modules, heads, pre=None, cnv_dim=256, make_tl_layer=None, make_br_layer=None,make_cnv_layer=make_cnv_layer, make_heat_layer=make_kp_layer,make_tag_layer=make_kp_layer, make_regr_layer=make_kp_layer,make_up_layer=make_layer, make_low_layer=make_layer, make_hg_layer=make_layer, make_hg_layer_revr=make_layer_revr,make_pool_layer=make_pool_layer, make_unpool_layer=make_unpool_layer,make_merge_layer=make_merge_layer, make_inter_layer=make_inter_layer, kp_layer=residual):super(exkp, self).__init__()self.nstack = nstackself.heads = headscurr_dim = dims[0]self.pre = nn.Sequential(convolution(7, 3, 128, stride=2),residual(3, 128, 256, stride=2)) if pre is None else preself.kps = nn.ModuleList([kp_module(n, dims, modules, layer=kp_layer,make_up_layer=make_up_layer,make_low_layer=make_low_layer,make_hg_layer=make_hg_layer,make_hg_layer_revr=make_hg_layer_revr,make_pool_layer=make_pool_layer,make_unpool_layer=make_unpool_layer,make_merge_layer=make_merge_layer) for _ in range(nstack)])self.cnvs = nn.ModuleList([make_cnv_layer(curr_dim, cnv_dim) for _ in range(nstack)])self.inters = nn.ModuleList([make_inter_layer(curr_dim) for _ in range(nstack - 1)])self.inters_ = nn.ModuleList([nn.Sequential(nn.Conv2d(curr_dim, curr_dim, (1, 1), bias=False),nn.BatchNorm2d(curr_dim)) for _ in range(nstack - 1)])self.cnvs_ = nn.ModuleList([nn.Sequential(nn.Conv2d(cnv_dim, curr_dim, (1, 1), bias=False),nn.BatchNorm2d(curr_dim)) for _ in range(nstack - 1)])## keypoint heatmapsfor head in heads.keys():if 'hm' in head:module = nn.ModuleList([make_heat_layer(cnv_dim, curr_dim, heads[head]) for _ in range(nstack)])self.__setattr__(head, module)for heat in self.__getattr__(head):heat[-1].bias.data.fill_(-2.19)else:module = nn.ModuleList([make_regr_layer(cnv_dim, curr_dim, heads[head]) for _ in range(nstack)])self.__setattr__(head, module)self.relu = nn.ReLU(inplace=True)def forward(self, image):# print('image shape', image.shape)inter = self.pre(image)outs = []for ind in range(self.nstack):kp_, cnv_ = self.kps[ind], self.cnvs[ind]kp = kp_(inter)cnv = cnv_(kp)out = {}for head in self.heads:layer = self.__getattr__(head)[ind]y = layer(cnv)out[head] = youts.append(out)if ind < self.nstack - 1:inter = self.inters_[ind](inter) + self.cnvs_[ind](cnv)inter = self.relu(inter)inter = self.inters[ind](inter)return outsdef make_hg_layer(kernel, dim0, dim1, mod, layer=convolution, **kwargs):layers = [layer(kernel, dim0, dim1, stride=2)]layers += [layer(kernel, dim1, dim1) for _ in range(mod - 1)]return nn.Sequential(*layers)class HourglassNet(exkp):def __init__(self, heads, num_stacks=2):n = 5dims = [256, 256, 384, 384, 384, 512]modules = [2, 2, 2, 2, 2, 4]super(HourglassNet, self).__init__(n, num_stacks, dims, modules, heads,make_tl_layer=None,make_br_layer=None,make_pool_layer=make_pool_layer,make_hg_layer=make_hg_layer,kp_layer=residual, cnv_dim=256)def get_large_hourglass_net(num_layers, heads, head_conv):model = HourglassNet(heads, 2)return model5、CenterNet效果展示與分析
5.1 CenterNet客觀效果展示與分析
??上表展示了CenterNet目標(biāo)檢測在COCO驗(yàn)證集上面的精度與速度。第1行展示了利用Hourglass-104作為基準(zhǔn)網(wǎng)絡(luò)后不僅能夠獲得40.4AP,而且可以獲得14FPS的速度;第2行展示了利用DLA-34作為基準(zhǔn)網(wǎng)絡(luò)后獲得的AP與FPS;第3行與第4行分別展示了ResNet-101與ResNet-18基準(zhǔn)網(wǎng)絡(luò)在COCO驗(yàn)證集上面的效果。通過觀察我們可以發(fā)現(xiàn),基于DLA-34的基準(zhǔn)網(wǎng)絡(luò)能夠在精度與速度之間達(dá)到一個(gè)折中。
??上表展示了CenterNet算法在COCO關(guān)鍵點(diǎn)驗(yàn)證集上面的測試效果。通過觀察我們可以得出以下的初步結(jié)論:(1)基于Hourglass的基準(zhǔn)網(wǎng)絡(luò)可以獲得更高的精度,但是速度卻很難滿足實(shí)時(shí)場景的需求;(2)基于DLA-34的基準(zhǔn)網(wǎng)絡(luò)不僅可以獲得更高的精度,而且可以獲得較好的精度。(3)該算法的精度接近于很多state-of-art的行人位姿估計(jì)算法。
5.2 CenterNet主觀效果展示與分析
??上圖展示了CenterNet檢測算法在一張測試圖片上面的測試結(jié)果。左邊展示的是對應(yīng)的Heatmap圖,圖中的褐色點(diǎn)表示該算法輸出的中心點(diǎn)坐標(biāo),右邊表示該算法的檢測結(jié)果。
??上圖展示了CenterNet人體位姿估計(jì)算法在一張測試圖片上面的測試結(jié)果。最左邊展示的是目標(biāo)中心點(diǎn)的Heatmap圖,中間圖表示的是輸出的人體關(guān)鍵點(diǎn)Heatmap圖,最右邊表示的是CenterNet人體位姿估計(jì)算法的輸出結(jié)果,該算法在這種復(fù)雜的場景下仍然獲得了較高的精度。
??上圖展示了CenterNet目標(biāo)檢測算法、CenterNet人體位姿估計(jì)算法、CenterNet 3D目標(biāo)檢測算法在一些復(fù)雜的測試場景上面的測試效果。通過觀察我們可以發(fā)現(xiàn)該算法在不同的復(fù)雜場景下仍然得到較高的精度。
6、總結(jié)與分析
??CenterNet是一個(gè)基于Anchor-free的目標(biāo)檢測算法。通過觀察上圖,我們可以發(fā)現(xiàn)該算法的精度幾乎超過了當(dāng)時(shí)所有的單階段與雙階段目標(biāo)檢測算法,包括Faster-RCNN、RetinaNet和Yolov3。由于該算法去除了耗時(shí)的Anchors與NMS后處理操作,因而該算法具有較快的運(yùn)行速度,適合部署在一些低性能的嵌入式設(shè)備中。除此之外,經(jīng)過實(shí)際的測試我們會發(fā)現(xiàn)該算法在多個(gè)實(shí)際場景中都能取得較高的檢測精度。
參考資料
[1] 原始論文
[2] 博客1
[3] 博客2
注意事項(xiàng)
[1] 該博客是本人原創(chuàng)博客,如果您對該博客感興趣,想要轉(zhuǎn)載該博客,請與我聯(lián)系(qq郵箱:1575262785@qq.com),我會在第一時(shí)間回復(fù)大家,謝謝大家的關(guān)注。
[2] 由于個(gè)人能力有限,該博客可能存在很多的問題,希望大家能夠提出改進(jìn)意見。
[3] 如果您在閱讀本博客時(shí)遇到不理解的地方,希望您可以聯(lián)系我,我會及時(shí)的回復(fù)您,和您交流想法和意見,謝謝。
[4] 本人業(yè)余時(shí)間承接各種本科畢設(shè)設(shè)計(jì)和各種項(xiàng)目,包括圖像處理(數(shù)據(jù)挖掘、機(jī)器學(xué)習(xí)、深度學(xué)習(xí)等)、matlab仿真、python算法及仿真等,有需要的請加QQ:1575262785詳聊,備注“項(xiàng)目”!!!
總結(jié)
以上是生活随笔為你收集整理的CenterNet算法详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vs2008激活、序列号
- 下一篇: YOLOv5算法详解