這里主要從輸入數據增量、新增層和檢測層的處理三個方面來說下v2版本,文中使用的參數和數值為代碼中默認值並以voc數據集為例來說明的。
一.輸入數據處理
V2版本處理具有前一個版本對數據增量處理方式外,還新增了對輸入圖像的色度、飽和度、曝光的處理,這三個分量都采用了和jitter類似的手段:產生一個指定范圍的隨機數,調整輸入圖像作為傳播使用的數據。
對truth的使用上相對v1發生了變化,一張圖片最大能容納30個目標(這30個目標是預定的,可以修改),超過30個的目標舍去,每個目標以(x,y,w,h,id)為順序存儲。每張圖片對應的輸出outpunum為5*30 = 150個。
二.新增層的處理
route layer
它主要是將指定的某一層(當然指定的那一層在它之前)輸出數據作為輸入,copy過來,再做為輸出使用,指定的層由layers參數確定,將不同大小的特征圖連接到一塊。其實這個操作在caffe里都不能算一層,只需要指針指向一下就可以了。這里主要說下copy的順序,Layers參數可以有多個,即將多個層的數據拷貝過來做為輸出。將每個batch中的各個層數據一次copy到output,即拷貝后的結果為:
L1 L2…Ln, L1 L2…Ln, …, L1 L2…Ln
batch1, batch2, … batchm
reorg layer
該層不是必須跟在route layer之后,它是否需要存在要看上面一層特征的大小是否需要變化,在voc的例子中,由於需要將26層的26*26*512的特征圖轉化成13*13*2048,使用stride為2的reorg layer。
該層將512個通道分成了4部分,分別遍歷了所有數據,結合reorg_cpu的代碼來看
第1部分 k∈(0-127),橫向從0開始取偶數位w=26個,縱向間隔stride*w*stride(4行),則通道間隔為h*stride*w*stride(從這里可以看出通道變化范圍必須為原來的1/4)
第2部分 k∈(128-255),橫向從1開始取奇數位w=26個,之后同上(c2與上一樣但offset變化為從1開始,而h2起始值沒變)
第3部分 k∈(256-383),橫向從52開始取偶數位w=26個(h2起始位1,則out_index起始位52,之后與1部分相同)
第4部分 k∈(384-511)橫向從53開始取奇數位w=26個(h2起始為1,w2起始為1,則out_index起始為53,后續規律相同)
如此每部分循環取從頭開始緊鄰4行的1/4,恰好取完.
三.檢測層的處理
網絡最后的輸出,它沒有像v1那樣使用全連接的方法,而是使用1*1的卷積生成125個通道,輸出尺寸為w*h*c = 13*13*125,即將每張圖片划分為13*13個網格,每個網格預測5個目標,每個目標包含三個部分,依次為:目標位置4個點、包含目標置信度1個點、目標類別置信度20個點,總共25個點。為了更加方便的以偏移取數據,使用flatten方法將最后的網絡輸出做轉置處理,這樣網絡變成了125*13*13,每次取數據都可以按各個網絡的5個預測目標依次處理。也可以將flatten理解成將輸出的三維矩陣壓扁成125*169的二維矩陣,對之后的取數據來講,是等效的。
這個很好理解,按照作者的思路,如果不使用flatten,按順序取數據(目標位置、置信度、坐標)為13行的每一行的列中分別取出,不符合上面的要求,轉置后,變成了13*13的每個位置上取5組可能的預測信息。
對於是否包含目標的置信度,輸出取logistic激活,是為了將輸出壓縮到0-1之間,用於后續計算誤差(有無目標)。
對於目標類別置信度,仍然采用了softmax方法處理。然后就是計算回歸的位置誤差敏感項,根據誤差求導生成。
這里還要說下在使用v2版本的時候遇到的一個多gpu下訓練不收斂的問題,或者出現nan,或者訓練的時候收斂,但是是否有目標的置信度逐漸減小,直至為0,這樣預測的目標置信度就都是0了。我是用的是tiny-yolo.cfg的配置,經過排查和各種嘗試,發現剛開始訓練時學習速率太大,在steps為-1,100,80000,100000的分段調整速率的划分中,使用小速率多學習一段時間,即可解決這個問題,比如改為-1,1000,80000,100000.分享出來,避免大家遇到相同的問題而糾結很久。
