使用 YOLO 做些好玩的事情

源碼獲取與安裝

GitHub 上搜索 YOLO 可以找到很多平臺的包,如: Tensorflow, pyTorch 等等;本文使用 darknet 原因:方便把玩。請參考如下頁面安裝測試:

實測

自帶圖

dog等

其他任選

簡單場景

西安國際汽車展.png

西電花季開放日

中等複雜

盆栽(potted plant)都可以, 當然花瓶是沒有的
charms於2017年4月4日攝於青龍寺

複雜場景

注意下圖中的包和傘都能檢測出來:
人羣密集的櫻花祭

還有這個圖,不是偶然
人羣密集的櫻花祭

惡劣環境

下面的環境有點惡劣,不過還不錯,雖然漏了個車和路燈
xidianbeimen.png

失敗例子

哈哈,畫的畫果然還是不行,難道畫技太差,哈哈:

charms 原創畫作

訓練

樣本

標記樣本

  • 工具:Yolo_mark或者自寫,本人自己寫了個腳本
  • 格式:類標從0開始,沒有背景(與訓練與微調均是)

其它說明見以下各自部分。

預訓練

準備訓練樣本

darknet 這個

cifar訓練樣本示例

微調

準備訓練樣本

訓練樣本標籤文件信息如下:

<object-class> <x> <y> <width> <height>
<object-class> <x> <y> <width> <height>
...

對應於:

<類別標籤數字> <物體中心水平方向座標/寬度> <物體中心垂直方向座標/高度> <物體區域寬度> <物體區域高度>

如對於 VOC2012中的一幅飛機的圖像,對應的訓練樣本標籤信息如下:

0 0.578 0.474474474474 0.744 0.588588588589

其中,0 表示類別,0.578 0.474474474474 爲中心座標,0.744 0.588588588589 分別爲寬度和高度,如下圖所示:

訓練樣本標籤圖解

訓練配置

learning_rate=0.0001
max_batches = 3 # 訓練代數 epoches
policy=steps
steps=1,2,3 # 每訓練step,保存一次
scales=10,.1,.1

開始微調訓練

./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23 -gpus 0,1,2,3 >> backup/training.log

可視化訓練

參考:

問題解決

不畫框

是圖像長寬比太大導致不畫框,通過查看相關源碼發現,在 image.c 函數中含有如下代碼:

int width = im.h * .006; 

可見源碼有BUG,對於高度過小的圖像,導致不畫框,因爲在 draw_box_width 函數裏:

for(i = 0; i < w; ++i){
    draw_box(a, x1+i, y1+i, x2-i, y2-i, r, g, b);

所以解決方法是:

        if(class >= 0){
            int width = im.h * .006;
            //============================Added by LiuZhi===========================//
            if(width < 1) width = 1; 
            //============================Added by LiuZhi===========================//

            /*
               if(0){
               width = pow(prob, 1./2.)*10+1;
               alphabet = 0;
               }
             */

            //printf("%d %s: %.0f%%\n", i, names[class], prob*100);
            int offset = class*123457 % classes;
            float red = get_color(2,offset,classes);
            float green = get_color(1,offset,classes);
            float blue = get_color(0,offset,classes);
            float rgb[3];

訓練時錯誤

Assertion `0’ failed

提示如下錯誤,試了網上的幾個方法,如改Makefile文件中的GPU ARCH,使用sudo 運行,等等均不行。後來想起自己曾改了batchsize爲64,於是將其改小爲8,該完後,重新運行,一切正常,是內存不足的問題。

darknet: ./src/cuda.c:36: check_error: Assertion `0' failed.
./train.sh: line 3: 12389 Aborted                 (core dumped) 

測試

輸出類別與自定義的不同

自定義二分類任務,訓練後測試發現,目標種類始終爲 “Person” 這應該是VOC和COCO裏的類別,網上查了好久,無果。第二天睡醒後,決定自己看看源碼,追根溯源,很快,不到5分鐘,找到了問題所在,看到下面代碼段中的最後一行了嗎(約在源文件440行),是的輸入的配置文件是 “cfg/coco.data” , ~.~:

終端執行代碼: ./darknet detect cfg/yolov3-tiny-lpd.cfg backup/yolov3-tiny-lpd_800.weights data/002001.jpg -thresh 0.0000

文件: “darknet.c”

    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);

你可以把”cfg/coco.data”換成你的,但是得重新編譯,注意看有個 “detector” ,在”detector.c”這個文件裏有:

void run_detector(int argc, char **argv)
{
...
    char *datacfg = argv[3];
    char *cfg = argv[4];
    char *weights = (argc > 5) ? argv[5] : 0;
    char *filename = (argc > 6) ? argv[6]: 0;
    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(cfg, weights);
    else if(0==strcmp(argv[2], "demo")) {
        list *options = read_data_cfg(datacfg);
        int classes = option_find_int(options, "classes", 20);
        char *name_list = option_find_str(options, "names", "data/names.list");
        char **names = get_labels(name_list);
        demo(cfg, weights, thresh, cam_index, filename, names, classes, frame_skip, prefix, avg, hier_thresh, width, height, fps, fullscreen);

看到了吧:test_detector(datacfg,於是決定 調用detector(這樣不用改代碼了),如下:

./darknet detector test cfg/data/lpd/lpd.data cfg/yolov3-tiny-lpd.cfg backup/yolov3-tiny-lpd_600.weights data/002003.jpg -thresh -0

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