python目標檢測yolo2詳解及預測代碼復現(xiàn)_第1頁
python目標檢測yolo2詳解及預測代碼復現(xiàn)_第2頁
python目標檢測yolo2詳解及預測代碼復現(xiàn)_第3頁
python目標檢測yolo2詳解及預測代碼復現(xiàn)_第4頁
python目標檢測yolo2詳解及預測代碼復現(xiàn)_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第python目標檢測yolo2詳解及預測代碼復現(xiàn)目錄前言實現(xiàn)思路1、yolo2的預測思路(網(wǎng)絡(luò)構(gòu)建思路)2、先驗框的生成3、利用先驗框?qū)W(wǎng)絡(luò)的輸出進行解碼4、進行得分排序與非極大抑制篩選實現(xiàn)結(jié)果

前言

最近在學習yolo1、yolo2和yolo3,寫這篇博客主要是為了讓自己對yolo2的結(jié)構(gòu)有更加深刻的理解,同時要理解清楚先驗框的含義。

盡量配合代碼觀看會更容易理解。

下載鏈接:/s/1NAqme8dD2Zoeo1Yd1xQVFw

提取碼:oq05

實現(xiàn)思路

1、yolo2的預測思路(網(wǎng)絡(luò)構(gòu)建思路)

YOLOv2使用了一個新的分類網(wǎng)絡(luò)DarkNet19作為特征提取部分,DarkNet19包含19個卷積層、5個最大值池化層。網(wǎng)絡(luò)使用了較多的3x3卷積核,在每一次池化操作后把通道數(shù)翻倍。借鑒了networkinnetwork的思想,把1x1的卷積核置于3x3的卷積核之間,用來壓縮特征。使用batchnormalization穩(wěn)定模型訓練,加速收斂,正則化模型。

與此同時,其保留了一個shortcut用于存儲之前的特征。

最后輸出的conv_dec的shape為(13,13,425),其中13x13是把整個圖分為13x13的網(wǎng)格用于預測,425可以分解為(85x5),在85中,其可以分為80和5兩部分,由于yolo2常用的是coco數(shù)據(jù)集,其中具有80個類,剩余的5指的是x、y、w、h和其置信度。x5的5中,意味著預測結(jié)果包含5個框,分別對應5個先驗框。

其實際情況就是,輸入N張416x416的圖片,在經(jīng)過多層的運算后,會輸出一個shape為(N,13,13,425)的數(shù)據(jù),對應每個圖分為13x13的網(wǎng)格后5個先驗框的位置。

defconv2d(self,x,filters_num,filters_size,pad_size=0,stride=1,batch_normalize=True,activation=leaky_relu,use_bias=False,name='conv2d'):

#是否進行pad

ifpad_size0:

x=tf.pad(x,[[0,0],[pad_size,pad_size],[pad_size,pad_size],[0,0]])

#pad后進行卷積

out=tf.layers.conv2d(x,filters=filters_num,kernel_size=filters_size,strides=stride,padding='VALID',activation=None,use_bias=use_bias,name=name)

#BN應該在卷積層conv和激活函數(shù)activation之間,

#后面有BN層的conv就不用偏置bias,并激活函數(shù)activation在后

#如果需要標準化則進行標準化

ifbatch_normalize:

out=tf.layers.batch_normalization(out,axis=-1,momentum=0.9,training=False,name=name+'_bn')

ifactivation:

out=activation(out)

returnout

defmaxpool(self,x,size=2,stride=2,name='maxpool'):

returntf.layers.max_pooling2d(x,pool_size=size,strides=stride,name=name)

defpassthrough(self,x,stride):

#變小變長

returntf.space_to_depth(x,block_size=stride)

defdarknet(self):

x=tf.placeholder(dtype=tf.float32,shape=[None,416,416,3])

#416,416,3-416,416,32

net=self.conv2d(x,filters_num=32,filters_size=3,pad_size=1,

name='conv1')

#416,416,32-208,208,32

net=self.maxpool(net,size=2,stride=2,name='pool1')

#208,208,32-208,208,64

net=self.conv2d(net,64,3,1,name='conv2')

#208,208,64-104,104,64

net=self.maxpool(net,2,2,name='pool2')

