前言: 與其他框架不同,Darknet構建網絡架構不是通過代碼直接堆疊,而是通過解析cfg文件進行生成的。cfg文件格式是有一定規則,雖然比較簡單,但是有些地方需要對yolov3有一定程度的熟悉,才能正確設置。
下邊以yolov3.cfg為例進行講解。
- 作者:pprp
- 首發:GiantPandaCV公眾號
1. Net層
[net]
#Testing
#batch=1
#subdivisions=1
#在測試的時候,設置batch=1,subdivisions=1
#Training
batch=16
subdivisions=4
#這里的batch與普遍意義上的batch不是一致的。
#訓練的過程中將一次性加載16張圖片進內存,然后分4次完成前向傳播,每次4張。
#經過16張圖片的前向傳播以后,進行一次反向傳播。
width=416
height=416
channels=3
#設置圖片進入網絡的寬、高和通道個數。
#由於YOLOv3的下采樣一般是32倍,所以寬高必須能被32整除。
#多尺度訓練選擇為32的倍數最小320*320,最大608*608。
#長和寬越大,對小目標越好,但是占用顯存也會高,需要權衡。
momentum=0.9
#動量參數影響着梯度下降到最優值得速度。
decay=0.0005
#權重衰減正則項,防止過擬合。
angle=0
#數據增強,設置旋轉角度。
saturation = 1.5
#飽和度
exposure = 1.5
#曝光量
hue=.1
#色調
learning_rate=0.001
#學習率:剛開始訓練時可以將學習率設置的高一點,而一定輪數之后,將其減小。
#在訓練過程中,一般根據訓練輪數設置動態變化的學習率。
burn_in=1000
max_batches = 500200
#最大batch
policy=steps
#學習率調整的策略,有以下policy:
#constant, steps, exp, poly, step, sig, RANDOM,constant等方式
#調整學習率的policy,
#有如下policy:constant, steps, exp, poly, step, sig, RANDOM。
#steps#比較好理解,按照steps來改變學習率。
steps=400000,450000
scales=.1,.1
#在達到40000、45000的時候將學習率乘以對應的scale
2. 卷積層
[convolutional]
batch_normalize=1
#是否做BN操作
filters=32
#輸出特征圖的數量
size=3
#卷積核的尺寸
stride=1
#做卷積運算的步長
pad=1
#如果pad為0,padding由padding參數指定。
#如果pad為1,padding大小為size/2,padding應該是對輸入圖像左邊緣拓展的像素數量
activation=leaky
#激活函數的類型:logistic,loggy,relu,
#elu,relie,plse,hardtan,lhtan,
#linear,ramp,leaky,tanh,stair
# alexeyAB版添加了mish, swish, nrom_chan等新的激活函數
feature map計算公式:
3. 下采樣
可以通過調整卷積層參數進行下采樣:
[convolutional]
batch_normalize=1
filters=128
size=3
stride=2
pad=1
activation=leaky
可以通過帶入以上公式,可以得到OutFeature是InFeature的一半。
也可以使用maxpooling進行下采樣:
[maxpool]
size=2
stride=2
4. 上采樣
[upsample]
stride=2
上采樣是通過線性插值實現的。
5. Shortcut和Route層
[shortcut]
from=-3
activation=linear
#shortcut操作是類似ResNet的跨層連接,參數from是−3,
#意思是shortcut的輸出是當前層與先前的倒數第三層相加而得到。
# 通俗來講就是add操作
[route]
layers = -1, 36
# 當屬性有兩個值,就是將上一層和第36層進行concate
#即沿深度的維度連接,這也要求feature map大小是一致的。
[route]
layers = -4
#當屬性只有一個值時,它會輸出由該值索引的網絡層的特征圖。
#本例子中就是提取從當前倒數第四個層輸出
6. YOLO層
[convolutional]
size=1
stride=1
pad=1
filters=18
#每一個[region/yolo]層前的最后一個卷積層中的
#filters=num(yolo層個數)*(classes+5) ,5的意義是5個坐標,
#代表論文中的tx,ty,tw,th,po
#這里類別個數為1,(1+5)*3=18
activation=linear
[yolo]
mask = 6,7,8
#訓練框mask的值是0,1,2,
#這意味着使用第一,第二和第三個anchor
anchors = 10,13, 16,30, 33,23, 30,61, 62,45,\
59,119, 116,90, 156,198, 373,326
# 總共有三個檢測層,共計9個anchor
# 這里的anchor是由kmeans聚類算法得到的。
classes=1
#類別個數
num=9
#每個grid預測的BoundingBox num/yolo層個數
jitter=.3
#利用數據抖動產生更多數據,
#屬於TTA(Test Time Augmentation)
ignore_thresh = .5
# ignore_thresh 指得是參與計算的IOU閾值大小。
#當預測的檢測框與ground true的IOU大於ignore_thresh的時候,
#不會參與loss的計算,否則,檢測框將會參與損失計算。
#目的是控制參與loss計算的檢測框的規模,當ignore_thresh過於大,
#接近於1的時候,那么參與檢測框回歸loss的個數就會比較少,同時也容易造成過擬合;
#而如果ignore_thresh設置的過於小,那么參與計算的會數量規模就會很大。
#同時也容易在進行檢測框回歸的時候造成欠擬合。
#ignore_thresh 一般選取0.5-0.7之間的一個值
# 小尺度(13*13)用的是0.7,
# 大尺度(26*26)用的是0.5。
7. 模塊總結
Darket-53結構如下圖所示:

它是由重復的類似於ResNet的模塊組成的,其下采樣是通過卷積來完成的。通過對cfg文件的觀察,提出了以下總結:
不改變feature大小的模塊:
- 殘差模塊:
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
- 1×1卷積:可以降低計算量
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
- 普通3×3卷積:可以對filter個數進行調整
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky
改變feature map大小
- feature map減半:
[maxpool]
size=2
stride=2
或者
[convolutional]
batch_normalize=1
filters=128
size=3
stride=2
pad=1
activation=leaky
- feature map加倍:
[maxpool]
size=2
stride=1
特征融合操作
- 使用Route層獲取指定的層(13×13)。
- 添加卷積層進行學習但不改變feature map大小。
- 進行上采樣(26×26)。
- 從backbone中找到對應feature map大小的層進行Route或者Shortcut(26×26)。
- 融合完成。
后記:以上就是筆者之前使用darknet過程中收集和總結的一些經驗,掌握以上內容並讀懂yolov3論文后,就可以着手運行代碼了。目前使用與darknet一致的cfg文件解析的有一些,比如原版Darknet,AlexeyAB版本的Darknet,還有一個pytorch版本的yolov3。AlexeyAB版本的添加了很多新特性,比如 [conv_lstm], [scale_channels] SE/ASFF/BiFPN, [local_avgpool], [sam], [Gaussian_yolo], [reorg3d] (fixed [reorg]), fixed [batchnorm]等等。而pytorch版本的yolov3可以很方便的添加我們需要的功能。之后將會對這個版本進行改進,添加孔洞卷積、SE、CBAM、SK等模塊。
