darknet整體框架

darknet是使用C和CUDA編寫的開源的神經網絡框架,它快速且使用簡單,之前在海康做caffe方面的工作,本想研究caffe的源代碼,但是被導師推薦閱讀darknet源代碼加深對深度學習的理解而且還能鞏固C語言,由此記錄一下我的darknet源碼閱讀之路。

一、darknet安裝

本記錄主要是閱讀源碼,所以opencv gpu我就先不弄了,darknet安裝非常簡單,直接源碼安裝,在github上下載源代碼:

https://github.com/pjreddie/darknet

下載過後解壓得到darknet-master文件夾,裏面主要包含幾個重要的文件夾和makefile和幾個license,cfg文件夾存放的是各種常見網絡結構的配置文件如yolo、rcnn等,如果想要定義自己的網絡結構需要編寫自己的cfg文件,這個感覺類似caffe的prototxt。data文件夾下是各種數據集如接下來演示會用到的dog圖片。examples文件夾中存放的各種檢測算法的例子,如detector.c就是檢測的代碼,根據你輸入run_detector函數的參數是train還是test轉到其內部的train_detector或者test_detector,此文件夾中最重要的文件是darknet.c,具體細節之後會講到。include文件夾中只有一個文件darknet.h是darknet的頭文件裏面定義了很多要用到的結構,對於熟悉C語言結構體很有幫助。scripts文件夾中是幾個shell腳本看幾個文件的名字應該是用來獲取數據集的。src文件夾中是CNN庫的很多細節實現,這個文件夾中的代碼應該會花好長時間來研究,裏面有BN層的實現、卷積層的實現、正則化等等閱讀這部分代碼我覺得對於深度學習各個基礎知識的理解還是非常有幫助的。

下載好了源代碼是第一步,之後還要進行編譯,這部分很好做,只要cd進入darknet-master之後執行make,這樣就編譯好了,這是你會發現文件夾裏多出了obj、backup、results三個文件夾和libdarknet.a靜態庫、libdarknet.so動態庫。動態鏈接的基本思想簡單來說就是不對那些組成程序的目標文件進行鏈接,而是當程序運行時才進行鏈接,從而解決了靜態鏈接空間浪費的問題。obj文件夾下就是和所有目標文件。這樣darknet就非常簡單的安裝好了。

二、簡單的使用

darknet的使用也是很簡單,我們先在darknet官網上下載好已經訓練出的yolov3的權重,之後在終端運行

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

這個命令結合代碼非常好理解,首先可以看darknet.c的主函數中

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], "super")){
        run_super(argc, argv);
    } else if (0 == strcmp(argv[1], "lsd")){
        run_lsd(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", .5);
        char *filename = (argc > 4) ? argv[4]: 0;
        char *outfile = find_char_arg(argc, argv, "-out", 0);
        int fullscreen = find_arg(argc, argv, "-fullscreen");
        test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);

可以看出該程序是根據給定的argv來決定程序的走向,如本例argv[1]爲detect,也就是說程序會轉到detector.c中的test_dector函數中,也就是測試檢測,那麼args[2]、args[3]、args[4]都分明指代什麼呢,我們來看test_detector函數的形參

void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
對比來看args[2]是所用檢測網絡的配置文件,定義了網絡的結構,args[3]指的是測試要用到的網絡權重的配置文件,args[4]也就是filename這個指的是要測試的圖片,從main中的if分支可以看出filename可以不用制定,但即使你不指定程序會提醒你“Enter Image Path:”,還有一點“cfg/coco.data”是做什麼的?通過分析test_detector函數我認爲這是爲了得到coco數據集中label的列表,從而顯示filename檢測出來的物體的名稱,而這個名稱是根據label列表索引到的,當然這只是我目前沒有對源碼深入理解的猜想,如有不正確指出歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章