#104,104,64-104,104,128

net=self.conv2d(net,128,3,1,name='conv3_1')

net=self.conv2d(net,64,1,0,name='conv3_2')

net=self.conv2d(net,128,3,1,name='conv3_3')

#104,104,128-52,52,128

net=self.maxpool(net,2,2,name='pool3')

net=self.conv2d(net,256,3,1,name='conv4_1')

net=self.conv2d(net,128,1,0,name='conv4_2')

net=self.conv2d(net,256,3,1,name='conv4_3')

#52,52,128-26,26,256

net=self.maxpool(net,2,2,name='pool4')

#26,26,256-26,26,512

net=self.conv2d(net,512,3,1,name='conv5_1')

net=self.conv2d(net,256,1,0,name='conv5_2')

net=self.conv2d(net,512,3,1,name='conv5_3')

net=self.conv2d(net,256,1,0,name='conv5_4')

net=self.conv2d(net,512,3,1,name='conv5_5')

#這一層特征圖,要進行后面passthrough,保留一層特征層

shortcut=net

#26,26,512-13,13,512

net=self.maxpool(net,2,2,name='pool5')#

#13,13,512-13,13,1024

net=self.conv2d(net,1024,3,1,name='conv6_1')

net=self.conv2d(net,512,1,0,name='conv6_2')

net=self.conv2d(net,1024,3,1,name='conv6_3')

net=self.conv2d(net,512,1,0,name='conv6_4')

net=self.conv2d(net,1024,3,1,name='conv6_5')

#下面這部分主要是trainingfordetection

net=self.conv2d(net,1024,3,1,name='conv7_1')

#13,13,1024-13,13,1024

net=self.conv2d(net,1024,3,1,name='conv7_2')

#shortcut增加了一個中間卷積層,先采用64個1*1卷積核進行卷積,然后再進行passthrough處理

#得到了26*26*512-26*26*64-13*13*256的特征圖

shortcut=self.conv2d(shortcut,64,1,0,name='conv_shortcut')

shortcut=self.passthrough(shortcut,2)

#連接之后,變成13*13*(1024+256)

net=tf.concat([shortcut,net],axis=-1)

#channel整合到一起,concatenatedwiththeoriginalfeatures,passthrough層與ResNet網(wǎng)絡(luò)的shortcut類似,以前面更高分辨率的特征圖為輸入,然后將其連接到后面的低分辨率特征圖上,

net=self.conv2d(net,1024,3,1,name='conv8')

#detectionlayer:最后用一個1*1卷積去調(diào)整channel,該層沒有BN層和激活函數(shù),變成:S*S*(B*(5+C)),在這里為:13*13*425

output=self.conv2d(net,filters_num=self.f_num,filters_size=1,batch_normalize=False,activation=None,

use_bias=True,name='conv_dec')

returnoutput,x

2、先驗框的生成

對于yolo1來講,其最后輸出的結(jié)果的shape為(7,7,30),對應著兩個框及其種類,盡管網(wǎng)絡(luò)可以不斷的訓練最后實現(xiàn)框的位置的調(diào)整,但是如果我們能夠給出一些框的尺寸備用,效果理論上會更好(實際上也是),這就是先驗框的來歷。

但是yolo2的框并不是隨便就得到的,它是通過計算得到的。

在尋常的kmean算法中,使用的是歐氏距離來完成聚類,但是先驗框顯然不可以這樣,因為大框的歐氏距離更大,yolo2使用的是處理后的IOU作為歐氏距離。

最后得到五個聚類中心便是先驗框的寬高。

importnumpyasnp

importxml.etree.ElementTreeasET

importglob

importrandom

defcas_iou(box,cluster):

x=np.minimum(cluster[:,0],box[0])

y=np.minimum(cluster[:,1],box[1])

intersection=x*y

area1=box[0]*box[1]

area2=cluster[:,0]*cluster[:,1]

iou=intersection/(area1+area2-intersection)

returniou

defavg_iou(box,cluster):

returnnp.mean([np.max(cas_iou(box[i],cluster))foriinrange(box.shape[0])])

defkmeans(box,k):

#取出一共有多少框

row=box.shape[0]

#每個框各個點的位置

distance=np.empty((row,k))

