• Darknet卷基层浅层特征可视化教程


    Darknet浅层可视化教程

    说明

    针对YOLO官方提供的c语言版的darknet进行了修改,添加了一些函数,进行可视化处理。

    建议使用visual studio code进行代码的跟踪和调试。

    可视化内容是针对一下命令,对一张图片进行可视化:

    ./darknet detector test cfg/voc.data data/yolov3-voc.cfg backup/yolov3-voc_40000.weights
    

    处理步骤

    • 入口: darknet.c的main文件,找到以下声明:
    } else if (0 == strcmp(argv[1], "detector")){
            run_detector(argc, argv);
    
    • 进入run_detector函数,在detector.c文件中找到以下代码:
    if(0==strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, outfile, fullscreen);
        else if(0==strcmp(argv[2], "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear);
        else if(0==strcmp(argv[2], "valid")) validate_detector(datacfg, cfg, weights, outfile);
        else if(0==strcmp(argv[2], "valid2")) validate_detector_flip(datacfg, cfg, weights, outfile);
        else if(0==strcmp(argv[2], "recall")) validate_detector_recall(datacfg, cfg, weights);
        else if(0==strcmp(argv[2], "demo")) {
    
    • 找到第二个参数“test”对应的函数: test_detector,进入该函数进行修改:
    while(1){
            if(filename){
                strncpy(input, filename, 256);
                image im = load_image_color(input,0,0);
                image sized = letterbox_image(im, net->w, net->h);
                layer l = net->layers[net->n-1]; 
     
                float *X = sized.data;
                time=what_time_is_it_now();
                network_predict(net, X);
                printf("%s: Predicted in %f seconds.
    ", 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);
    
    • 很明显,network_predict函数就是用来让图片在网络中forward_gpu一下,然后得到结果,所以进入该函数:
    float *network_predict(network *net, float *input)
    {
        network orig = *net;
        net->input = input;
        net->truth = 0;
        net->train = 0;
        net->delta = 0;
        forward_network(net);
        float *out = net->output;
        *net = orig;
        return out;
    }
    
    • 再继续找核心函数forward_network(net)
    void forward_network(network *netp)
    {
    #ifdef GPU
        if(netp->gpu_index >= 0){
            forward_network_gpu(netp);   
            return;
        }
    #endif
        network net = *netp;
        printf("haha, net layer number: %d
    ",net.n);
        int i;
        for(i = 0; i < net.n; ++i){
            //image imi = get_network_image(netp);
            //save_image(imi,"thiisisatest");        
            net.index = i;
            layer l = net.layers[i];
            if(l.delta){
                fill_cpu(l.outputs * l.batch, 0, l.delta, 1);
            }
            l.forward(l, net);
            net.input = l.output;
            if(l.truth) {
                net.truth = l.output;
            }
        }
        calc_network_cost(netp);
    }
    
    • 由于本项目是在有GPU支持的情况下,所以会执行#ifdef和#endif之间的内容,继续找forward_network_gpu()函数。
    void forward_network_gpu(network *netp)
    {
        network net = *netp;
        cuda_set_device(net.gpu_index);
        cuda_push_array(net.input_gpu, net.input, net.inputs*net.batch);
        if(net.truth){
            cuda_push_array(net.truth_gpu, net.truth, net.truths*net.batch);
        }
    
        int i;
        for(i = 0; i < net.n; ++i){
            net.index = i;
            layer l = net.layers[i];
            if(l.delta_gpu){
                fill_gpu(l.outputs * l.batch, 0, l.delta_gpu, 1);
            }
            l.forward_gpu(l, net);
            net.input_gpu = l.output_gpu;
            net.input = l.output;
    
            if(l.truth) {
                net.truth_gpu = l.output_gpu;
                net.truth = l.output;
            }
            //这个函数是新加的,用来得到图片保存图片
            image tmp = get_network_cow_image_layer(&net,i);
        }
        pull_network_output(netp);
        calc_network_cost(netp);
    }
    
    • 该函数在network.c文件中声明,需要在darknet.h中提前声明该函数:
    image get_network_cow_image_layer(network *net, int i);
    

    具体内容如下:

    image get_network_cow_image_layer(network *net, int i)
    {
        layer l = net->layers[i];
    
    #ifdef GPU
        cuda_pull_array(l.output_gpu, l.output, l.outputs);
    #endif
        printf("w:%d,h:%d,c:%d
    ",l.out_w,l.out_h,l.out_c);
        if (l.out_w && l.out_h && l.out_c){
            return float_to_cow_image(l.out_w,l.out_h,l.out_c,l.output,i);
        }
        image def = {0};
        return def;
    }
    
    • 可以发现,float_to_cow_image也是新加的函数,也需要加入到darknet.h中去:
    image get_network_cow_image_layer(network *net, int i);
    

    该函数具体内容如下(参考get_network_image_layer进行修改,添加i是为了识别这是第几层的可视化,用于保存文件):

    /*****************************************************
    *func: 主要是为了将output结果能够映射到0-255区间(初始化,使用sigmoid函数进行归一化,),便于进行可视化操作。 将所有维度合成到一个维度,然后取平均,×255,便于查看
    *****************************************************/
    image float_to_cow_image(int w, int h, int c, float *data,int ai)
    {
        char tp[1000];
        //保存文件到特定文件夹(feature_txt)中并根据ai大小命名
        sprintf(tp,"/home/learner/darknet/feature_txt/out_%d.txt",ai);
        FILE * stream = fopen(tp,"w+");
        
        //创建一个1维的空图片
        image out = make_empty_image(w,h,1);    
        int i, j;
        
        //设计一个数组保存该图片内容
        float * tempData = calloc(w*h,sizeof(float));
    	//初始化
        for(i = 0 ; i < w*h ; i++)
        {
            tempData[i] = 0;
        }
    
        //归一化,sigmoid
        for(i = 0 ; i < w*h*c ; i++)
        {
            data[i] = 1.0/(1+exp(-1*data[i]));
    
        }
    
        //合并通道
        for(i = 0 ; i < w*h ; i++)
        {
            for(j = 0 ; j < c ; j++)
            {
                tempData[i] += data[i+j*w*h];
            }
        }
        
        //保存到文件
        for(i = 0 ; i < w*h; i++)
        {
            tempData[i] /= c;
            tempData[i] *= 255;
            fprintf(stream," %f",tempData[i]);
            if((i+1)%w==0)
                fprintf(stream,"
    ");
        }
       
    	//关闭文件流
        fclose(stream);
        out.data = tempData;
        return out;
    }
    

    重新make,运行命令,会在指定目录下得到txt文件,之后的操作就是需要将txt文件可视化为图片。

    使用python可视化txt文件

    使用python读取图片有一个好处,就是可以将灰度图转化为热力图,这样更容易观察,否则会认为生成了一系列噪音点。

    具体代码如下:(需要matplotlib,PIL, numpy库)

    #!/home/learner/miniconda3/bin/python
    # -*- coding: utf-8 -*-
    """
    Spyder Editor
    
    This is a temporary script file.
    """
    import os
    import matplotlib.pyplot as plt
    import numpy as np
    from PIL import Image
    
    def process(filepath,outpath):
        for fileName in os.listdir(filepath):
            print(fileName)
            print(filepath+"/"+fileName)
            a=np.loadtxt(filepath+"/"+fileName)        
            im = Image.fromarray(np.uint8(a))
            #tmp_img = plt.imshow(im)
            #tmp_img.set_cmap('hsv')
            #plt.show()
            print(im.size)
            #im.set_cmap('hot')
            
            #plt.figure(figsize=(15,15))
            plt.title(fileName)
            plt.imshow(im),plt.axis('off')
            im.save(outpath+"/"+fileName[:-4]+".jpg")
            #plt.savefig(outpath+"/"+fileName[:-4]+".jpg",bbox_inches="tight",transparent=True,pad_inches=0)
          
          
    if __name__ == "__main__":
        outpath = "/home/learner/darknet/feature_pic"
        filepath="/home/learner/darknet/feature_txt"
        process(filepath,outpath)
    
  • 相关阅读:
    QuantLib 金融计算
    【翻译】《理解收益率曲线》系列
    QuantLib 金融计算——C++ 代码改写成 Python 程序的一些经验
    可转债研报阅读笔记
    SWIG 3 中文手册——13. 约定
    SWIG 3 中文手册——12. 自定义功能
    SWIG 3 中文手册——11. 类型映射
    【翻译】Quant 应该怎样写博客?
    QuantLib 金融计算——案例之普通利率互换分析(2)
    仿射期限结构模型:理论与实现——实现部分
  • 原文地址:https://www.cnblogs.com/pprp/p/10146355.html
Copyright © 2020-2023  润新知