Single Shot Multibox Detection (SSD)实战(上)
Single Shot Multibox Detection (SSD)實戰(上)
介紹了邊界框、錨框、多尺度對象檢測和數據集。現在,我們將利用這些背景知識構建一個目標檢測模型:單次多盒檢測(SSD)。這種快速簡便的模式已經被廣泛應用。該模型的一些設計思想和實現細節也適用于其他對象檢測模型。
- Model
圖1顯示了一個SSD模型的設計。該模型的主要組成部分是一個基本網絡塊和若干個串聯的多尺度特征塊。在這里,基網絡塊用于提取原始圖像的特征,一般采用深度卷積神經網絡的形式。關于SSDs的論文選擇在分類層之前放置一個截斷的VGG,但現在這通常被ResNet取代。我們可以設計基礎網絡,使其輸出更大的高度和寬度。這樣,基于這個特征圖生成更多的錨框,允許我們檢測更小的對象。接下來,每個多尺度要素塊都會減少上一層提供的要素映射的高度和寬度(例如,它可以將尺寸縮小一半)。然后使用特征映射中的每個元素來擴展輸入圖像上的感受野。這樣,多尺度特征塊越接近圖1頂部,其輸出特征圖越小,基于特征圖生成的錨框越少。此外,特征塊越接近頂部,特征圖中每個元素的感受野越大,越適合檢測較大的物體。由于SSD根據基本網絡塊和每個多尺度特征塊生成不同數量的不同大小的錨盒,然后預測錨盒的類別和偏移量(即預測的邊界框),以檢測不同大小的對象,因此SSD是一種多尺度目標檢測模型。
Fig. 1 The SSD is composed of a base network block and several multiscale feature blocks connected in a series.
接下來,我們將描述圖1中模塊的實現。首先,我們需要討論類別預測和包圍盒預測的實現。
1.1. Category Prediction Layer
將對象類別的數目設置為問問. 在這種情況下,錨盒類別的數量是q+1,0表示只包含背景的定位框。對于特定比例,將要素映射的高度和寬度分別設置為h和w。如果我們以每個元素為中心來生成錨箱,我們需要對hwa錨箱。如果我們使用全連接層(FCN)作為輸出,這可能會導致模型參數過多。如何使用卷積層通道輸出類別預測。SSD采用相同的方法來降低模型復雜度。具體地說,類別預測層使用保持輸入高度和寬度的卷積層。因此,輸出和輸入與特征映射的寬度和高度的空間坐標一一對應。假設輸出和輸入具有相同的空間坐標(x,y),坐標的通道(x,y)在輸出特征圖上,包含使用輸入特性圖坐標生成的所有定位框的類別預測(x,y)作為中心。因此,有a(q+1)輸出通道,輸出通道索引為i(q+1)+ji(q+1)+j(0≤j≤q0≤j≤q)表示類別索引的預測j對于錨箱索引。我們將定義這種類型的類別預測層。在我們指定參數a和q之后,它使用3×3卷積層,填充為1。這個卷積層的輸入和輸出的高度和寬度保持不變。
%matplotlib inline
from d2l
import mxnet as d2l
from mxnet
import autograd, gluon, image, init, np, npx
from mxnet.gluon
import nn
npx.set_np()
def cls_predictor(num_anchors, num_classes):
return
nn.Conv2D(num_anchors * (num_classes + 1), kernel_size=3,
padding=1)
1.2. Bounding Box Prediction Layer
包圍盒預測層的設計與類別預測層的設計相似。唯一的區別是,在這里,我們需要為每個錨框預測4個偏移量,而不是q+1類別。
def bbox_predictor(num_anchors):
return nn.Conv2D(num_anchors * 4, kernel_size=3, padding=1)
1.3. Concatenating Predictions for Multiple Scales
如前所述,SSD使用基于多尺度的特征映射來生成錨盒并預測其類別和偏移量。由于不同尺度的特征映射,同一元素中心錨盒的形狀和數量不同,不同尺度下的預測輸出可能具有不同的形狀。
在下面的例子中,我們使用同一批數據構建兩個不同比例的特征映射,Y1和Y2。在這里,Y2的高度和寬度是Y1的一半。以類別預測為例,我們假設Y1和Y2特征映射中的每個元素生成五個(Y1)或三個(Y2)錨定框。當有10個對象類別時,類別預測輸出通道的數量為 5×(10+1)=55或3×(10+1)=33。預測輸出的格式是(批次大小、通道數、高度、寬度)。如您所見,除了批量大小,其他維度的大小是不同的。因此,我們必須將它們轉換成一致的格式,并將多個尺度的預測串聯起來,以便于后續的計算。
def forward(x, block):
block.initialize()return
block(x)
Y1 = forward(np.zeros((2, 8, 20, 20)), cls_predictor(5,10))
Y2 = forward(np.zeros((2, 16, 10, 10)), cls_predictor(3,10))
(Y1.shape, Y2.shape)
((2, 55, 20, 20), (2, 33, 10, 10))
通道尺寸包含具有相同中心的所有錨定盒的預測。我們首先將通道維度移動到最后一個維度。我們可以將批量大小轉換為相同的二進制大小(因為批量大小的預測是相同的)(batch size, height ×× width ×× number of channels),以便于后續在第一尺寸。
def flatten_pred(pred):
return
npx.batch_flatten(pred.transpose(0, 2, 3, 1))
def concat_preds(preds):
return np.concatenate([flatten_pred§ for
p in preds], axis=1)
因此,盡管Y1和Y2的形態不同,我們仍然可以將同一批次的兩個不同尺度的預測結果串聯起來。
concat_preds([Y1, Y2]).shape
(2, 25300)
1.4. Height and Width Downsample Block
對于多尺度目標檢測,我們定義了下面的下采樣塊,它將高度和寬度減少了50%。這個街區有兩個3×3,填充為1和a的卷積層2×2,以串聯方式連接的跨距為2的最大池化層。我們知道,3×3填充為1的卷積層不會改變特征映射的形狀。然而,隨后的池化層直接將特征圖的大小縮小了一半。因為1×2+(3?1)+(3?1)=6,輸出特征映射中的每個元素在形狀的輸入特征映射上都有一個接受域6×6。height和width downsample塊放大了輸出特征映射中每個元素的感受野。
def down_sample_blk(num_channels):
blk = nn.Sequential()for _ in range(2):blk.add(nn.Conv2D(num_channels, kernel_size=3, padding=1),nn.BatchNorm(in_channels=num_channels),nn.Activation('relu'))blk.add(nn.MaxPool2D(2))
return blk
通過在height和width下采樣塊中測試正向計算,我們可以看到它改變了輸入通道的數目,并使高度和寬度減半。
forward(np.zeros((2, 3, 20, 20)), down_sample_blk(10)).shape
(2, 10, 10, 10)
1.5. Base Network Block
基本網絡塊用于從原始圖像中提取特征。為了簡化計算,我們將構造一個基礎小網絡。該網絡由三個高度和寬度的下采樣塊串聯而成,因此在每一步中它的通道數加倍。當我們用輸入原始256×256圖像時,基礎網絡塊輸出具有該形狀的特征映射32×32。
def base_net():
blk = nn.Sequential()for num_filters in [16, 32, 64]:blk.add(down_sample_blk(num_filters))return blk
forward(np.zeros((2, 3, 256, 256)), base_net()).shape
(2, 64, 32, 32)
1.6. The Complete Model
SSD型號共包含五個模塊。每個模塊輸出一個特征映射,用于生成錨框并預測這些錨框的類別和偏移量。第一個模塊是基本網絡塊,模塊2到4個是高度和寬度下采樣塊,第五個模塊是一個全局最大池化層,它將高度和寬度減小到1。因此,模塊2到5都是圖1所示的多尺度特征塊。
def get_blk(i):
if i == 0:blk = base_net()elif i == 4:blk = nn.GlobalMaxPool2D()else:blk = down_sample_blk(128)
return blk
定義每個模塊的正向計算過程。與前面描述的卷積神經網絡相比,該模塊不僅返回卷積計算輸出的特征映射Y,而且返回由Y生成的當前尺度的錨盒及其預測的類別和偏移量。
def blk_forward(X, blk, size, ratio, cls_predictor, bbox_predictor):
Y = blk(X)anchors = npx.multibox_prior(Y, sizes=size, ratios=ratio)cls_preds = cls_predictor(Y)bbox_preds = bbox_predictor(Y)return (Y, anchors, cls_preds, bbox_preds)
當我們在圖7.1中提到的更大的目標塊時,它必須生成一個更大的錨框。在這里,我們首先將0.2到1.05的間隔分成五個相等的部分,以確定不同比例的較小錨箱的尺寸:0.2、0.37、0.54等,然后根據SQRT(0.2×0.37)= 0.272,SQRT(0.37×0.54)= 0.447,
以及類似的公式,確定了不同尺度下較大錨箱的尺寸。
sizes = [[0.2, 0.272], [0.37, 0.447], [0.54, 0.619], [0.71, 0.79],
[0.88, 0.961]]
ratios = [[1, 2, 0.5]] * 5
num_anchors = len(sizes[0]) + len(ratios[0]) – 1
可以定義完整的模型,TinySSD。
class TinySSD(nn.Block):
def __init__(self, num_classes, **kwargs):super(TinySSD, self).__init__(**kwargs)self.num_classes = num_classesfor i in range(5):# The assignment statement is self.blk_i = get_blk(i)setattr(self, 'blk_%d' % i, get_blk(i))setattr(self, 'cls_%d' % i, cls_predictor(num_anchors,num_classes))setattr(self, 'bbox_%d' % i, bbox_predictor(num_anchors))
def forward(self, X):
anchors, cls_preds, bbox_preds = [None] * 5, [None] * 5, [None] * 5for i in range(5):# getattr(self, 'blk_%d' % i) accesses self.blk_iX, anchors[i], cls_preds[i], bbox_preds[i] = blk_forward(X, getattr(self, 'blk_%d' % i), sizes[i], ratios[i],getattr(self, 'cls_%d' % i), getattr(self, 'bbox_%d' % i))# In the reshape function, 0 indicates that the batch size remains# unchangedanchors = np.concatenate(anchors, axis=1)cls_preds = concat_preds(cls_preds)cls_preds = cls_preds.reshape(cls_preds.shape[0], -1, self.num_classes + 1)bbox_preds = concat_preds(bbox_preds)return anchors, cls_preds, bbox_preds
現在,我們創建一個SSD模型實例,并使用它對圖像minibatchx執行正向計算,它的高度和寬度為256像素。如前所述,第一個模塊輸出帶有形狀的特征映射32×32。因為模塊2到4是高度和寬度的下采樣塊,模塊5是一個全局池化層,并且特征圖中的每個元素都被用作4個錨框的中心,總共,在五個比例下為每個圖像生成錨框。
net = TinySSD(num_classes=1)
net.initialize()
X = np.zeros((32, 3, 256, 256))
anchors, cls_preds, bbox_preds = net(X)
print(‘output anchors:’, anchors.shape)
print(‘output class preds:’, cls_preds.shape)
print(‘output bbox preds:’, bbox_preds.shape)
output anchors: (1, 5444, 4)
output class preds: (32, 5444, 2)
output bbox preds: (32, 21776)
總結
以上是生活随笔為你收集整理的Single Shot Multibox Detection (SSD)实战(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Anchor Boxes示例实战
- 下一篇: Single Shot Multibox