最近开始学习yolo,以博客形式记录下自己的学习路程,关于安装,背景等都不介绍了,直接开始读源码:
1.首先在darknet.c文件中找到main函数,看到对参数的解释,如果是yolo,执行run_yolo函数:
int main(int argc, char **argv)
{
//test_resize("data/bad.jpg");
//test_box();
//test_convolutional_layer();
if(argc < 2){
fprintf(stderr, "usage: %s \n" , argv[0]);
return 0;
}
gpu_index = find_int_arg(argc, argv, "-i", 0);
if(find_arg(argc, argv, "-nogpu")) {
gpu_index = -1;
}
#ifndef GPU
gpu_index = -1;
#else
if(gpu_index >= 0){
cuda_set_device(gpu_index);
}
#endif
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")){
run_detector(argc, argv);
} else if (0 == strcmp(argv[1], "detect")){
float thresh = find_float_arg(argc, argv, "-thresh", .24);
char *filename = (argc > 4) ? argv[4]: 0;
test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5);
} else if (0 == strcmp(argv[1], "cifar")){
run_cifar(argc, argv);
2。转到run_yolo中去,根据第二个参数来进入不同的函数,先进入test中看一看test_yolo函数:
void test_yolo(char *cfgfile, char *weightfile, char *filename, float thresh)
{
image **alphabet = load_alphabet();
network net = parse_network_cfg(cfgfile);
if(weightfile){
load_weights(&net, weightfile);
}
detection_layer l = net.layers[net.n-1];
set_batch_network(&net, 1);
srand(2222222);
clock_t time;
char buff[256];
char *input = buff;
int j;
float nms=.4;
box *boxes = calloc(l.side*l.side*l.n, sizeof(box));
float **probs = calloc(l.side*l.side*l.n, sizeof(float *));
for(j = 0; j < l.side*l.side*l.n; ++j) probs[j] = calloc(l.classes, sizeof(float *));
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");
}
image im = load_image_color(input,0,0);
image sized = resize_image(im, net.w, net.h);
float *X = sized.data;
time=clock();
network_predict(net, X);
printf("%s: Predicted in %f seconds.\n", input, sec(clock()-time));
get_detection_boxes(l, 1, 1, thresh, probs, boxes, 0);
if (nms) do_nms_sort(boxes, probs, l.side*l.side*l.n, l.classes, nms);
//draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, voc_names, alphabet, 20);
draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, voc_names, alphabet, 20);
save_image(im, "predictions");
show_image(im, "predictions");
free_image(im);
free_image(sized);
#ifdef OPENCV
cvWaitKey(0);
cvDestroyAllWindows();
#endif
if (filename) break;
}
}
第一行是一个加载图片的函数,先不管。第二个函数,从名字来看是一个根据cfg文件构建网络的过程,返回是network的变量,那么network这个struct是什么情况呢?看它的申明:
typedef struct network{
float *workspace;
int n;//网络层数
int batch;//批处理样本个数,结合subdivision使用
int *seen;//已经处理过的样本数
float epoch;
int subdivisions;
float momentum;
float decay;
layer *layers;//每一层
int outputs;
float *output;
learning_rate_policy policy;//学习率的策略
float learning_rate;//学习效率
float gamma;
float scale;
float power;
int time_steps;
int step;
int max_batches;
float *scales;
int *steps;
int num_steps;
int burn_in;
int adam;
float B1;
float B2;
float eps;
int inputs;
int h, w, c;
int max_crop;
int min_crop;
float angle;
float aspect;
float exposure;
float saturation;
float hue;
int gpu_index;
tree *hierarchy;
(很多变量的意义还并不能完全明白,先在此处挖个坑。)
进入parser.c文件中的parse_network_cfg函数:
第一个方法是read_cfg,首先我们看一下cfg文件内容是什么样:
会看到cfg文件是一段一段的,开始第一段是net,后面紧跟着数行的参数。代码:首先会设置一个list变量(基本的链表结构),然后申明一个section:
typedef struct{
char *type;
list *options;
}section;
一个section是由一个字符串和一个链表组成,这就对应cfg文件一段一段的数据。一行行读取数据,strip函数是将读到的一行字符串中去掉空格换行等内容。就是讲cfg内容读取到一个list中,list的每一个元素又是又一个类型说明字符串和一个list表示的,这里的list的元素是一个个kvp结构(就是network中一些变量和其值,还有一个used变量表示是否使用过)。cfg中一段表示的意义指的就是网络中的一层,含有多个属性(kvp)而已。注意cfg文件第一段一定是net层,会进行判is_network().
之后会根据【net】的list(地一层的所有属性们)对network进行设置,注意到batch值等于batch/subdivisions的值。net段应该就是声明整个网络结构中的所有用到的属性们。
3、之后就是不同的层参数设置,如果是卷积层(convolutional),进入parse_convolutional()函数,
之后就是整个网络结构的知识了。需要知道的是yolo使用的是卷积神经网络,想要进一步理解代码(根据参数设置卷积层)需要结合卷积神经网络模型知识。