Darknet卷基層淺層特徵可視化教程

Darknet淺層可視化教程

說明

針對YOLO官方提供的c語言版的darknet進行了修改,添加了一些函數,進行可視化處理。數組

建議使用visual studio code進行代碼的跟蹤和調試。網絡

可視化內容是針對一下命令,對一張圖片進行可視化:函數

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

處理步驟

  • 入口: 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.\n", 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\n",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);

具體內容以下:ui

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\n",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是爲了識別這是第幾層的可視化,用於保存文件):spa

/*****************************************************
*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,"\n");
    }
   
    //關閉文件流
    fclose(stream);
    out.data = tempData;
    return out;
}

從新make,運行命令,會在指定目錄下獲得txt文件,以後的操做就是須要將txt文件可視化爲圖片。設計

使用python可視化txt文件

使用python讀取圖片有一個好處,就是能夠將灰度圖轉化爲熱力圖,這樣更容易觀察,不然會認爲生成了一系列噪音點。調試

具體代碼以下:(須要matplotlib,PIL, numpy庫)code

#!/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)
相關文章
相關標籤/搜索