写点什么

目标检测 - 框架之 darknet- 数据读取

用户头像
Dreamer
关注
发布于: 2020 年 11 月 13 日
目标检测-框架之darknet-数据读取

darknet-1之数据读取




之前一直在用darknet的框架训练yolo,但是对于具体的框架内不的机制还是不熟,最近下定决定深入了解这个框架的内部机制,这是参考好了很多博主的博客,感谢他们的帮助。希望可以和各位同仁一起学习,共同进步。



本次的源码阅读参考的https://github.com/AlexeyAB/darknet,俗称A版darknet.



author: dreamer



date: 2020-11-11




首先需要明确的一点是因为darknet是用C, CUDA实现的,因此其中对于复杂层,网络,函数的实现都是经过的结构体,这里先重点关注下面这几个:

//node ,链表中节点的基本单元

typedef struct node{

void *val;

struct node *next;

struct node *prev;

} node;

//双向链接,记录头节点,尾节点,和链表的长度,会存储网络的所有参数

typedef struct list{

int size;

node *front;

node *back;

} list;

首先找到入口函数 darknet.c 中的main()



if (0 == strcmp(argv[1], "average")){

average(argc, argv);

} else if (0 == strcmp(argv[1], "yolo")){

run_yolo(argc, argv);

} else if (0 == strcmp(argv[1], "voxel")){

run_voxel(argc, argv);

} else if (0 == strcmp(argv[1], "super")){

run_super(argc, argv);

} else if (0 == strcmp(argv[1], "detector")){

// 关注主要部分, 检测代码

//======================

//训练的部分基本包含了整个框架

//汇总所有的功能,因此我们跟着一种大佬进来学习学习。

// author: dreamer

//date: 2020-11-11

//=======================

run_detector(argc, argv);

} else if (0 == strcmp(argv[1], "detect")){

float thresh = findfloatarg(argc, argv, "-thresh", .24);

int extoutput = findarg(argc, argv, "-ext_output");

char *filename = (argc > 4) ? argv[4]: 0;

testdetector("cfg/coco.data", argv[2], argv[3], filename, thresh, 0.5, 0, extoutput, 0, NULL, 0, 0);

} else if (0 == strcmp(argv[1], "cifar"))

...

接下来进入run_detector(),前面的部分都是对参数的提取,重点在下面



if (0 == strcmp(argv[2], "test")) testdetector(datacfg, cfg, weights, filename, thresh, hierthresh, dontshow, extoutput, savelabels, outfile, letterbox, benchmark_layers);

//=======================

// train arg,会调用下面这个函数

//=======================

else if (0 == strcmp(argv[2], "train")) traindetector(datacfg, cfg, weights, gpus, ngpus, clear, dontshow, calcmap, mjpegport, showimgs, benchmarklayers, chart_path);

else if (0 == strcmp(argv[2], "valid")) validate_detector(datacfg, cfg, weights, outfile);

else if (0 == strcmp(argv[2], "recall")) validatedetectorrecall(datacfg, cfg, weights);

else if (0 == strcmp(argv[2], "map")) validatedetectormap(datacfg, cfg, weights, thresh, iouthresh, mappoints, letter_box, NULL);

else if (0 == strcmp(argv[2], "calcanchors")) calcanchors(datacfg, numofclusters, width, height, show);

else if (0 == strcmp(argv[2], "draw")) {

int it_num = 100;

drawobject(datacfg, cfg, weights, filename, thresh, dontshow, itnum, letterbox, benchmark_layers);

}

else if (0 == strcmp(argv[2], "demo")) {

list *options = readdatacfg(datacfg);

int classes = optionfindint(options, "classes", 20);

char *namelist = optionfind_str(options, "names", "data/names.list");

char **names = getlabels(namelist);

if (filename)

if (strlen(filename) > 0)

if (filename[strlen(filename) - 1] == 0x0d) filename[strlen(filename) - 1] = 0;

demo(cfg, weights, thresh, hierthresh, camindex, filename, names, classes, avgframes, frameskip, prefix, outfilename,

mjpegport, dontdrawbbox, jsonport, dontshow, extoutput, letterbox, timelimitsec, httpposthost, benchmark, benchmark_layers);



freelistcontents_kvp(options);

free_list(options);

}

else printf(" There isn't such command: %s", argv[2]);

...



,接着进入train_detector()



//这里进入配置文件的读取

list *options = readdatacfg(datacfg);

//====================================

//readdatacfg的定义, 位于option_list.c

list read_data_cfg(char filename)

{

FILE *file = fopen(filename, "r");

if(file == 0) file_error(filename);

char *line;

int nu = 0;

list *options = make_list(); // 初始化链表,后面每次读一行参数的时候,会把参数挂上这个总的链表上

while((line=fgetl(file)) != 0){

++nu;

strip(line);

switch(line[0]){

case '\0':

case '#':

case ';':

free(line);

break;

default:

// read_option 实现具体如何将读到的哪一行参数解析出来,并且加入链表的操作。

if(!read_option(line, options)){

fprintf(stderr, "Config file error line %d, could parse: %s\n", nu, line);

free(line);

}

break;

}

}

fclose(file);

return options;

}

//readoption() 位于optionlist.c

//分离出参数的key和value,然后进一步调用optioninsert()挂到options,也就是readdata_cfg()中最开始创建的那个总的参数list里面

int read_option(char s, list options)

{

size_t i;

size_t len = strlen(s);

char *val = 0;

for(i = 0; i < len; ++i){

if(s[i] == '='){

s[i] = '\0';

val = s+i+1;

break;

}

}

if(i == len-1) return 0;

char *key = s;

option_insert(options, key, val);

return 1;

}

// option_insert() ,创建一个kvp

/*

typedef struct{

char *key;

char *val;

int used;

} kvp;

void option_insert(list l, char key, char *val)

{

kvp p = (kvp)xmalloc(sizeof(kvp));

p->key = key;

p->val = val;

p->used = 0;

list_insert(l, p);

}

以上就完成了数据配置文件的读取。



总结一下,对于数据文件的配置信息的读取,是通过先创建一个空的list, 然后每次读取一行配置信息出,通过分离出的key 和value,组建一个kvp,顺序的挂上这个创建的list,在需要使用访问文件信息的时候对这个list 读取即可完成。



用户头像

Dreamer

关注

一个不想做搜索的NLPer不是一个好的CVer 2019.12.18 加入

还未添加个人简介

评论

发布
暂无评论
目标检测-框架之darknet-数据读取