Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例_第1頁(yè)
Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例_第2頁(yè)
Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例_第3頁(yè)
Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例_第4頁(yè)
Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例_第5頁(yè)
已閱讀5頁(yè),還剩39頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第Keras搭建M2Det目標(biāo)檢測(cè)平臺(tái)示例目錄什么是M2det目標(biāo)檢測(cè)算法M2det實(shí)現(xiàn)思路一、預(yù)測(cè)部分1、主干網(wǎng)絡(luò)介紹2、FFM1特征初步融合3、細(xì)化U型模塊TUM4、FFM2特征加強(qiáng)融合5、注意力機(jī)制模塊SFAM6、從特征獲取預(yù)測(cè)結(jié)果7、預(yù)測(cè)結(jié)果的解碼8、在原圖上進(jìn)行繪制二、訓(xùn)練部分1、真實(shí)框的處理2、利用處理完的真實(shí)框與對(duì)應(yīng)圖片的預(yù)測(cè)結(jié)果計(jì)算loss訓(xùn)練自己的M2Det模型一、數(shù)據(jù)集的準(zhǔn)備二、數(shù)據(jù)集的處理三、開始網(wǎng)絡(luò)訓(xùn)練四、訓(xùn)練結(jié)果預(yù)測(cè)

什么是M2det目標(biāo)檢測(cè)算法

一起來看看M2det的keras實(shí)現(xiàn)吧,順便訓(xùn)練一下自己的數(shù)據(jù)。

常見的特征提取方法如圖所示有SSD形,F(xiàn)PN形,STDN形:

SSD型:使用了主干網(wǎng)絡(luò)的最后兩層,再加上4個(gè)使用stride=2卷積的下采樣層構(gòu)成;

FPN型:也稱為U型網(wǎng)絡(luò),經(jīng)過上采樣操作,然后對(duì)應(yīng)融合相同的scale;

STDN型:基于DenseNet的最后一個(gè)denseblock,通過池化和scale-transfer操作來構(gòu)建;

這三者有一定的缺點(diǎn):

一是均基于分類網(wǎng)絡(luò)作為主干提取,對(duì)目標(biāo)檢測(cè)任務(wù)而言特征表示可能不夠;

二是每個(gè)featuremap僅由主干網(wǎng)絡(luò)的singlelevel給出,不夠全面

M2det論文新提出MLFPN型,整體思想是Multi-levelMulti-scale。是一種更加有效的適合于檢測(cè)的特征金字塔結(jié)構(gòu)。

源碼下載

M2det實(shí)現(xiàn)思路

一、預(yù)測(cè)部分

1、主干網(wǎng)絡(luò)介紹

M2det采用可以采用VGG和ResNet101作為主干特征提取網(wǎng)絡(luò),上圖的backbonenetwork指的就是VGG和Resnet101,本文以VGG為例介紹。

M2DET采用的主干網(wǎng)絡(luò)是VGG網(wǎng)絡(luò),關(guān)于VGG的介紹大家可以看我的另外一篇博客

/article/246917.htm

在m2det中,我們?nèi)サ袅巳康娜B接層,只保留了卷積層和最大池化層,即Conv1到Conv5。

1、一張?jiān)紙D片被resize到(320,320,3)。

2、conv1兩次[3,3]卷積網(wǎng)絡(luò),輸出的特征層為64,輸出為(320,320,64),再2X2最大池化,輸出net為(160,160,64)。

3、conv2兩次[3,3]卷積網(wǎng)絡(luò),輸出的特征層為128,輸出net為(160,160,128),再2X2最大池化,輸出net為(80,80,128)。

4、conv3三次[3,3]卷積網(wǎng)絡(luò),輸出的特征層為256,輸出net為(80,80,256),再2X2最大池化,輸出net為(40,40,256)。

5、conv4三次[3,3]卷積網(wǎng)絡(luò),輸出的特征層為512,輸出net為(40,40,512),再2X2最大池化,此時(shí)不進(jìn)行池化,輸出net為(40,40,512)。conv4-3的結(jié)果會(huì)進(jìn)入FFM1進(jìn)行特征的融合。

6、conv5三次[3,3]卷積網(wǎng)絡(luò),輸出的特征層為1024,輸出net為(40,40,1024),再2X2最大池化,輸出net為(20,20,1024)。池化后的結(jié)果會(huì)進(jìn)入FFM1進(jìn)行特征的融合。

fromkerasimportModel

fromkeras.layersimportConv2D,MaxPooling2D

defVGG16(inputs):

net={}

#------------------------#

#輸入默認(rèn)為320,320,3

#------------------------#

net['input']=inputs

