丁香五月天婷婷久久婷婷色综合91|国产传媒自偷自拍|久久影院亚洲精品|国产欧美VA天堂国产美女自慰视屏|免费黄色av网站|婷婷丁香五月激情四射|日韩AV一区二区中文字幕在线观看|亚洲欧美日本性爱|日日噜噜噜夜夜噜噜噜|中文Av日韩一区二区

您正在使用IE低版瀏覽器,為了您的雷峰網(wǎng)賬號安全和更好的產(chǎn)品體驗,強烈建議使用更快更安全的瀏覽器
此為臨時鏈接,僅用于文章預(yù)覽,將在時失效
人工智能開發(fā)者 正文
發(fā)私信給孔令雙
發(fā)送

0

YOLO,一種簡易快捷的目標檢測算法

本文作者: 孔令雙 2018-01-24 14:29
導(dǎo)語:本文會對YOLO的思路進行總結(jié)并給出關(guān)鍵代碼的分析。

雷鋒網(wǎng) AI 研習(xí)社按:本文為知乎主兔子老大為雷鋒網(wǎng) AI 研習(xí)社撰寫的獨家稿件。

YOLO全稱You Only Look Once,是一個十分容易構(gòu)造目標檢測算法,出自于CVPR2016關(guān)于目標檢測的方向的一篇優(yōu)秀論文(https://arxiv.org/abs/1506.02640 ),本文會對YOLO的思路進行總結(jié)并給出關(guān)鍵代碼的分析,在介紹YOLO前,不妨先看看其所在的領(lǐng)域的發(fā)展歷程。

目標檢測

相對于傳統(tǒng)的分類問題,目標檢測顯然更符合現(xiàn)實需求,因為往往現(xiàn)實中不可能在某一個場景只有一個物體(業(yè)務(wù)需求也很少會只要求分辨這是什么),但也因此目標檢測的需求變得更為復(fù)雜,不僅僅要求detector能夠檢驗出是什么物體,還的確定這個物體在圖片哪里。

總的來說,目標檢測先是經(jīng)歷了最為簡單而又暴力的歷程,這個過程高度的符合人類的直覺。簡單點來說,既然要我要識別出目標在哪里,那我就將圖片劃分成一個個一個個小圖片扔進detector,但detecror認為某樣物體在這個小區(qū)域 上了,OK,那我們就認為這個物體在這個小圖片上了。而這個思路,正是比較早期的目標檢測思路,比如R-CNN。

然后來的Fast R-CNN,F(xiàn)aster R-CNN雖有改進,比如不再是將圖片一塊塊的傳進CNN提取特征,而是整體放進CNN提取除 featuremap 然后再做進一步處理,但依舊是整體流程分為區(qū)域提取 和 目標分類 兩部分(two-stage),這樣做的一個特點是雖然精度是保證了,但速度上不去,于是以YOLO為主要代表的這種一步到位(one-stage)即 End To End 的目標算法應(yīng)運而生了。

YOLO詳解

細心的讀者可能已經(jīng)發(fā)現(xiàn),是的,YOLO的名字You only look once正是自身特點的高度概括。

YOLO的核心思想在于將目標檢測作為回歸問題解決 ,YOLO首先將圖片劃分成SxS個區(qū)域,注意這個區(qū)域的概念不同于上文提及將圖片劃分成N個區(qū)域扔進detector這里的區(qū)域不同。上文提及的區(qū)域是真的將圖片進行剪裁,或者說把圖片的某個局部的像素扔進detector,而這里的劃分區(qū)域,只的是邏輯上的劃分。

為什么是邏輯上的劃分呢?這體現(xiàn)再YOLO最后一層全連接層上,也就是YOLO針對每一幅圖片做出的預(yù)測。

其預(yù)測的向量是SxSx(B*5+C)長度的向量。其中S是劃分的格子數(shù),一般S=7,B是每個格子預(yù)測的邊框數(shù) ,一般B=2,C是跟你實際問題相關(guān)的類別數(shù),但要注意的是這里你應(yīng)該背景當作一個類別考慮進去。

不難得出,這個預(yù)測向量包括:

  • SxSxC 個類別信息,表示每一個格子可能屬于什么類別

  • SxSxB 個置信度,表示每一個格子的B個框的置信度,再YOLO進行預(yù)測后,一般只保留置信度為0.5以上的框。當然這個閾值也可以人工調(diào)整。

  • SxSxBx4 個位置信息,4個位置信息分別是xywh,其中xy為box的中心點。

說完YOLO的總體思路后,我們在看看YOLO的網(wǎng)絡(luò)結(jié)構(gòu)


YOLO,一種簡易快捷的目標檢測算法

該網(wǎng)絡(luò)結(jié)構(gòu)包括 24 個卷積層,最后接 2 個全連接層。文章設(shè)計的網(wǎng)絡(luò)借鑒 GoogleNet 的思想,在每個 1x1 的 歸約層(Reduction layer,1x1的卷積 )之后再接一個 3?3 的卷積層的結(jié)構(gòu)替代 Inception結(jié)構(gòu)。論文中還提到了 fast 版本的 Yolo,只有 9 個卷積層,其他則保持一致。

因為最后使用了全連接層,預(yù)測圖片要和train的圖片大小一致,而其他one-stage的算法,比如SSD,或者YOLO-V2則沒有這個問題,但這個不在本文討論范圍內(nèi)。

其實網(wǎng)絡(luò)架構(gòu)總體保持一致即可,個人不建議照抄全部參數(shù),還是需要根據(jù)你的實際任務(wù)或計算資源進行魔改,所以接下來重點會講述訓(xùn)練的過程和損失函數(shù)的構(gòu)建,其中也會給出MXNET版本的代碼進行解釋。文末會給出全部代碼的開源地址。

損失函數(shù)的定義


YOLO,一種簡易快捷的目標檢測算法

圖片來源于網(wǎng)絡(luò)

大體來說,損失函數(shù)分別由:

  • 預(yù)測框位置的誤差 (1)(2)

  • IOU誤差(3)(4)

  • 類別誤差(5)

其中,每一個組成部分對整體的貢獻度的誤差是不同的,需要乘上一個權(quán)重進行調(diào)和。相對來說,目標檢測的任務(wù)其實更在意位置誤差,故位置誤差的權(quán)重一般為5。在此,讀者可能費解,為什么框的寬和高取的是根號,而非直接計算?

想要了解這個問題,我們不妨來看看的YOLO,一種簡易快捷的目標檢測算法圖像

YOLO,一種簡易快捷的目標檢測算法

這里額外多說一句,如果有打數(shù)據(jù)挖掘比賽經(jīng)驗的同學(xué),可能會比較清楚一種數(shù)據(jù)處理的手段,當某些時候,會對某一特征進行數(shù)據(jù)變換,比如YOLO,一種簡易快捷的目標檢測算法YOLO,一種簡易快捷的目標檢測算法,取 log 這些變換有一個特征,就是數(shù)值越大,懲罰越大(變換的幅度越大,比如4和4的平方,10到10的平方)。

而在損失函數(shù)中應(yīng)用這一方法,起到的作用則是使得小框產(chǎn)生的誤差比大框的誤差更為敏感,其目的是為了解決對小物體的檢測問題。但事實上,這樣的設(shè)定只能緩解卻沒有最終解決這個問題。

在說IOU誤差,IOU的定義為實際描框和預(yù)測框之間的交集除以兩者之間的并集。

聽上去很復(fù)雜,實際我們既然能獲得預(yù)測框坐標,只要通過簡單的換算,該比值實際能轉(zhuǎn)換成面積的計算。而同樣的,這里也有一個問題,我們感興趣的物體,對于整體圖片來說,畢竟屬于小數(shù)。換言之,就是在SxS個格子里面,預(yù)測出來的框大多是無效的框,這些無效框的誤差積累是會對損失函數(shù)產(chǎn)生影響,換句話說,我們只希望有物體的預(yù)測框有多準,而不在乎沒有物體的框預(yù)測得有多差。因此,我們也需要對這些無效框的在損失函數(shù)上得貢獻乘上一個權(quán)重,進行調(diào)整。

也就是λnoobj,該值一般取0.5。

關(guān)于分類誤差,論文雖然是采用mse來衡量,但是否采用交叉熵來衡量更合理呢?對于分類問題,采用mse和交叉熵來衡量,又會產(chǎn)生什么問題?這個問題留給讀者思考。

代碼實現(xiàn)

說完了損失函數(shù),下面來講述如何使用MXNET來實現(xiàn)YOLO,同理的,YOLO的網(wǎng)絡(luò)結(jié)構(gòu)較為簡單,你可以采用任何的框架搭出,如果像我一樣只是為了演示demo,對網(wǎng)絡(luò)結(jié)構(gòu)可以修改一下,采取網(wǎng)絡(luò)拓撲上比較簡單的模型。

同樣的,目標檢測常使用在ImageNet上預(yù)訓(xùn)練(pretrain)的模型 作為特征抽取器,同樣,因為這里只是演示demo,同樣也省略這一部分,只是重點講損失函數(shù)的構(gòu)造。

首先,雖然損失函數(shù)雖然是邏輯上分成三個部分,但我們不打算分開三個部分計算。

而是將整體式子拆分成 W x loss來計算,這樣在代碼上,實現(xiàn)起來要方便得多,以下時loss函數(shù)的計算過程:

def hybrid_forward(self, F, ypre, label):
   label_pre, preds_pre, location_pre =self._split_y(ypre)
   label_real, preds_real, location_real=self._split_y(label)
   batch_size =len(label_real)
   loss =nd.square(ypre - label)
   class_weight=nd.ones(
   shape =(batch_size, self.s*self.s*self.c))*self._scale_class_prob
   location_weight = nd.ones(shape = (batch_size, self.s *self.s *self.b, 4))
   confs =self._calculate_preds_loss(preds_pre,preds_real, location_pre, location_real)
   preds_weight =self._scale_noobject_conf * (1. - confs) +self._scale_object_conf * confs  
   location_weight = (nd.expand_dims(preds_weight, axis=2) * location_weight) *self._scale_coordinate
   location_weight = nd.reshape(location_weight, (-1, self.s *self.s *self.b *4))
   W =nd.concat(*[class_weight, preds_weight, location_weight], dim=1)
   total_loss = nd.sum(loss * W, 1)
   return total_loss

可能會有童鞋好奇,為什么坐標誤差是用預(yù)測值和label直接mse算呢,w和h不是應(yīng)該要開根號嗎?是的,但我們?yōu)榱藬?shù)值穩(wěn)定,在人工構(gòu)建label時就已經(jīng)將wh以開根后的形式存儲好了,這是因為,神經(jīng)網(wǎng)絡(luò)的輸出在初始時,正負值時隨機的,盡管在數(shù)學(xué)上YOLO,一種簡易快捷的目標檢測算法的結(jié)果是虛數(shù)i,但在DL相關(guān)的框架,該操作會直接造成nan,造成損失函數(shù)無法優(yōu)化,而且相應(yīng)代碼的書寫更為復(fù)雜。而采取直接以取根號后的形式我們只要在獲取輸出時,再將wh求一個平方即可。