#最后的聚類位置

last_clu=np.zeros((row,))

np.random.seed()

#隨機選5個當聚類中心

cluster=box[np.random.choice(row,k,replace=False)]

#cluster=random.sample(row,k)

whileTrue:

#計算每一行距離五個點的iou情況。

foriinrange(row):

distance[i]=1-cas_iou(box[i],cluster)

#取出最小點

near=np.argmin(distance,axis=1)

if(last_clu==near).all():

break

#求每一個類的中位點

forjinrange(k):

cluster[j]=np.median(

box[near==j],axis=0)

last_clu=near

returncluster

defload_data(path):

data=[]

#對于每一個xml都尋找box

forxml_fileinglob.glob('{}/*xml'.format(path)):

tree=ET.parse(xml_file)

height=int(tree.findtext('./size/height'))

width=int(tree.findtext('./size/width'))

#對于每一個目標都獲得它的寬高

forobjintree.iter('object'):

xmin=int(float(obj.findtext('bndbox/xmin')))/width

ymin=int(float(obj.findtext('bndbox/ymin')))/height

xmax=int(float(obj.findtext('bndbox/xmax')))/width

ymax=int(float(obj.findtext('bndbox/ymax')))/height

xmin=np.float64(xmin)

ymin=np.float64(ymin)

xmax=np.float64(xmax)

ymax=np.float64(ymax)

#得到寬高

data.append([xmax-xmin,ymax-ymin])

returnnp.array(data)

if__name__=='__main__':

anchors_num=5

#載入數(shù)據(jù)集,可以使用VOC的xml

path='../SSD-Tensorflow-master/VOC2012/Annotations'

#載入所有的xml

#存儲格式為轉(zhuǎn)化為比例后的width,height

data=load_data(path)

#使用k聚類算法

out=kmeans(data,anchors_num)

print('acc:{:.2f}%'.format(avg_iou(data,out)*100))

print(out)

print('box',out[:,0]*13,out[:,1]*13)

ratios=np.around(out[:,0]/out[:,1],decimals=2).tolist()

print('ratios:',sorted(ratios))

得到結(jié)果為:

acc:61.32%

[[0.0440.07733333]

[0.1060.17866667]

[0.4080.616]

[0.8160.83]

[0.20.38933333]]

box[0.5721.3785.30410.6082.6][1.005333332.322666678.00810.795.06133333]

ratios:[0.51,0.57,0.59,0.66,0.98]

3、利用先驗框?qū)W(wǎng)絡(luò)的輸出進行解碼

yolo2的解碼過程與SSD類似,但是并不太一樣,相比之下yolo2的解碼過程更容易理解,因為其僅有單層的特征層。

1、將網(wǎng)絡(luò)的輸出reshape成[-1,13*13,5,80+5],代表169個中心點每個中心點的5個先驗框的情況。

2、將80+5的5中的xywh分離出來,0、1是xy相對中心點的偏移量;2、3是寬和高的情況;4是置信度。

3、建立13x13的網(wǎng)格,代表圖片進行13x13處理后網(wǎng)格的中心點。

4、利用計算公式計算實際的bbox的位置。

解碼部分代碼如下:

defdecode(self,net):

self.anchor_size=tf.constant(self.anchor_size,tf.float32)

#net的shape為[batch,169,5,85]

net=tf.reshape(net,[-1,13*13,self.num_anchors,self.num_class+5])

#85里面0、1為xy的偏移量,2、3是wh的偏移量,4是置信度,5-84是每個種類的概率

#偏移量、置信度、類別

#中心坐標相對于該cell坐上角的偏移量,sigmoid函數(shù)歸一化到(0,1)

#[batch,169,5,2]

xy_offset=tf.nn.sigmoid(net[:,:,:,0:2])

wh_offset=tf.exp(net[:,:,:,2:4])

obj_probs=tf.nn.sigmoid(net[:,:,:,4])

class_probs=tf.nn.softmax(net[:,:,:,5:])

#在featuremap對應坐標生成anchors,13,13

height_index=tf.range(self.feature_map_size[0],dtype=tf.float32)

width_index=tf.range(self.feature_map_size[1],dtype=tf.float32)