#------------------------------------------------#

#第一個(gè)卷積部分320,320,3-160,160,64

#------------------------------------------------#

net['conv1_1']=Conv2D(64,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv1_1')(net['input'])

net['conv1_2']=Conv2D(64,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv1_2')(net['conv1_1'])

net['pool1']=MaxPooling2D((2,2),strides=(2,2),padding='same',

name='pool1')(net['conv1_2'])

#------------------------------------------------#

#第二個(gè)卷積部分160,160,64-80,80,128

#------------------------------------------------#

net['conv2_1']=Conv2D(128,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv2_1')(net['pool1'])

net['conv2_2']=Conv2D(128,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv2_2')(net['conv2_1'])

net['pool2']=MaxPooling2D((2,2),strides=(2,2),padding='same',

name='pool2')(net['conv2_2'])

y0=net['pool2']

#------------------------------------------------#

#第三個(gè)卷積部分80,80,128-40,40,256

#------------------------------------------------#

net['conv3_1']=Conv2D(256,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv3_1')(net['pool2'])

net['conv3_2']=Conv2D(256,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv3_2')(net['conv3_1'])

net['conv3_3']=Conv2D(256,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv3_3')(net['conv3_2'])

net['pool3']=MaxPooling2D((2,2),strides=(2,2),padding='same',

name='pool3')(net['conv3_3'])

y1=net['pool3']

#------------------------------------------------#

#第四個(gè)卷積部分40,40,256-40,40,512

#------------------------------------------------#

net['conv4_1']=Conv2D(512,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv4_1')(net['pool3'])

net['conv4_2']=Conv2D(512,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv4_2')(net['conv4_1'])

net['conv4_3']=Conv2D(512,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv4_3')(net['conv4_2'])

#net['pool4']=MaxPooling2D((2,2),strides=(2,2),padding='same',

#name='block4_pool')(net['conv4_3'])

y2=net['conv4_3']

#------------------------------------------------#

#第五個(gè)卷積部分40,40,512-20,20,1024

#------------------------------------------------#

net['conv5_1']=Conv2D(1024,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv5_1')(net['conv4_3'])

net['conv5_2']=Conv2D(1024,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv5_2')(net['conv5_1'])

net['conv5_3']=Conv2D(1024,kernel_size=(3,3),

activation='relu',

padding='same',

name='conv5_3')(net['conv5_2'])

net['pool5']=MaxPooling2D((3,3),strides=(2,2),padding='same',

name='pool5')(net['conv5_3'])

y3=net['pool5']

model=Model(inputs,[y0,y1,y2,y3],name='vgg16')

returnmodel

2、FFM1特征初步融合

FFM1具體的結(jié)構(gòu)如下:

FFM1會(huì)對(duì)VGG提取到的特征進(jìn)行初步融合。

在利用VGG進(jìn)行特征提取的時(shí)候,我們會(huì)取出shape為(40,40,512)、(20,20,1024)的特征層進(jìn)行下一步的操作。

在FFM1中,其會(huì)對(duì)(20,20,1024)的特征層進(jìn)行進(jìn)行一個(gè)通道數(shù)為512、卷積核大小為3x3、步長(zhǎng)為1x1的卷積,然后再進(jìn)行上采樣,使其Shape變?yōu)?40,40,512);

同時(shí)會(huì)對(duì)(40,40,512)的特征層進(jìn)行進(jìn)行一個(gè)通道數(shù)為256、卷積核大小為1x1,步長(zhǎng)為1x1的卷積,使其Shape變?yōu)?40,40,256);

然后將兩個(gè)卷積后的結(jié)果進(jìn)行堆疊,變成一個(gè)(40,40,768)的初步融合特征層

實(shí)現(xiàn)代碼為:

defFFMv1(C4,C5,feature_size_1=256,feature_size_2=512,name='FFMv1'):

#------------------------------------------------#

#C4特征層40,40,512

#C5特征層20,20,1024

#------------------------------------------------#

#40,40,512-40,40,256

F4=conv2d(C4,filters=feature_size_1,kernel_size=(3,3),strides=(1,1),padding='same',name='F4')

#20,20,1024-20,20,512

F5=conv2d(C5,filters=feature_size_2,kernel_size=(1,1),strides=(1,1),padding='same',name='F5')

#20,20,512-40,40,512

F5=keras.layers.UpSampling2D(size=(2,2),name='F5_Up')(F5)

#40,40,256+40,40,512-40,40,768

outputs=keras.layers.Concatenate(name=name)([F4,F5])

returnoutputs

3、細(xì)化U型模塊TUM

Tum的結(jié)構(gòu)具體如下:

當(dāng)我們給Tum輸入一個(gè)(40,40,256)的有效特征層之后,Tum會(huì)對(duì)輸入進(jìn)來的特征層進(jìn)行U型的特征提取,這里的結(jié)構(gòu)比較類似特征金字塔的結(jié)構(gòu),先對(duì)特征層進(jìn)行不斷的特征壓縮,然后再不斷的上采樣進(jìn)行特征融合,利用Tum我們可以獲得6個(gè)有效特征層,大小分別是(40,40,128)、(20,20,128)、(10,10,128)、(5,5,128)、(3,3,128)、(1,1,128)。

defTUM(stage,inputs,feature_size=256,name="TUM"):#---------------------------------##進(jìn)行下采樣的部分#---------------------------------##40,40,256f1=inputs#40,40,256-20,20,256f2=conv2d(f1,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f2')#20,20,256-10,10,256f3=conv2d(f2,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f3')#10,10,256-5,5,256f4=conv2d(f3,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f4')#5,5,256-3,3,256f5=conv2d(f4,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f5')#3,3,256-1,1,256f6=conv2d(f5,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='valid',name=name+"_"+str(stage)+'_f6')size_buffer=[]#40,40size_buffer.append([int(f1.shape[1]),int(f1.shape[2])])#20,20size_buffer.append([int(f2.shape[1]),int(f2.shape[2])])#10,10size_buffer.append([int(f3.shape[1]),int(f3.shape[2])])#5,5size_buffer.append([int(f4.shape[1]),int(f4.shape[2])])#3,3size_buffer.append([int(f5.shape[1]),int(f5.shape[2])])#---------------------------------##進(jìn)行上采樣與特征融合的部分#---------------------------------#c6=f6#1,1,256-1,1,256c5=conv2d(c6,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c5')#1,1,256-3,3,256c5=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[4]),name=name+"_"+str(stage)+'_upsample_add5')(c5)c5=keras.layers.Add()([c5,f5])#3,3,256-3,3,256c4=conv2d(c5,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c4')#3,3,256-5,5,256c4=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[3]),name=name+"_"+str(stage)+'_upsample_add4')(c4)c4=keras.layers.Add()([c4,f4])#5,5,256-5,5,256c3=conv2d(c4,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c3')#5,5,256-10,10,256c3=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[2]),name=name+"_"+str(stage)+'_upsample_add3')(c3)c3=keras.layers.Add()([c3,f3])#10,10,256-10,10,256c2=conv2d(c3,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c2')#10,10,256-20,20,256c2=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[1]),name=name+"_"+str(stage)+'_upsample_add2')(c2)c2=keras.layers.Add()([c2,f2])#20,20,256-20,20,256c1=conv2d(c2,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c1')#20,20,256-40,40,256c1=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[0]),name=name+"_"+str(stage)+'_upsample_add1')(c1)c1=keras.layers.Add()([c1,f1])#---------------------------------##利用1x1卷積調(diào)整通道數(shù)后輸出#---------------------------------#output_features=feature_size//2#40,40,256-40,40,128o1=conv2d(c1,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o1')#20,20,256-20,20,128o2=conv2d(c2,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o2')#10,10,256-10,10,128o3=conv2d(c3,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o3')#5,5,256-5,5,128o4=conv2d(c4,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o4')#3,3,256-3,3,128o5=conv2d(c5,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o5')#1,1,256-1,1,128o6=conv2d(c6,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o6')outputs=[o1,o2,o3,o4,o5,o6]returnoutputs

defTUM(stage,inputs,feature_size=256,name="TUM"):

#---------------------------------#

#進(jìn)行下采樣的部分

#---------------------------------#

#40,40,256

f1=inputs

#40,40,256-20,20,256

f2=conv2d(f1,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f2')

#20,20,256-10,10,256

f3=conv2d(f2,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f3')

#10,10,256-5,5,256

f4=conv2d(f3,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f4')

#5,5,256-3,3,256

f5=conv2d(f4,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='same',name=name+"_"+str(stage)+'_f5')

#3,3,256-1,1,256

f6=conv2d(f5,filters=feature_size,kernel_size=(3,3),strides=(2,2),padding='valid',name=name+"_"+str(stage)+'_f6')

size_buffer=[]

#40,40

size_buffer.append([int(f1.shape[1]),int(f1.shape[2])])

#20,20

size_buffer.append([int(f2.shape[1]),int(f2.shape[2])])

#10,10

size_buffer.append([int(f3.shape[1]),int(f3.shape[2])])

#5,5

size_buffer.append([int(f4.shape[1]),int(f4.shape[2])])

#3,3

size_buffer.append([int(f5.shape[1]),int(f5.shape[2])])

#---------------------------------#

#進(jìn)行上采樣與特征融合的部分

#---------------------------------#

c6=f6

#1,1,256-1,1,256

c5=conv2d(c6,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c5')

#1,1,256-3,3,256

c5=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[4]),name=name+"_"+str(stage)+'_upsample_add5')(c5)

c5=keras.layers.Add()([c5,f5])

#3,3,256-3,3,256

c4=conv2d(c5,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c4')

#3,3,256-5,5,256

c4=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[3]),name=name+"_"+str(stage)+'_upsample_add4')(c4)

c4=keras.layers.Add()([c4,f4])

#5,5,256-5,5,256

c3=conv2d(c4,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c3')

#5,5,256-10,10,256

c3=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[2]),name=name+"_"+str(stage)+'_upsample_add3')(c3)

c3=keras.layers.Add()([c3,f3])

#10,10,256-10,10,256

c2=conv2d(c3,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c2')

#10,10,256-20,20,256

c2=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[1]),name=name+"_"+str(stage)+'_upsample_add2')(c2)

c2=keras.layers.Add()([c2,f2])

#20,20,256-20,20,256

c1=conv2d(c2,filters=feature_size,kernel_size=(3,3),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_c1')

#20,20,256-40,40,256

c1=keras.layers.Lambda(lambdax:tf.image.resize_bilinear(x,size=size_buffer[0]),name=name+"_"+str(stage)+'_upsample_add1')(c1)

c1=keras.layers.Add()([c1,f1])

#---------------------------------#

#利用1x1卷積調(diào)整通道數(shù)后輸出

#---------------------------------#

output_features=feature_size//2

#40,40,256-40,40,128

o1=conv2d(c1,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o1')

#20,20,256-20,20,128

o2=conv2d(c2,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o2')

#10,10,256-10,10,128

o3=conv2d(c3,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o3')

#5,5,256-5,5,128

o4=conv2d(c4,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o4')

#3,3,256-3,3,128

o5=conv2d(c5,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o5')

#1,1,256-1,1,128

o6=conv2d(c6,filters=output_features,kernel_size=(1,1),strides=(1,1),padding='valid',name=name+"_"+str(stage)+'_o6')

outputs=[o1,o2,o3,o4,o5,o6]

returnoutputs

4、FFM2特征加強(qiáng)融合

通過TUM,我們可以獲得六個(gè)有效特征層,為了進(jìn)一步加強(qiáng)網(wǎng)絡(luò)的特征提取能力,M2det將6個(gè)有效特征層中的(40,40,128)特征層取出,和FFM1提取出來的初步融合特征層進(jìn)行加強(qiáng)融合,再次輸出一個(gè)(40,40,256)的加強(qiáng)融合的特征層。

此時(shí)FFM2輸出的加強(qiáng)融合特征層可以再一次傳入到TUM中進(jìn)行U形特征提取。

如上圖所示,我們可以進(jìn)一步利用多個(gè)TUM模塊進(jìn)行特征提取,利用多個(gè)TUM模塊我們可以獲得多次有效特征層。

TUM模塊的數(shù)量我們可以根據(jù)自身需要進(jìn)行修改,本文使用4次TUM模塊,可以分別獲得四次(40,40,128)、(20,20,128)、(10,10,128)、(5,5,128)、(3,3,128)、(1,1,128)的有效特征層。(論文中做了實(shí)驗(yàn),用8次TUM模塊會(huì)有比較好的效果)。

我們可以將獲得的有效特征層,按照shape進(jìn)行堆疊,最終獲得(40,40,512)、(20,20,512)、(10,10,512)、(5,5,512)、(3,3,512)、(1,1,512)六個(gè)有效特征層。

defFFMv2(stage,base,tum,base_size=(40,40,768),tum_size=(40,40,128),feature_size=128,name='FFMv2'):

#40,40,128

outputs=conv2d(base,filters=feature_size,kernel_size=(1,1),strides=(1,1),padding='same',name=name+"_"+str(stage)+'_base_feature')

outputs=keras.layers.Concatenate(name=name+"_"+str(stage))([outputs,tum])

#40,40,256

returnoutputs

def_create_feature_pyramid(base_feature,stage=8):

features=[[],[],[],[],[],[]]

#將輸入進(jìn)來的

inputs=keras.layers.Conv2D(filters=256,kernel_size=1,strides=1,padding='same')(base_feature)

#第一個(gè)TUM模塊

outputs=TUM(1,inputs)

max_output=outputs[0]

forjinrange(len(features)):

features[j].append(outputs[j])

#第2,3,4個(gè)TUM模塊,需要將上一個(gè)Tum模塊輸出的40x40x128的內(nèi)容,傳入到下一個(gè)Tum模塊中

foriinrange(2,stage+1):

#將Tum模塊的輸出和基礎(chǔ)特征層傳入到FFmv2層當(dāng)中

#輸入為base_feature40x40x768,max_output40x40x128

#輸出為40x40x256

inputs=FFMv2(i-1,base_feature,max_output)

#輸出為40x40x128、20x20x128、10x10x128、5x5x128、3x3x128、1x1x128

outputs=TUM(i,inputs)

max_output=outputs[0]

forjinrange(len(features)):

features[j].append(outputs[j])

#進(jìn)行了4次TUM

#將獲得的同樣大小的特征層堆疊到一起

concatenate_features=[]

forfeatureinfeatures:

concat=keras.layers.Concatenate()([fforfinfeature])

concatenate_features.append(concat)

returnconcatenate_features

5、注意力機(jī)制模塊SFAM

注意力機(jī)制模塊如下:

其會(huì)對(duì)上一步獲得的(40,40,512)、(20,20,512)、(10,10,512)、(5,5,512)、(3,3,512)、(1,1,512)六個(gè)有效特征層。進(jìn)行各個(gè)通道的注意力機(jī)制調(diào)整,判斷每一個(gè)通道數(shù)應(yīng)該有的權(quán)重。

#注意力機(jī)制

defSE_block(inputs,input_size,compress_ratio=16,name='SE_block'):

pool=keras.layers.GlobalAveragePooling2D()(inputs)

reshape=keras.layers.Reshape((1,1,input_size[2]))(pool)

fc1=keras.layers.Conv2D(filters=input_size[2]//compress_ratio,kernel_size=1,strides=1,padding='valid',

activation='relu',name=name+'_fc1')(reshape)

fc2=keras.layers.Conv2D(filters=input_size[2],kernel_size=1,strides=1,padding='valid',activation='sigmoid',

name=name+'_fc2')(fc1)

reweight=keras.layers.Multiply(name=name+'_reweight')([inputs,fc2])

returnreweight

defSFAM(feature_pyramid,input_sizes,compress_ratio=16,name='SFAM'):

outputs=[]

foriinrange(len(input_sizes)):

input_size=input_sizes[i]

_input=feature_pyramid[i]

_output=SE_block(_input,input_size,compress_ratio=compress_ratio,name='SE_block_'+str(i))

outputs.append(_output)

returnoutputs

6、從特征獲取預(yù)測(cè)結(jié)果

通過第五步,我們獲取了6個(gè)融合了注意力機(jī)制的有效特征層。

對(duì)獲取到的每一個(gè)有效特征層,我們分別對(duì)其進(jìn)行一次num_anchorsx4的卷積、一次num_anchorsxnum_classes的卷積、并需要計(jì)算每一個(gè)有效特征層對(duì)應(yīng)的先驗(yàn)框。而num_anchors指的是該特征層所擁有的先驗(yàn)框數(shù)量。

其中:

num_anchorsx4的卷積用于預(yù)測(cè)該特征層上每一個(gè)網(wǎng)格點(diǎn)上每一個(gè)先驗(yàn)框的變化情況。(為什么說是變化情況呢,這是因?yàn)镸2DET的預(yù)測(cè)結(jié)果需要結(jié)合先驗(yàn)框獲得預(yù)測(cè)框,預(yù)測(cè)結(jié)果就是先驗(yàn)框的變化情況。)

num_anchorsxnum_classes的卷積用于預(yù)測(cè)該特征層上每一個(gè)網(wǎng)格點(diǎn)上每一個(gè)預(yù)測(cè)框?qū)?yīng)的種類。

每一個(gè)有效特征層對(duì)應(yīng)的先驗(yàn)框?qū)?yīng)著該特征層上每一個(gè)網(wǎng)格點(diǎn)上預(yù)先設(shè)定好的六個(gè)框。

所有的特征層對(duì)應(yīng)的預(yù)測(cè)結(jié)果的shape如下:

實(shí)現(xiàn)代碼為:

defm2det(input_shape,num_classes=21,num_anchors=6):

inputs=keras.layers.Input(shape=input_shape)

#------------------------------------------------#

#利用主干特征提取網(wǎng)絡(luò)獲得兩個(gè)有效特征層

#分別是C440,40,512

#分別是C520,20,1024

#------------------------------------------------#

C4,C5=VGG16(inputs).outputs[2:]

#base_feature的shape為40,40,768

base_feature=FFMv1(C4,C5,feature_size_1=256,feature_size_2=512)

#---------------------------------------------------------------------------------------------------#

#在_create_feature_pyramid函數(shù)里,我們會(huì)使用TUM模塊對(duì)輸入進(jìn)來的特征層進(jìn)行特征提取

#最終輸出的特征層有六個(gè),由于進(jìn)行了四次的TUM模塊,所以六個(gè)有效特征層由4次TUM模塊的輸出堆疊而成

#o140,40,128*440,40,512

#o220,20,128*420,20,512

#o310,10,128*410,10,512

#o45,5,128*45,5,512

#o53,3,128*43,3,512

#o61,1,128*41,1,512

#---------------------------------------------------------------------------------------------------#

feature_pyramid=_create_feature_pyramid(base_feature,stage=4)

#-------------------------------------------------#

#給合并后的特征層添加上注意力機(jī)制

#-------------------------------------------------#

outputs=SFAM(feature_pyramid)

#-------------------------------------------------#

#將有效特征層轉(zhuǎn)換成輸出結(jié)果

#-------------------------------------------------#

classifications=[]

regressions=[]

forfeatureinoutputs:

classification=keras.layers.Conv2D(filters=num_anchors*num_classes,kernel_size=3,strides=1,padding='same')(feature)

classification=keras.layers.Reshape((-1,num_classes))(classification)

classification=keras.layers.Activation('softmax')(classification)

regression=keras.layers.Conv2D(filters=num_anchors*4,kernel_size=3,strides=1,padding='same')(feature)

regression=keras.layers.Reshape((-1,4))(regression)

classifications.append(classification)

regressions.append(regression)

classifications=keras.layers.Concatenate(axis=1,name="classification")(classifications)

regressions=keras.layers.Concatenate(axis=1,name="regression")(regressions)

pyramids=keras.layers.Concatenate(axis=-1,name="out")([regressions,classifications])

returnkeras.models.Model(inputs=inputs,outputs=pyramids)

7、預(yù)測(cè)結(jié)果的解碼

我們通過對(duì)每一個(gè)特征層的處理,可以獲得兩個(gè)內(nèi)容,分別是:

num_anchorsx4的卷積用于預(yù)測(cè)該特征層上每一個(gè)網(wǎng)格點(diǎn)上每一個(gè)先驗(yàn)框的變化情況。

num_anchorsxnum_classes的卷積用于預(yù)測(cè)該特征層上每一個(gè)網(wǎng)格點(diǎn)上每一個(gè)預(yù)測(cè)框?qū)?yīng)的種類。

每一個(gè)有效特征層對(duì)應(yīng)的先驗(yàn)框?qū)?yīng)著該特征層上每一個(gè)網(wǎng)格點(diǎn)上預(yù)先設(shè)定好的六個(gè)框。

我們利用num_anchorsx4的卷積與每一個(gè)有效特征層對(duì)應(yīng)的先驗(yàn)框獲得框的真實(shí)位置。

每一個(gè)有效特征層對(duì)應(yīng)的先驗(yàn)框就是,如圖所示的作用:

每一個(gè)有效特征層將整個(gè)圖片分成與其長(zhǎng)寬對(duì)應(yīng)的網(wǎng)格,如conv4-3和fl7組合成的特征層就是將整個(gè)圖像分成38x38個(gè)網(wǎng)格;然后從每個(gè)網(wǎng)格中心建立多個(gè)先驗(yàn)框,如conv4-3和fl7組合成的有效特征層就是建立了6個(gè)先驗(yàn)框;對(duì)于conv4-3和fl7組合成的特征層來講,整個(gè)圖片被分成38x38個(gè)網(wǎng)格,每個(gè)網(wǎng)格中心對(duì)應(yīng)6個(gè)先驗(yàn)框,一共包含了,38x38x6個(gè),8664個(gè)先驗(yàn)框。

先驗(yàn)框雖然可以代表一定的框的位置信息與框的大小信息,但是其是有限的,無法表示任意情況,因此還需要調(diào)整,RFBnet利用num_anchorsx4的卷積的結(jié)果對(duì)先驗(yàn)框進(jìn)行調(diào)整。

num_anchorsx4中的num_anchors表示了這個(gè)網(wǎng)格點(diǎn)所包含的先驗(yàn)框數(shù)量,其中的4表示了x_offset、y_offset、h和w的調(diào)整情況。

x_offset與y_offset代表了真實(shí)框距離先驗(yàn)框中心的xy軸偏移情況。h和w代表了真實(shí)框的寬與高相對(duì)于先驗(yàn)框的變化情況。

RFBnet解碼過程就是將每個(gè)網(wǎng)格的中心點(diǎn)加上它對(duì)應(yīng)的x_offset和y_offset,加完后的結(jié)果就是預(yù)測(cè)框的中心,然后再利用先驗(yàn)框和h、w結(jié)合計(jì)算出預(yù)測(cè)框的長(zhǎng)和寬。這樣就能得到整個(gè)預(yù)測(cè)框的位置了。

當(dāng)然得到最終的預(yù)測(cè)結(jié)構(gòu)后還要進(jìn)行得分排序與非極大抑制篩選這一部分基本上是所有目標(biāo)檢測(cè)通用的部分。

1、取出每一類得分大于self.obj_threshold的框和得分。

2、利用框的位置和得分進(jìn)行非極大抑制。

實(shí)現(xiàn)代碼如下:

importnumpyasnp

importtensorflowastf

importkeras.backendasK

classBBoxUtility(object):

def__init__(self,num_classes,nms_thresh=0.45,top_k=300):

self.num_classes=num_classes

self._nms_thresh=nms_thresh

self._top_k=top_k

self.boxes=K.placeholder(dtype='float32',shape=(None,4))

self.scores=K.placeholder(dtype='float32',shape=(None,))

self.nms=tf.image.non_max_suppression(self.boxes,self.scores,self._top_k,iou_threshold=self._nms_thresh)

self.sess=K.get_session()

defssd_correct_boxes(self,box_xy,box_wh,input_shape,image_shape,letterbox_image):

#-----------------------------------------------------------------#

#把y軸放前面是因?yàn)榉奖泐A(yù)測(cè)框和圖像的寬高進(jìn)行相乘

#-----------------------------------------------------------------#

box_yx=box_xy[...,::-1]

box_hw=box_wh[...,::-1]

input_shape=np.array(input_shape)

image_shape=np.array(image_shape)

ifletterbox_image:

#-----------------------------------------------------------------#

#這里求出來的offset是圖像有效區(qū)域相對(duì)于圖像左上角的偏移情況

#new_shape指的是寬高縮放情況

#-----------------------------------------------------------------#

new_shape=np.round(image_shape*np.min(input_shape/image_shape))

offset=(input_shape-new_shape)/2./input_shape

scale=input_shape/new_shape

box_yx=(box_yx-offset)*scale

box_hw*=scale

box_mins=box_yx-(box_hw/2.)

box_maxes=box_yx+(box_hw/2.)

boxes=np.concatenate([box_mins[...,0:1],box_mins[...,1:2],box_maxes[...,0:1],box_maxes[...,1:2]],axis=-1)

boxes*=np.concatenate([image_shape,image_shape],axis=-1)

returnboxes

defdecode_boxes(self,mbox_loc,anchors,variances):

#獲得先驗(yàn)框的寬與高

anchor_width=anchors[:,2]-anchors[:,0]

anchor_height=anchors[:,3]-anchors[:,1]

#獲得先驗(yàn)框的中心點(diǎn)

anchor_center_x=0.5*(anchors[:,2]+anchors[:,0])

anchor_center_y=0.5*(anchors[:,3]+anchors[:,1])

#真實(shí)框距離先驗(yàn)框中心的xy軸偏移情況

decode_bbox_center_x=mbox_loc[:,0]*anchor_width*variances[0]

decode_bbox_center_x+=anchor_center_x

decode_bbox_center_y=mbox_loc[:,1]*anchor_height*variances[1]

decode_bbox_center_y+=anchor_center_y

#真實(shí)框的寬與高的求取

decode_bbox_width=np.exp(mbox_loc[:,2]*variances[2])

decode_bbox_width*=anchor_width

decode_bbox_height=np.exp(mbox_loc[:,3]*variances[3])

decode_bbox_height*=anchor_height

#獲取真實(shí)框的左上角與右下角

decode_bbox_xmin=decode_bbox_center_x-0.5*decode_bbox_width

decode_bbox_ymin=decode_bbox_center_y-0.5*decode_bbox_height

decode_bbox_xmax=decode_bbox_center_x+0.5*decode_bbox_width

decode_bbox_ymax=decode_bbox_center_y+0.5*decode_bbox_height

#真實(shí)框的左上角與右下角進(jìn)行堆疊

decode_bbox=np.concatenate((decode_bbox_xmin[:,None],

decode_bbox_ymin[:,None],

decode_bbox_xmax[:,None],

decode_bbox_ymax[:,None]),axis=-1)

#防止超出0與1

decode_bbox=np.minimum(np.maximum(decode_bbox,0.0),1.0)

returndecode_bbox

defdecode_box(self,predictions,anchors,image_shape,input_shape,letterbox_image,variances=[0.1,0.1,0.2,0.2],confidence=0.5):

#---------------------------------------------------#

#:4是回歸預(yù)測(cè)結(jié)果

#---------------------------------------------------#

mbox_loc=predictions[:,:,:4]

#---------------------------------------------------#

#獲得種類的置信度

#---------------------------------------------------#

mbox_conf=predictions[:,:,4:]

results=[]

#----------------------------------------------------------------------------------------------------------------#

#對(duì)每一張圖片進(jìn)行處理,由于在predict.py的時(shí)候,我們只輸入一張圖片,所以foriinrange(len(mbox_loc))只進(jìn)行一次

#----------------------------------------------------------------------------------------------------------------#

foriinrange(len(mbox_loc)):

results.append([])

#--------------------------------#

#利用回歸結(jié)果對(duì)先驗(yàn)框進(jìn)行解碼

#--------------------------------#

decode_bbox=self.decode_boxes(mbox_loc[i],anchors,variances)

forcinrange(1,self.num_classes):

#--------------------------------#

#取出屬于該類的所有框的置信度

#判斷是否大于門限

#--------------------------------#

c_confs=mbox_conf[i,:,c]

c_confs_m=c_confsconfidence

iflen(c_confs[c_confs_m])0:

#-----------------------------------------#

#取出得分高于confidence的框

#-----------------------------------------#

boxes_to_process=decode_bbox[c_confs_m]

confs_to_process=c_confs[c_confs_m]

#-----------------------------------------#

#進(jìn)行iou的非極大抑制

#-----------------------------------------#

idx=self.sess.run(self.nms,feed_dict={self.boxes:boxes_to_process,self.scores:confs_to_process})

#-----------------------------------------#

#取出在非極大抑制中效果較好的內(nèi)容

#-----------------------------------------#

good_boxes=boxes_to_process[idx]

confs=confs_to_process[idx][:,None]

labels=(c-1)*np.ones((len(idx),1))

#-----------------------------------------#

#將label、置信度、框的位置進(jìn)行堆疊。

#-----------------------------------------#

c_pred=np.concatenate((good_boxes,labels,confs),axis=1)

#添加進(jìn)result里

results[-1].extend(c_pred)

iflen(results[-1])0:

results[-1]=np.array(results[-1])

box_xy,box_wh=(results[-1][:,0:2]+results[-1][:,2:4])/2,results[-1][:,2:4]-results[-1][:,0:2]

results[-1][:,:4]=self.ssd_correct_boxes(box_xy,box_wh,input_shape,image_shape,letterbox_image)

returnresults

8、在原圖上進(jìn)行繪制

通過第三步,我們可以獲得預(yù)測(cè)框在原圖上的位置,而且這些預(yù)測(cè)框都是經(jīng)過篩選的。這些篩選后的框可以直接繪制在圖片上,就可以獲得結(jié)果了。

二、訓(xùn)練部分

1、真實(shí)框的處理

從預(yù)測(cè)部分我們知道,每個(gè)特征層的預(yù)測(cè)結(jié)果,num_anchorsx4的卷積用于預(yù)測(cè)該特征層上每一個(gè)網(wǎng)格點(diǎn)上每一個(gè)先驗(yàn)框的變化情況。

也就是說,我們直接利用M2DET網(wǎng)絡(luò)預(yù)測(cè)到的結(jié)果,并不是預(yù)測(cè)框在圖片上的真實(shí)位置,需要解碼才能得到真實(shí)位置。

而在訓(xùn)練的時(shí)候,我們需要計(jì)算loss函數(shù),這個(gè)loss函數(shù)是相對(duì)于M2DET網(wǎng)絡(luò)的預(yù)測(cè)結(jié)果的。我們需要把圖片輸入到當(dāng)前的M2DET網(wǎng)絡(luò)中,得到預(yù)測(cè)結(jié)果;同時(shí)還需要把真實(shí)框的信息,進(jìn)行編碼,這個(gè)編碼是把真實(shí)框的位置信息格式轉(zhuǎn)化為M2DET預(yù)測(cè)結(jié)果的格式信息。

也就是,我們需要找到每一張用于訓(xùn)練的圖片的每一個(gè)真實(shí)框?qū)?yīng)的先驗(yàn)框,并求出如果想要得到這樣一個(gè)真實(shí)框,我們的預(yù)測(cè)結(jié)果應(yīng)該是怎么樣的。

從預(yù)測(cè)結(jié)果獲得真實(shí)框的過程被稱作解碼,而從

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論