yolov3的訓練**從 detector.c de train_detector()函式開始,函式如下:
void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear, int dont_show)
如果訓練**為:
*datacfg代表的是 voc.data ,*cfgfile代表的是 yolov3-voc.cfg
voc.data格式:
下面解讀train_detector()下的函式.
list *options = read_data_cfg(datacfg);
這個函式的作用是解析voc.data中的資料,並將資料存入到頭結點為options的雙向鍊錶中,
裡面的關鍵函式為:
int read_option(char *s, list *options)
}if(i == len-1) return 0;
char *key = s;
option_insert(options, key, val);
return 1;
}
可以看出程式將voc.data中的資料以「=」為界限分為兩類字元,左邊為key 右邊為val,然後插入到options鍊錶中。在opton_insert()函式中可以看到,作者將key與val包裝成乙個node節點中的val,val的格式如下:
typedef struct kvp;
以上,可以看出作者將voc.data中的資料按照每一行為乙個node節點加入乙個options鍊錶中,每個node中包含三個重要資訊,分別為key,val,used(初始為零,標籤處理),三個資訊包裝成乙個struct。
下面函式:
char *train_images = option_find_str(options, "train", "data/train.list");
將訓練位址傳入到train_images中。同時將options煉表頭指標指向key為train的下一行,used設為1。至此,將訓練位址匯入到train_images中。注意:這裡train_images指向的是個寫入位址的txt檔案的位址。
網路模型的解析:
char *base = basecfg(cfgfile);
上面的函式將訓練**(4)cfg/後的資料傳入到*base中。以例子為視:*base = yolov3-voc.cfg.
轉入到parser.c檔案中,解讀
network parse_network_cfg_custom(char *filename, int batch)
*filename是yolov3-voc.cfg,裡面的batch是0;
這裡看list *read_cfg()函式:
list *read_cfg(char *filename)
break;}}
fclose(file);
return sections;
}
在看這個程式之前先放幾個比價重要的結構體:
typedef struct list list;
typedef structsection;
typedef struct node node;
typedef struct kvp;
這幾個結構體構成鍊錶,下面是程式解讀。
這裡將yolov3-voc.cfg中的網路層鏈入到乙個鍊錶中,名稱為sections,鍊錶中每個節點是list結構體。同時將每一層引數解析到乙個section結構體中,結構體名為current,這裡放出來下面這個函式:
void list_insert(list *l, void *val)
else
l->back = new;
++l->size;
}
從這個函式可以看到,作者將current包裝成乙個node->val,讓後將node作為節點插入到list鍊錶中,這裡node->val(current)結構體是section,包含兩個變數,tpye與options。
section結構體中包含乙個list鍊錶,名為options,往深處扒拉扒拉可以看到,這個options鍊錶主要為了儲存乙個網路層中不同的引數,拿第乙個[net]層為例。
type中的值是』net』,options中的的節點node中儲存著』height=416』這一類資料,node中有key與val ,key = height,val=416。
轉入到list *read_cfg(char *filename)函式的下面的程式段中:
case '[':
current = malloc(sizeof(section));
list_insert(sections, current);
current->options = make_list();
current->type = line;
break;
在這一段可以看出,在識別出"["這個符號後,作者將current插入到sections鍊錶中,轉入到list_insert()這個函式中:
void list_insert(list *l, void *val)
else
l->back = new;
++l->size;
}
這裡是乙個雙向鍊錶插入程式,最後的 ++l->size;表明乙個yolov3網路結構有size個網路層,且第乙個網路層時從1開始的。
將current(代表的是乙個網路層)的頭位址作為節點位址插入到sections(代表的是整個yolov3網路)鍊錶中後,作者以第乙個current->options的頭位址作為鍊錶的頭位址建立乙個鍊錶:
current->options = make_list();
這個鍊錶中儲存的資訊在一下程式段中:
default:
if(!read_option(line, current->options))
break;
read_option()函式如下:
int read_option(char *s, list *options)
}if(i == len-1) return 0;
char *key = s;
option_insert(options, key, val);
return 1;
}
這個函式主要將我上面說的section插入到options中。最後在list *read_cfg(char *filename)中多次迴圈,將乙個網路層以current插入到sections中,而將乙個網路層的引數current->otpions的鍊錶中。
最終:將各個node鏈成乙個options(list結構)鍊錶,代表乙個網路層的引數,將網路層名稱(「net」)賦值給type,而options與type合成為乙個current。然後將current作為乙個節點鏈入到sections(list)中,sections是整個yolov3網路結構。
至此,整個網路載入到鍊錶sections中。
yolov3資料讀入(二)
前面以一篇文章將寫將yolov3網路層引數載入出來。這裡有幾個結構體在yolov3中的鍊錶中作用比較大 typedef struct list list typedef struct node node typedef struct kvp typedef structsection node n ...
yolov3系列 零 yolov3詳解
目標檢測演算法與efficientdet講解 論 文 翻譯 yolov3主頁 yolo系列的目標檢測演算法可以說是目標檢測史上的巨集篇巨作,v3演算法是在v1 v2基礎上形成的,先看下 yolov1 yolov2 下圖為yolov3的網路結構 dbl darknetconv2d bn leaky 是...
YOLOv3 從入門到部署 (一)YOLOv3概述
這是目標檢測領域常用的兩個資料集。voc和coco的區別主要在於影象標註的格式不一樣。voc將目標的標籤資訊以某種格式儲存在.xml格式的檔案中,而coco則是儲存在.txt檔案中。因此有時候voc和coco不是指資料集,而是指資料集標註格式。我們完全沒有必要去研究每種標註格式的細節,網路也有大量的...