另外要說的一點就是IOU誤差,雖然很多文章都將這一點直接成為IOU誤差,實際上計算時IOU誤差和置信度的結(jié)合。

def_iou(self, box, box_label):
   wh = box[:, :, :, 2:4]
   wh = nd.power(wh, 2)
   center = box[:, :, :, 0:1]
   predict_areas = wh[:, :, :, 0] * wh[:, :, :, 1]

   predict_bottom_right = center +0.5* wh
   predict_top_left =center -0.5* wh

   wh = box_label[:, :, :, 2:4]
   wh = nd.power(wh, 2)
   center = box_label[:, :, :, 0:1]
   label_areas = wh[:, :, :, 0] * wh[:, :, :, 1]

   label_bottom_right = center +0.5* wh
   label_top_left = center -0.5* wh
   temp = nd.concat(*[predict_top_left[:, :, :, 0:1], label_top_left[:, :, :, 0:1]], dim=3)
   temp_max1 = nd.max(temp, axis=3)
   temp_max1 = nd.expand_dims(temp_max1, axis=3)
   temp = nd.concat(*[predict_top_left[:, :, :, 1:], label_top_left[:, :, :, 1:]], dim=3)
   temp_max2 = nd.max(temp, axis=3)
   temp_max2 = nd.expand_dims(temp_max2, axis=3)

   intersect_top_left = nd.concat(*[temp_max1, temp_max2], dim=3)
   temp = nd.concat(*[predict_bottom_right[:, :, :, 0:1], label_bottom_right[:, :, :, 0:1]], dim=3)
   temp_min1 = nd.min(temp, axis=3)
   temp_min1 = nd.expand_dims(temp_min1, axis=3)
   temp = nd.concat(*[predict_bottom_right[:, :, :, 1:], label_bottom_right[:, :, :, 1:]], dim=3)
   temp_min2 = nd.min(temp, axis=3)
   temp_min2 = nd.expand_dims(temp_min2, axis=3)

   intersect_bottom_right = nd.concat(*[temp_min1, temp_min2], dim=3)
   intersect_wh = intersect_bottom_right - intersect_top_left
   intersect_wh = nd.relu(intersect_wh)  # 把0過濾了
   intersect = intersect_wh[:, :, :, 0] * intersect_wh[:, :, :, 1]  
   ious = intersect / (predict_areas + label_areas - intersect)
   max_iou = nd.expand_dims(nd.max(ious,2),axis=2)
   best_ = nd.equal(max_iou,ious)
   best_boat = nd.ones(shape = ious.shape)
   for batch in range(len(best_)):
       best_box[batch] = best_[batch]
   return nd.reshape(best_box, shape=(-1, self.s*self.s*self.b))

   def_calculate_preds_loss(self, ypre, label, local_pre, local_label):
      ious =self._iou(local_pre, local_label)
      conf = label * ious  
      returnconf

