darknet原始碼學習 (1) :yolov3 推理過程
最近專案中會頻繁用到yolov3這個目標檢測演算法框架,由於其在速度和精度尤其是小物體檢測的能力上都比較突出所以目前應用面很廣泛,在應用yolov3的過程中經常會遇到一些演算法上的疑點,由於之前沒有好好學習過darknet這個輕量級DL演算法框架所以決定從yolov3入手理清一些darknet以及yolov3的概念,查漏補缺並糾正之前可能錯誤的理解。
在darknet中跑yolov3的準備工作
git clone https://github.com/pjreddie/darknet
cd darknet && make # 編譯darknet,如果需要使用GPU和opencv set GPU=1 CUDNN=1 OPENCV=1
mkdir model && cd model # 建立model資料夾放置darknet模型
wget https://pjreddie.com/media/files/yolov3.weights # 下載yolov3在coco資料上的模型
yolov3檢測
./darknet detector test cfg/coco.data cfg/yolov3.cfg model/yolov3.weights data/dog.jpg # 載入yolov3配置檔案和模型引數進行檢測
# yolov3 log 從36層擷取:0-74層一共53個conv layer其餘都是res layer即shortcut操作,75-105層為yolov3的特徵互動層分為三種尺度
layer filters size input output
36 res 33 52 x 52 x 256 -> 52 x 52 x 256
37 conv 512 3 x 3 / 2 52 x 52 x 256 -> 26 x 26 x 512 1.595 BFLOPs
38 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
39 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
40 res 37 26 x 26 x 512 -> 26 x 26 x 512
41 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
42 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
43 res 40 26 x 26 x 512 -> 26 x 26 x 512
44 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
45 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
46 res 43 26 x 26 x 512 -> 26 x 26 x 512
47 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
48 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
49 res 46 26 x 26 x 512 -> 26 x 26 x 512
50 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
51 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
52 res 49 26 x 26 x 512 -> 26 x 26 x 512
53 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
54 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
55 res 52 26 x 26 x 512 -> 26 x 26 x 512
56 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
57 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
58 res 55 26 x 26 x 512 -> 26 x 26 x 512
59 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
60 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
61 res 58 26 x 26 x 512 -> 26 x 26 x 512
62 conv 1024 3 x 3 / 2 26 x 26 x 512 -> 13 x 13 x1024 1.595 BFLOPs
63 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
64 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
65 res 62 13 x 13 x1024 -> 13 x 13 x1024
66 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
67 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
68 res 65 13 x 13 x1024 -> 13 x 13 x1024
69 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
70 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
71 res 68 13 x 13 x1024 -> 13 x 13 x1024
72 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
73 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
74 res 71 13 x 13 x1024 -> 13 x 13 x1024
75 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
76 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
77 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
78 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
79 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 0.177 BFLOPs
80 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 1.595 BFLOPs
81 conv 255 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 255 0.088 BFLOPs
82 yolo # small尺寸的特徵圖 13*13*(3*(5+80))
83 route 79
84 conv 256 1 x 1 / 1 13 x 13 x 512 -> 13 x 13 x 256 0.044 BFLOPs
85 upsample 2x 13 x 13 x 256 -> 26 x 26 x 256 # 對當前特徵層進行上取樣
86 route 85 61 # concat 85和61層 起到特徵合併的作用 類似FPN的思想
87 conv 256 1 x 1 / 1 26 x 26 x 768 -> 26 x 26 x 256 0.266 BFLOPs
88 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
89 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
90 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
91 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 0.177 BFLOPs
92 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 1.595 BFLOPs
93 conv 255 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 255 0.177 BFLOPs
94 yolo # middle尺寸的特徵圖 26*26*(3*(5+80))
95 route 91
96 conv 128 1 x 1 / 1 26 x 26 x 256 -> 26 x 26 x 128 0.044 BFLOPs
97 upsample 2x 26 x 26 x 128 -> 52 x 52 x 128 # 上取樣
98 route 97 36 # cocat 97和36層
99 conv 128 1 x 1 / 1 52 x 52 x 384 -> 52 x 52 x 128 0.266 BFLOPs
100 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 1.595 BFLOPs
101 conv 128 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 128 0.177 BFLOPs
102 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 1.595 BFLOPs
103 conv 128 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 128 0.177 BFLOPs
104 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 1.595 BFLOPs
105 conv 255 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 255 0.353 BFLOPs
106 yolo # large尺寸的特徵圖 52*52*(3*(5+80))
Loading weights from model/yolov3.weights...Done!
data/dog.jpg: Predicted in 0.024054 seconds. # 1080T inference time
# 影象中類別和置信度
dog: 99%
truck: 92%
bicycle: 99%
從darknet原始碼中理解yolov3 forward資料流動
- yolov3 detect入口
//example/darknet.c main函式
} else if (0 == strcmp(argv[1], "detector")){
run_detector(argc, argv);
//example/detector.c run_detector函式
if(0==strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, outfile, fullscreen); // 根據系統引數配置網路輸入檔案資訊thresh=0.5, hier_thresh=0.5(看程式碼不知道這個引數是否用到,後面再分析吧),outfile=null fullscreen=0
- yolov3 detect核心函式: test_detector
//example/detector.c test_detector函式
void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
{
/*將/data/coco.names裡面的label載入到names中*/
list *options = read_data_cfg(datacfg);
char *name_list = option_find_str(options, "names", "data/names.list");
char **names = get_labels(name_list);
image **alphabet = load_alphabet(); // 將/data/label的影象載入到 image陣列中,darknet中最後展現在result中的label都是以影象的形式展現出來的,而不是用put_text到影象中的
network *net = load_network(cfgfile, weightfile, 0); // 載入cfg和引數構建darknet network -> 稍後具體分析(1)
set_batch_network(net, 1); // 將 network裡面layer的batch_size都設定為1
srand(2222222);
double time;
char buff[256];
char *input = buff;
float nms=.45;
while(1){
if(filename){
strncpy(input, filename, 256);
} else {
printf("Enter Image Path: ");
fflush(stdout);
input = fgets(input, 256, stdin);
if(!input) return;
strtok(input, "\n");
}
/*yolov3輸入的影象預處理:
1.除以255歸一化
2.影象居中等比例縮放padding 127.5/255
3.BGR2RGB
4.NHWC2NCHW
影象處理部分邏輯比較簡單,需要注意的主要是等比例縮放,在不使用opencv的情況下使用C影象庫stb_image,用影象w h c以及資料data初始化一個image結構體*/
image im = load_image_color(input,0,0);
image sized = letterbox_image(im, net->w, net->h);
//image sized = resize_image(im, net->w, net->h);
//image sized2 = resize_max(im, net->w);
//image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
//resize_network(net, sized.w, sized.h);
layer l = net->layers[net->n-1]; // 獲取最後一個yolo layer, 主要是為了獲取類別資訊吧,因為三個yolo layer的input size都不相同
float *X = sized.data;
time=what_time_is_it_now();
network_predict(net, X); // 連續呼叫layer的forward做inference
printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
int nboxes = 0;
detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes); //呼叫yolo_layer對三個output tensor進行分析 -> 稍後具體分析(2)
//printf("%d\n", nboxes);
//if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
if (nms) do_nms_sort(dets, nboxes, l.classes, nms); // 對三個層級的bbox做nms, nms的演算法思想不難但是沒有好好看過實現,關於darknet的nms還是需要理解一下 -> 分析完yolo_layer後簡單分析一下nms的實現 (3)
draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes); // 把檢測到的目標展示出來, 第一次研究這個function的時候發現不是簡單的展示, 還做了一些小處理的 -> 稍後分析 (4)
free_detections(dets, nboxes);
if(outfile){
save_image(im, outfile);
}
else{
save_image(im, "predictions");
#ifdef OPENCV
make_window("predictions", 512, 512, 0);
show_image(im, "predictions", 0);
#endif
}
free_image(im);
free_image(sized);
if (filename) break;
}
}
- darknet網路模型的構建: yolov3模型cfg和引數載入
//src/network.c load_network函式
network *load_network(char *cfg, char *weights, int clear)
{
network *net = parse_network_cfg(cfg); //將網路的cfg檔案引數化,即解析cfg配置檔案
if(weights && weights[0] != 0){
load_weights(net, weights); // 根據cfg構建的network按照layer的順序載入對一個的layer引數權重
}
if(clear) (*net->seen) = 0; // *net->seen 代表目前網路已經處理的影象數量 batch_num = net->batch * net->subdivisions 可以演算法網路已經處理的batch數量
return net;
}
//src/parser.c parse_network_cfg函式
network *parse_network_cfg(char *filename)
{
/*分析read_cfg: 個人理解darknet將cfg中每一個layer當做節點node其中val為section構建成一個連結串列list
其中涉及的數結構有:
typedef struct{
char *type; //存放 layer name
list *options; // 暫時不太清晰list成員的作用(存放layer的屬性欄位?)
}section;
typedef struct node{
void *val; // 存放當前section
struct node *next;
struct node *prev;
} node;
typedef struct list{
int size; // 連結串列節點個數
node *front;
node *back;
} list;
*/
list *sections = read_cfg(filename);
node *n = sections->front;
if(!n) error("Config file has no sections");
network *net = make_network(sections->size - 1); // 為構建網路分類記憶體 calloc (malloc並且初始化為0)
net->gpu_index = gpu_index;
size_params params;
section *s = (section *)n->val;
list *options = s->options;
if(!is_network(s)) error("First section must be [net] or [network]");
parse_net_options(options, net); // 初始化網路全域性引數
params.h = net->h;
params.w = net->w;
params.c = net->c;
params.inputs = net->inputs;
params.batch = net->batch;
params.time_steps = net->time_steps;
params.net = net;
size_t workspace_size = 0;
n = n->next;
int count = 0;
free_section(s);
fprintf(stderr, "layer filters size input output\n");
while(n){ // 初始化每一層的引數,這部分內容比較多,就不在yolov3這個模組展開了,如果有必要的話會單獨對網路引數和layer引數的載入進行學習和分析
params.index = count;
fprintf(stderr, "%5d ", count);
s = (section *)n->val;
options = s->options;
layer l = {0};
LAYER_TYPE lt = string_to_layer_type(s->type);
if(lt == CONVOLUTIONAL){
l = parse_convolutional(options, params);
}else if(lt == DECONVOLUTIONAL){
l = parse_deconvolutional(options, params);
}else if(lt == LOCAL){
l = parse_local(options, params);
}else if(lt == ACTIVE){
l = parse_activation(options, params);
}else if(lt == LOGXENT){
l = parse_logistic(options, params);
}else if(lt == L2NORM){
l = parse_l2norm(options, params);
}else if(lt == RNN){
l = parse_rnn(options, params);
}else if(lt == GRU){
l = parse_gru(options, params);
}else if (lt == LSTM) {
l = parse_lstm(options, params);
}else if(lt == CRNN){
l = parse_crnn(options, params);
}else if(lt == CONNECTED){
l = parse_connected(options, params);
}else if(lt == CROP){
l = parse_crop(options, params);
}else if(lt == COST){
l = parse_cost(options, params);
}else if(lt == REGION){
l = parse_region(options, params);
}else if(lt == YOLO){ // yolov3獨有的yolo_layer
l = parse_yolo(options, params);
}else if(lt == ISEG){
l = parse_iseg(options, params);
}else if(lt == DETECTION){
l = parse_detection(options, params);
}else if(lt == SOFTMAX){
l = parse_softmax(options, params);
net->hierarchy = l.softmax_tree;
}else if(lt == NORMALIZATION){
l = parse_normalization(options, params);
}else if(lt == BATCHNORM){
l = parse_batchnorm(options, params);
}else if(lt == MAXPOOL){
l = parse_maxpool(options, params);
}else if(lt == REORG){
l = parse_reorg(options, params);
}else if(lt == AVGPOOL){
l = parse_avgpool(options, params);
}else if(lt == ROUTE){
l = parse_route(options, params, net);
}else if(lt == UPSAMPLE){
l = parse_upsample(options, params, net);
}else if(lt == SHORTCUT){
l = parse_shortcut(options, params, net);
}else if(lt == DROPOUT){
l = parse_dropout(options, params);
l.output = net->layers[count-1].output;
l.delta = net->layers[count-1].delta;
#ifdef GPU
l.output_gpu = net->layers[count-1].output_gpu;
l.delta_gpu = net->layers[count-1].delta_gpu;
#endif
}else{
fprintf(stderr, "Type not recognized: %s\n", s->type);
}
l.clip = net->clip;
l.truth = option_find_int_quiet(options, "truth", 0);
l.onlyforward = option_find_int_quiet(options, "onlyforward", 0);
l.stopbackward = option_find_int_quiet(options, "stopbackward", 0);
l.dontsave = option_find_int_quiet(options, "dontsave", 0);
l.dontload = option_find_int_quiet(options, "dontload", 0);
l.numload = option_find_int_quiet(options, "numload", 0);
l.dontloadscales = option_find_int_quiet(options, "dontloadscales", 0);
l.learning_rate_scale = option_find_float_quiet(options, "learning_rate", 1);
l.smooth = option_find_float_quiet(options, "smooth", 0);
option_unused(options);
net->layers[count] = l;
if (l.workspace_size > workspace_size) workspace_size = l.workspace_size;
free_section(s);
n = n->next;
++count;
if(n){ // 這部分將連線的兩個層之間的輸入輸出shape統一
params.h = l.out_h;
params.w = l.out_w;
params.c = l.out_c;
params.inputs = l.outputs;
}
}
free_list(sections);
layer out = get_network_output_layer(net); //返回網路的輸出layer
net->outputs = out.outputs;
net
相關推薦
darknet原始碼學習 (1) :yolov3 推理過程
最近專案中會頻繁用到yolov3這個目標檢測演算法框架,由於其在速度和精度尤其是小物體檢測的能力上都比較突出所以目前應用面很廣泛,在應用yolov3的過程中經常會遇到一些演算法上的疑點,由於之前沒有好好學習過darknet這個輕量級DL演算法框架所以決定從yolov3入手理清一些
Yolo系列學習1-Yolov3訓練福彩快三平臺出租自己的數據
平臺 sprint rectangle 修改文件 ted issues printf res idt 目的:福彩快三平臺出租 haozbbs.com Q1446595067
實現利用yolov3訓練自己的數據集(voc格式)
方法:
1)構建VOC數據集
將你手中的數據
struts1原始碼學習1
ActionServlet初始化方法init
public class ActionServlet extends HttpServlet
//servlet初始化
public void init() throws ServletException {
final
Yolo系列學習1-Yolov3訓練自己的資料
前提:
目的:
實現利用yolov3訓練自己的資料集(voc格式)
方法:
1)構建VOC資料集
將你手中的資料集的標註txt修改成voc格式的txt,voc格式如下:
000002.jpg car 44 28 132 121
000003.jpg
spring原始碼學習(1) --BeanDefinition學習
BeanDefinition
BeanDefinition作為定義springBean檔案中bean的介面,可以說是bean的抽象資料結構,它包括屬性引數,構造器引數,以及其他具體的引數。
<bean id="person" class="com.de
Redis原始碼學習(1):adlist
redis中的adlist是一個簡單的無環雙向連結串列,主要邏輯在這兩個檔案中實現:
adlist.h
adlist.c
結構也很簡單,資料結構中最基本的結構。
新增節點程式碼:
if (after) {
node->prev =
結合redis設計與實現的redis原始碼學習-1-記憶體分配(zmalloc)
在進入公司後的第一個任務就是使用redis的快取功能實現伺服器的雲託管功能,在瞭解了大致需求後,依靠之前對redis的瞭解封裝了常用的redis命令,並使用單例的連線池來維護與redis的連線,使用連線池來獲取redis的連線物件,依靠這些功能基本可以實現要求的
TensorFlow原始碼學習--1 Session API reference
學習TensorFlow原始碼,先把API文件扒出來研究一下整體結構: 一下是文件內容的整理,簡單翻譯一下
原文地址:http://www.tcvpr.com/archives/181
TensorFlow C++ Session API reference
linux TCP傳送原始碼學習(1)--tcp_sendmsg
一、tcp_sendmsg()函式分析:
int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
{
Darknet 原始碼學習和非常詳細的中文註釋(絕對經典)
https://pjreddie.com/darknet/
用於人臉表情端到端系統的重訓練
附錄1:
darknet深度學習框架原始碼分析:詳細中文註釋,涵蓋框架原理與實現語法分析
https://github.com/hgpvision/da
HBase原始碼學習 客戶端scan過程
申明:以下程式碼均來自HBase-1.0.1.1
HTable tb = new HTable(conf,"test");
Scan scan = new Scan();
scan.addColumn(("colfam").getBytes(),("col
Asp.NetCore原始碼學習[1-2]:配置[Option]
Asp.NetCore原始碼學習[1-2]:配置[Option]
在上一篇文章中,我們知道了可以通過IConfiguration訪問到注入的ConfigurationRoot,但是這樣只能通過索引器IConfiguration["配置名"]訪問配置。這篇文章將一下如何將IConfiguration對映到
Hive原始碼分析(1)——HiveServer2啟動過程
1.想了解HiveServer2的啟動過程,則需要找到啟動HiveServer2的入口,hive服務的啟動命令為hive --service HiveServer2,通過分析$HIVE_HOME/bin下hive指令碼可知,執行hive --service HiveServer2後正真呼叫的是$HIVE_HO
spring原始碼學習之路---深度分析IOC容器初始化過程(三)
分析FileSystemXmlApplicationContext的建構函式,到底都做了什麼,導致IOC容器初始化成功。
public FileSystemXmlApplicationContext(String[] configLocations, boolean ref
spring原始碼學習(5.1.0版本)——Bean的初始化(中)
目錄
前言
createBean
有自定義TargetSource代理類的生成
resolveBeforeInstantiation
applyBeanPostProcessorsBeforeInstantiation
postProcessBeforeIn
spring原始碼學習(5.1.0版本)——Bean的初始化(上)
目錄
前言
源頭
preInstantiateSingletons方法
getBean(String beanName)
doGetBean
getObjectForBeanInstance
getObjectFromFactoryBean
doGe
Hadoop-0.20.2原始碼學習(1)——原始碼初窺
參考:
JeffreyZhou的部落格園
《Hadoop權威指南》第四版
0. 為什麼選擇0.20.2版本
前面學習搭建的Hadoop版本是2.7.6,可是這裡為什麼要學習0.20.2這麼老的版本呢?
區塊鏈學習1.5-比特幣原始碼的學習-比特幣網路
本篇文章有部分內容直接出自《Mastering Bitcoin》
比特幣網路層主要是由 P2P網路,傳播機制,驗證機制三部分組成。
白皮書關於network的內容回顧一下:
The steps to run the network are as follows:
區塊鏈學習1.4-比特幣原始碼的學習-比特幣基礎
1.3就已經提到區塊鏈的四大技術組合,我認為還是有必要了解背後的原理的。下面做一個簡要的介紹。
一. 區塊鏈資料結構和數字簽名演算法
1.資料結構Merkel樹
說到merkle樹就不得不談到交易,merkle樹就是用於存放交易的 資料結構。如下圖:
它是一個雜湊二叉樹,雜湊的
View的工作原理之Measure過程原始碼學習(四)
上一篇文章,學習了ViewGroup和View的measure流程。文章最後講到,本文將會學習ViewGroup和普通View的onMeasure方法的工作。
因為ViewGroup是