Darknet 程式碼分析(之二,parse_network_cfg_custom函式)
阿新 • • 發佈:2018-11-19
parse_network_cfg_custom函式中,讀取配置檔案是先把各個section
讀取出來,然後再解析。
yolov3.cfg裡面只有幾個不同的section,分別是[net]、[convolutional]、[shortcut]、[yolo]、[route]、[upsample],下面分別探究。
NET(全域性)
參考 YOLO配置檔案理解
引數名稱 | 型別 | 預設值 | 說明 |
---|---|---|---|
Testing | - | - | |
Training | - | - | |
batch | int | 1 | 前向計算梯度和通過反向傳導更新權重值的計算中一次處理的圖片檔案的數量。 |
subdivisions | int | 1 | 批處理被細分為許多“塊”。塊的影象在gpu上並行執行。在darknet程式碼中,會將batch/subdivisions命名為batch,這個值設定比batch小往往回出現out out memory的問題。 |
width | int | 416 | 影象的寬,32的倍數 |
height | int | 416 | 影象的高,32的倍數 |
channels | int | 3 | 按照stackflow上的說法,用下圖來表述channels=4的情況:在左邊,我們有一個4x4畫素的單一通道,重組層將大小減小到一半,然後在不同通道中建立4個相鄰畫素的通道。我認為可能是表示顏色通道。 |
momentum | float | 0.9 | 見 深度學習中momentum的作用 一文的解釋 |
decay | float | 0.0005 | 權重衰減正則項,防止過擬合 |
angle | int | 0 | 通過旋轉角度來生成更多訓練樣本 |
saturation | float | 1.5 | 通過調整飽和度來生成更多訓練樣本 |
exposure | float | 1.5 | 通過調整曝光量來生成更多訓練樣本 |
hue | float | 0.1 | 通過調整色調來生成更多訓練樣本 |
learning_rate | float | 0.001 | 初始學習率 |
burn_in | int | 1000 | 對於第首個burn_in批的訓練,緩慢地提高學習率,直到它的最終值等於learning_rate設定的值。通過對學習率的監控可以瞭解到對於Loss函式的收斂的貢獻情況 |
max_batches | int | 1000 | 訓練達到max_batches後停止學習 |
policy | string | steps | 調整學習率的策略。policy取值:CONSTANT, STEP, EXP, POLY, STEPS, SIG, RANDOM。policy=steps 表示使用下面的steps引數和scales引數來調整訓練時的學習速度 |
steps | int array | 1000,2000 | 如取值是1000,2000,則表示在第1000個訓練批次和2000個批次後調整learning_rate |
scales | float array | 0.1,0.1 | 在1000個訓練批次後,LR = 0.1, 然後在2000個訓練批次後LR *= 0.1, 也就是說再執行一次調整 |
convolutional
引數:
引數名稱 | 型別 | 預設值 | 說明 |
---|---|---|---|
batch_normalize | bool | 1 | 是否非規範化這個layer,見函式denormalize_convolutional_layer |
filters | int | 255 | 輸出多少個特徵圖。filters =(classes + 5) x 3 |
size | int | 3 | 卷積核的尺寸 |
stride | int | 1 | 卷積運算的步長 |
pad | bool | 0 | 指定padding的方式 |
padding | int | 0 | padding由 padding引數指定。如果pad為1,padding大小為size/2 |
activation | string | logistic | “logistic”、“loggy”、“relu”、“elu”、“relie”、“plse”、“hardtan”、 “lhtan”、 “linear”、ramp"、“leaky”、“tanh”、"stair"是合法的啟用函式值。 |
binary | int | 0 | 暫未見使用,先不管 |
xnor | int | 0 | 暫未見使用,先不管 |
bin_output | int | 0 | 暫未見使用,先不管 |
相應程式碼段:
int n = option_find_int(options, "filters",1);
int size = option_find_int(options, "size",1);
int stride = option_find_int(options, "stride",1);
int pad = option_find_int_quiet(options, "pad",0);
int padding = option_find_int_quiet(options, "padding",0);
if(pad) padding = size/2;
char *activation_s = option_find_str(options, "activation", "logistic");
int batch_normalize = option_find_int_quiet(options, "batch_normalize", 0);
int binary = option_find_int_quiet(options, "binary", 0);
int xnor = option_find_int_quiet(options, "xnor", 0);
int use_bin_output = option_find_int_quiet(options, "bin_output", 0);
shortcut
引數:
引數名稱 | 型別 | 預設值 | 說明 |
---|---|---|---|
shortcut | int | - | 指向其他layer的索引偏移值,yolov3裡面是-3 |
activation | string | - | 啟用函式型別,yolov3裡面是“linear” |
相應程式碼段:
layer parse_shortcut(list *options, size_params params, network net)
{
char *l = option_find(options, "from");
int index = atoi(l);
if(index < 0) index = params.index + index;
int batch = params.batch;
layer from = net.layers[index];
layer s = make_shortcut_layer(batch, index, params.w, params.h, params.c, from.out_w, from.out_h, from.out_c);
char *activation_s = option_find_str(options, "activation", "linear");
ACTIVATION activation = get_activation(activation_s);
s.activation = activation;
return s;
}
yolo
引數:
引數名稱 | 型別 | 預設值 | 說明 |
---|---|---|---|
classes | int | 20 | |
num | int | 1 | |
mask | int | 0 | |
max | int | 90 | |
jitter | float | 0.2 | |
focal_loss | int | 0 | |
ignore_thresh | float | 0.5 | |
truth_thresh | int | 1 | |
random | int | 0 | |
map | string | “” | |
anchors | string | “” |
相應程式碼段:
layer parse_yolo(list *options, size_params params)
{
int classes = option_find_int(options, "classes", 20);
int total = option_find_int(options, "num", 1);
int num = total;
char *a = option_find_str(options, "mask", 0);
int *mask = parse_yolo_mask(a, &num);
int max_boxes = option_find_int_quiet(options, "max", 90);
layer l = make_yolo_layer(params.batch, params.w, params.h, num, total, mask, classes, max_boxes);
if (l.outputs != params.inputs) {
printf("Error: l.outputs == params.inputs \n");
printf("filters= in the [convolutional]-layer doesn't correspond to classes= or mask= in [yolo]-layer \n");
exit(EXIT_FAILURE);
}
//assert(l.outputs == params.inputs);
//l.max_boxes = option_find_int_quiet(options, "max", 90);
l.jitter = option_find_float(options, "jitter", .2);
l.focal_loss = option_find_int_quiet(options, "focal_loss", 0);
l.ignore_thresh = option_find_float(options, "ignore_thresh", .5);
l.truth_thresh = option_find_float(options, "truth_thresh", 1);
l.random = option_find_int_quiet(options, "random", 0);
char *map_file = option_find_str(options, "map", 0);
if (map_file) l.map = read_map(map_file);
a = option_find_str(options, "anchors", 0);
if (a) {
int len = strlen(a);
int n = 1;
int i;
for (i = 0; i < len; ++i) {
if (a[i] == ',') ++n;
}
for (i = 0; i < n && i < total*2; ++i) {
float bias = atof(a);
l.biases[i] = bias;
a = strchr(a, ',') + 1;
}
}
return l;
}
route
route layer只有一個引數,layers,指定一個輸入的layer。
route_layer parse_route(list *options, size_params params, network net)
{
char *l = option_find(options, "layers");
int len = strlen(l);
if(!l) error("Route Layer must specify input layers");
int n = 1;
int i;
for(i = 0; i < len; ++i){
if (l[i] == ',') ++n;
}
int *layers = calloc(n, sizeof(int));
int *sizes = calloc(n, sizeof(int));
for(i = 0; i < n; ++i){
int index = atoi(l);
l = strchr(l, ',')+1;
if(index < 0) index = params.index + index;
layers[i] = index;
sizes[i] = net.layers[index].outputs;
}
int batch = params.batch;
route_layer layer = make_route_layer(batch, n, layers, sizes);
convolutional_layer first = net.layers[layers[0]];
layer.out_w = first.out_w;
layer.out_h = first.out_h;
layer.out_c = first.out_c;
for(i = 1; i < n; ++i){
int index = layers[i];
convolutional_layer next = net.layers[index];
if(next.out_w == first.out_w && next.out_h == first.out_h){
layer.out_c += next.out_c;
}else{
layer.out_h = layer.out_w = layer.out_c = 0;
}
}
return layer;
}
upsample
顧名思義,這個layer是用來做上取樣的,只有stride和scale兩個引數,程式碼如下
layer parse_upsample(list *options, size_params params, network net)
{
int stride = option_find_int(options, "stride", 2);
layer l = make_upsample_layer(params.batch, params.w, params.h, params.c, stride);
l.scale = option_find_float_quiet(options, "scale", 1);
return l;
}