置信度在label的表現(xiàn)形式時,這個地方有目標物體則為1,沒有則是0,這樣用mse優(yōu)化后,輸出值會在0~1附近,正好可以代表某個框是否框中物體的置信度。

但為什么不直接 對置信度用mse呢,這同樣是一個權(quán)重的調(diào)節(jié)的問題,但這里不能說我們就不care那些沒有物體的框的值了,因為這里的值是置信度,如果我們?nèi)斡善浒l(fā)展,萬一沒有物體的框的置信度比有框中物體的置信度還要高,那我們使用閾值過濾時,就可能出現(xiàn)問題了。只能說我們希望loss中更重視有框中物體的框的誤差。

這里補充另外一個知識點最大值抑制 ,簡單點來說,既然每個格子會生成B個框(一般B>1)這樣就有可能同時兩個框都框中了物體,那么到底采用那個框作為預(yù)測結(jié)果呢?答案是采用IOU值高的那個框,而IOU值小的,就會不被重視而受到抑制。

ious = intersect / (predict_areas + label_areas -intersect)
max_iou = nd.expand_dims(nd.max(ious,2),axis=2)
best_ = nd.equal(max_iou,ious)
best_boat =nd.ones(shape = ious.shape)
for batch in range(len(best_)):
   best_box[batch] = best_[batch]
return nd.reshape(best_box, shape=(-1, self.s*self.s*self.b))

在求出IOU后,我們求出每一個格子的框中的最大值,再使用equal操作,使得最大值為1,其余值為0再參與后面的運算即可。

代碼地址

DEMO-github:(https://github.com/MashiMaroLjc/YOLO

代碼使用的是李沐公開課的皮卡丘數(shù)據(jù)集,用MXNET的Gluon接口實現(xiàn),enjoy it!

運行效果:

YOLO,一種簡易快捷的目標檢測算法

上述文章若有不正確的地方,敬請指正。

雷峰網(wǎng)特約稿件,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。

YOLO,一種簡易快捷的目標檢測算法

分享:
相關(guān)文章
當月熱門文章
最新文章
請?zhí)顚懮暾埲速Y料
姓名
電話
郵箱
微信號
作品鏈接
個人簡介
為了您的賬戶安全,請驗證郵箱
您的郵箱還未驗證,完成可獲20積分喲!
請驗證您的郵箱
立即驗證
完善賬號信息
您的賬號已經(jīng)綁定,現(xiàn)在您可以設(shè)置密碼以方便用郵箱登錄
立即設(shè)置 以后再說