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 <function>\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使用的是卷积神经网络,想要进一步理解代码(根据参数设置卷积层)需要结合卷积神经网络模型知识。