結果展示
其中綠線是我繪制的圖像划分網格。
這里的loss是我訓練的 0.77 ,由於損失函數是我自己寫的,所以可能跟大家的不太一樣,這個不重要,重要的是學習思路。


重點提示
yolov1是一個目標檢測的算法,他是一階段的檢測算法。
一階段(
one-stage):檢測物體的同時進行分類。(代表論文:yolov1 - yolov5)二階段(
two-stage):先檢測出物體,再進行分類。(代表論文:rcnn,fast-rcnn)
重點要理解yolov1的數據特征標注方式。
只有理解了數據特征的標注方式才可以理解他為什么可以起作用。
論文剖析
1、理解
VOC數據集的數據形式。2、從
VOC數據集中提取出標注好的數據特征。3、
yolov1的數據組織。4、
yolov1的算法模型。5、
yolov1的准確率評估方式(IOU)。6、
yolov1的損失函數。
理解VOC數據集
首先需要知道我們使用的數據集的形式,因為每一個數據集的特征標注以及組織方式都不同。
我們可以去官網下載voc的數據集,這里使用的是voc2012數據集。
VOC數據集鏡像網站. 下載voc2012的Train/Validation Data (1.9 GB)。
數據集下載之后解壓出來是這樣子:
每個文件夾存放的啥都標注好了,我們這里用不到那么多。
我們只用jpg原圖,以及每個原圖中目標的位置即可。(下邊圖片中畫紅框的兩個文件夾)

但是我們發現,Annotations文件夾中的目標位置信息是存放在xml中,所以我們往下分析一個xml文件看看。
<filename>: 表示這個文件是對應於哪一個jpg圖片的。
<size>:表示對應的jpg圖片大小。
<object>:就是這個圖片中的目標在圖片中的信息。包括:目標名字,是否難識別,以及目標在整個圖片中的坐標位置。(有幾個 object 就是有幾個目標)

提取目標初始數據
上邊我們分析出每個圖片中有什么目標都是存儲在
xml文件中的,所以我們需要將xml文件的目標與類別數據提取出來,以便我們使用。
思路:
-
1、使用庫
xml.etree.ElementTree讀取xml格式的文件,從中提取出每一個xml文件中的所有<ojgect>標簽數據(個數就是目標的數量)。 -
2、將
<object>標簽提取出類別、xmin、ymin、xmax、ymax,並且將其歸一化為類別、x、y、w、h。
歸一化就是根據從目標中提取出的
xmin、ymin、xmax、ymax得到目標的寬高,分別除以整個圖片的寬高。
x:目標的中心位置x坐標。y:目標的中心位置y坐標。w:目標的寬度,h:目標的高度。
- 3、然后將歸一化的數據按照上面的格式,整理為labels文件。
每一個
labels文件對應於一個圖片,labels文件中的每一行就是這個圖片中的一個目標的類別、x、y、w、h數據(一個圖片有幾個目標,對應的labels文件就有幾行)。
例子:
針對如下xml文件,可以得知:
- 對應的
jpg圖片是2007_000042.jpg,並且圖片的大小是500*335的三色圖(這里的圖片大小就是用來歸一化的)。- 含有兩個
<object>標簽,所以這個圖片中有兩個目標,並且目標的類別、位置坐標可以根據name、xmin、ymin、xmax、ymax得到。
<annotation>
<folder>VOC2012</folder>
<filename>2007_000042.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
</source>
<size>
<width>500</width>
<height>335</height>
<depth>3</depth>
</size>
<segmented>1</segmented>
<object>
<name>train</name>
<pose>Unspecified</pose>
<truncated>1</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>263</xmin>
<ymin>32</ymin>
<xmax>500</xmax>
<ymax>295</ymax>
</bndbox>
</object>
<object>
<name>train</name>
<pose>Unspecified</pose>
<truncated>1</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>1</xmin>
<ymin>36</ymin>
<xmax>235</xmax>
<ymax>299</ymax>
</bndbox>
</object>
</annotation>
大致如下:綠色框 與 藍色框 分別是兩個目標。

