yolo源码学习(一)

最近开始学习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函数:
yolo源码学习(一)_第1张图片
第一个方法是read_cfg,首先我们看一下cfg文件内容是什么样:
yolo源码学习(一)_第2张图片
会看到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使用的是卷积神经网络,想要进一步理解代码(根据参数设置卷积层)需要结合卷积神经网络模型知识。

你可能感兴趣的:(python学习)