x_cell,y_cell=tf.meshgrid(height_index,width_index)

x_cell=tf.reshape(x_cell,[1,-1,1])#和上面[H*W,num_anchors,num_class+5]對應

y_cell=tf.reshape(y_cell,[1,-1,1])

#x_cell和y_cell是網(wǎng)格分割中心

#xy_offset是相對中心的偏移情況

bbox_x=(x_cell+xy_offset[:,:,:,0])/13

bbox_y=(y_cell+xy_offset[:,:,:,1])/13

bbox_w=(self.anchor_size[:,0]*wh_offset[:,:,:,0])/13

bbox_h=(self.anchor_size[:,1]*wh_offset[:,:,:,1])/13

bboxes=tf.stack([bbox_x-bbox_w/2,bbox_y-bbox_h/2,bbox_x+bbox_w/2,bbox_y+bbox_h/2],

axis=3)

returnbboxes,obj_probs,class_probs

4、進行得分排序與非極大抑制篩選

這一部分基本上是所有目標檢測通用的部分。

1、將所有box還原成圖片中真實的位置。

2、得到每個box最大的預測概率對應的種類。

3、將每個box最大的預測概率乘上置信度得到每個box的分數(shù)。

4、對分數(shù)進行篩選與排序。

5、非極大抑制,去除重復率過大的框。

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

defbboxes_cut(self,bbox_min_max,bboxes):

bboxes=np.copy(bboxes)

bboxes=np.transpose(bboxes)

bbox_min_max=np.transpose(bbox_min_max)

#cutthebox

bboxes[0]=np.maximum(bboxes[0],bbox_min_max[0])#xmin

bboxes[1]=np.maximum(bboxes[1],bbox_min_max[1])#ymin

bboxes[2]=np.minimum(bboxes[2],bbox_min_max[2])#xmax

bboxes[3]=np.minimum(bboxes[3],bbox_min_max[3])#ymax

bboxes=np.transpose(bboxes)

returnbboxes

defbboxes_sort(self,classes,scores,bboxes,top_k=400):

index=np.argsort(-scores)

classes=classes[index][:top_k]

scores=scores[index][:top_k]

bboxes=bboxes[index][:top_k]

returnclasses,scores,bboxes

defbboxes_iou(self,bboxes1,bboxes2):

bboxes1=np.transpose(bboxes1)

bboxes2=np.transpose(bboxes2)

int_ymin=np.maximum(bboxes1[0],bboxes2[0])

int_xmin=np.maximum(bboxes1[1],bboxes2[1])

int_ymax=np.minimum(bboxes1[2],bboxes2[2])

int_xmax=np.minimum(bboxes1[3],bboxes2[3])

int_h=np.maximum(int_ymax-int_ymin,0.)

int_w=np.maximum(int_xmax-int_xmin,0.)

#計算IOU

int_vol=int_h*int_w#交集面積

vol1=(bboxes1[2]-bboxes1[0])*(bboxes1[3]-bboxes1[1])#bboxes1面積

vol2=(bboxes2[2]-bboxes2[0])*(bboxes2[3]-bboxes2[1])#bboxes2面積

IOU=int_vol/(vol1+vol2-int_vol)#IOU=交集/并集

returnIOU

#NMS,或者用tf.image.non_max_suppression

defbboxes_nms(self,classes,scores,bboxes,nms_threshold=0.2):

keep_bboxes=np.ones(scores.shape,dtype=np.bool)

foriinrange(scores.size-1):

ifkeep_bboxes[i]:

overlap=self.bboxes_iou(bboxes[i],bboxes[(i+1):])

keep_overlap=np.logical_or(overlapnms_threshold,

classes[(i+1):]!=classes[i])#IOU沒有超過0.5或者是不同的類則保存下來

keep_bboxes[(i+1):]=np.logical_and(keep_bboxes[(i+1):],keep_overlap)

idxes=np.where(keep_bboxes)

returnclasses[idxes],scores[idxes],bboxes[idxes]

defpostprocess(self,bboxes,obj_probs,class_probs,image_shape=(416,416),threshold=0.5):

bboxes=np.reshape(bboxes,[-1,4])

#將所有box還原成圖片中真實

溫馨提示

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

評論

0/150

提交評論