使用xml文件中已有數據,得到 labels文件如下:
其中每一行是一個物體,每行的數據表示的意義是:
類別,x,y,w,h. (數據都是歸一化過了)

所以,這個就是最初的labels文件的形式。
下一步就是將這個初始labels文件數據形式,組織成可以 直接與對應圖片運行 的數據形式。
YOLOV1的數據組織
其實yolo的思想可以用一句話來代替:將一個張圖片划分網格(通常是
7*7),然后找目標的中心落在那個網格中(得到目標中心點坐標),並且以中心點坐標為參考找出目標邊框的寬與高。
將圖片進行網格划分
如圖,針對圖片進行
7*7的網格划分。

找目標物體中心落所在的網格
所以這個圖片中的兩個目標
cat與person的中心點分別落在網格中的(5,1)與(3,4)兩個位置,並且可以知道這個中心點相對於當前網格的坐標(就是紫色框表示的內容)。

目標物體的寬高
在物體中心點找出之后,以中心點為坐標找出邊框的寬與高即可。
經過上邊的分析,我們可以發現:想要確定一個物體,只要知道它的中心點坐標,以及相對於中心點坐標的物體寬高即可。
所以:當我們的模型拿到一張圖片之后
- 首先,將圖片進行網格划分。
- 然后,判斷每一個小網格中是否有物體。
- 如果預測有物體就預測出物體相對於本網格的坐標,以及相對於本坐標的物體寬高。
labels的組織方式
labels的數據都是來自上邊xml中提取的數據。
經過上邊yolo運作流程的講解,可以得知labels數據需要 針對每一個小網格 組織出:相對於當前網格中心點的坐標,寬高,預測概率,目標類別。
其中:
- 預測概率的值是 1或0,有目標的時候預測值是1,沒目標的時候預測值是0。
- 這里用20個類別,每一個網格預測的目標是什么類別,則對應的類別數字為1,否則為0 (細節見下圖)。
注意:由於每一個網格中可能會有多個目標的中心點,所以這里的labels組織的時候,將每個格子預測兩個中心點。(細節見下圖)
這個圖是所有網格的數據形式。數據長度為30.
**這個圖中的所有數據都可以根據 上文從xml中提取的數據得到。 **

由此可知,每個網格的labels是由長度為30的上述數據組成的;因為我們的圖片划分為7*7個網格,所以就是有7*7個長度為30的數據組成整個圖片的lables。即整張圖片的labels數據形式為:7*7*30。labels數據矩陣如下圖所示。

所以,我們輸入網絡的數據就是圖片轉為tensor的數據,inputs維度為:[batchsize,3,448,448].
網絡的輸入labels維度為:[batchsize,30,7,7]. 就是上邊的數據矩陣。
網絡的輸出:[batchsize,30,7,7].
ok,上邊的數據組織完成,那么接下來就是將組織好的 inputs 與 labels 送入網絡訓練即可。
YOLOV1模型
- 網絡有24個卷積層,然后是2個全連接層,簡化了1×1還原層,由3×3個卷積層組成。
- (原文使用的是imageNet作為預處理模型,然后后邊的輸出重寫成所需要的輸出。)
- 我這里使用的是基於resnet的預處理模型。
評估標准IOU
IOU就是交並比,因為原來有一個正確的目標邊框數據,此時我們預測一個邊框數據之后,計算出兩個邊框相交的面積,在計算出相並的面積,然后求出比值,就是交並比。

交並比越 大 ,說明兩個框子越相似,說明預測結果越好。最大 IOU=1 ,就是預測框與真實框重合。
交並比越 小 ,說明兩個框子越不相似,說明預測結果越差。最小 IOU=0 ,就是預測框與真實框沒有一點相交的地方。
損失函數
三部分組成。

