1. 程式人生 > >YOLO原始碼詳解(一)-訓練

YOLO原始碼詳解(一)-訓練

本系列文章會持續更新,主要會分以下幾個部分:
1、darknet下的yolo原始碼解讀
2、將yolo移植到mxnet下
3、模型壓縮與加速
白天需要工作,只有晚上時間寫,所以可能更新速度有點慢,還有就是該系列博文不一定會嚴格按照以上三點的順序來寫,也可能移植到caffe下,在caffe下進行壓縮和加速。

一、訓練

我用的是VOC2007的資料集,下載指令如下:

$curl -O http://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar
$curl -O http://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar
$tar xf VOCtrainval_06-Nov-2007.tar $tar xf VOCtest_06-Nov-2007.tar

執行以下程式碼,將.xml 檔案轉換成.txt 檔案,以備YOLO訓練時資料解析:

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

sets=[('2007', 'train'), ('2007', 'val')]

classes = ["aeroplane", "bicycle", "bird"
, "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"] def convert(size, box): dw = 1./size[0] dh = 1./size[1] x = (box[0] + box[1])/2.0 y = (box[2] + box[3])/2.0 w = box[1] - box[0
] h = box[3] - box[2] x = x*dw w = w*dw y = y*dh h = h*dh return (x,y,w,h) def convert_annotation(year, image_id): in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id)) out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w') tree=ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for obj in root.iter('object'): difficult = obj.find('difficult').text cls = obj.find('name').text if cls not in classes or int(difficult) == 1: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) bb = convert((w,h), b) out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') wd = getcwd() for year, image_set in sets: if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)): os.makedirs('VOCdevkit/VOC%s/labels/'%(year)) image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split() list_file = open('%s_%s.txt'%(year, image_set), 'w') for image_id in image_ids: list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id)) convert_annotation(year, image_id) list_file.close()

yolo.c中找到以下程式碼,並修改:

//指向你剛才生成的train.txt檔案
char *train_images = "/data/voc/train.txt";
//新建個資料夾,然後指向這裡就可以,訓練生成的模型檔案會儲存在這裡
char *backup_directory = "/home/pjreddie/backup/";

執行以下指令開始訓練:

./darknet yolo train cfg/yolo.train.cfg extraction.conv.weights

二、原始碼解讀

1.首先我們看一下訓練的資料流,從main函式開始看,該函式在darknet.c 檔案中:

//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")){
        //第一個引數是yolo,所以跳轉到run_yolo函式
        run_yolo(argc, argv);
    } else {
        fprintf(stderr, "Not an option: %s\n", argv[1]);
    }
    return 0;
}
//yolo.c
void run_yolo(int argc, char **argv)
{
    char *prefix = find_char_arg(argc, argv, "-prefix", 0);
    float thresh = find_float_arg(argc, argv, "-thresh", .2);
    int cam_index = find_int_arg(argc, argv, "-c", 0);
    int frame_skip = find_int_arg(argc, argv, "-s", 0);
    if(argc < 4){
        fprintf(stderr, "usage: %s %s [train/test/valid] [cfg] [weights (optional)]\n", argv[0], argv[1]);
        return;
    }

    char *cfg = argv[3];
    char *weights = (argc > 4) ? argv[4] : 0;
    char *filename = (argc > 5) ? argv[5]: 0;
    if(0==strcmp(argv[2], "test")) test_yolo(cfg, weights, filename, thresh);
    //第二個引數是train,所以跳轉到了train_yolo函式
    else if(0==strcmp(argv[2], "train")) train_yolo(cfg, weights);
    voc_names, 20, frame_skip, prefix);
}


void train_yolo(char *cfgfile, char *weightfile)
{
    char *train_images = "/data/voc/train.txt";
    char *backup_directory = "/home/pjreddie/backup/";
    /*srand函式是隨機數發生器的初始化函式。
    srand和rand()配合使用產生偽隨機數序列。rand函式在產生隨機數前,需要系統提供的生成偽隨機數序列的
    種子,rand根據這個種子的值產生一系列隨機數。如果系統提供的種子沒有變化,每次呼叫rand函式生成的偽
    隨機數序列都是一樣的。*/
    srand(time(0));
    /*第三個引數是:`cfg/yolo.train.cfg`,`basecfg()`這個函式把`cfg/yolo.train.cfg`變成了
    `yolo0train.cfg`,然後用base指標指向`yolo0train.cfg`*/
    char *base = basecfg(cfgfile);
    //列印"yolo"字樣
    printf("%s\n", base);
    float avg_loss = -1;
    //解析網路構架,下面會仔細分析該函式
    network net = parse_network_cfg(cfgfile);
    //載入預訓練引數,下面會仔細分析該函式
    if(weightfile){
        load_weights(&net, weightfile);
    }
    printf("Learning Rate: %g, Momentum: %g, Decay: %g\n", net.learning_rate, net.momentum, net.decay);
    /*imgs是一次載入到記憶體的影象數量,如果佔記憶體太大的話可以把subdivisions或者batch調小一點
    詳細可以參考知乎:[深度機器學習中的batch的大小對學習效果有何影響?](https://www.zhihu.com/question/32673260)*/
    int imgs = net.batch*net.subdivisions;
    //net.seen就是已經經過網路訓練(看)的圖片數量,算出的i就是已經經過了多少次訓練
    int i = *net.seen/imgs;
    data train, buffer;


    layer l = net.layers[net.n - 1];
    //side就是論文中的7
    int side = l.side;
    int classes = l.classes;
    //jitter是什麼意思呢?可以參考這篇部落格:[非均衡資料集處理:利用抖動(jittering)生成額外資料](http://weibo.com/1402400261/EgMr4vCC2?type=comment#_rnd1478833653326)
    float jitter = l.jitter;

    list *plist = get_paths(train_images);
    //int N = plist->size;
    char **paths = (char **)list_to_array(plist);

    load_args args = {0};
    args.w = net.w;
    args.h = net.h;
    args.paths = paths;
    //n就是一次載入到記憶體中的圖片數量
    args.n = imgs;
    //m是待訓練圖片的總數量
    args.m = plist->size;
    args.classes = classes;
    args.jitter = jitter;
    //7*7個網格
    args.num_boxes = side;
    args.d = &buffer;
    args.type = REGION_DATA;

    //調節圖片旋轉角度、曝光度、飽和度、色調等,來增加圖片數量
    args.angle = net.angle;
    args.exposure = net.exposure;
    args.saturation = net.saturation;
    args.hue = net.hue;
    //宣告執行緒ID
    pthread_t load_thread = load_data_in_thread(args);
    clock_t time;
    //while(i*imgs < N*120){
    while(get_current_batch(net) < net.max_batches){
        i += 1;
        time=clock();
        /*pthread_join()函式,以阻塞的方式等待thread指定的執行緒結束。當函式返回時,被等待執行緒的資源被
        收回。如果執行緒已經結束,那麼該函式會立即返回。*/
        pthread_join(load_thread, 0);
        train = buffer;
        load_thread = load_data_in_thread(args);

        printf("Loaded: %lf seconds\n", sec(clock()-time));

        time=clock();
        //開始訓練
        float loss = train_network(net, train);
        if (avg_loss < 0) avg_loss = loss;
        avg_loss = avg_loss*.9 + loss*.1;

        printf("%d: %f, %f avg, %f rate, %lf seconds, %d images\n", i, loss, avg_loss, get_current_rate(net), sec(clock()-time), i*imgs);
        //每100次或者1000次儲存一次權重
        if(i%1000==0 || (i < 1000 && i%100 == 0)){
            char buff[256];
            sprintf(buff, "%s/%s_%d.weights", backup_directory, base, i);
            save_weights(net, buff);
        }
        free_data(train);
    }
    char buff[256];
    sprintf(buff, "%s/%s_final.weights", backup_directory, base);
    save_weights(net, buff);
}

看到這裡,我想你已經能可以自己來訓練VOC資料集了。但這只是剛剛開始,我們要想將YOLO移植到mxnet下,就需要了解其具體函式的實現過程,請看下一節內容。

(END)

相關推薦

YOLO原始碼-訓練

本系列文章會持續更新,主要會分以下幾個部分: 1、darknet下的yolo原始碼解讀 2、將yolo移植到mxnet下 3、模型壓縮與加速 白天需要工作,只有晚上時間寫,所以可能更新速度有點慢,還有就是該系列博文不一定會嚴格按照以上三點的順序來

06.RTSP原始碼

6.7.rtsp傳輸原始碼分析1 6.8.rtsp傳輸原始碼分析2 6.9.rtsp傳輸原始碼分析3 6.10.rtsp傳輸原始碼分析4 6.11.rtsp傳輸實戰分析 6.12.直接傳送與環狀buffer傳送 6.13.rtsp分包傳送h264的原始碼分析 rtp_timestamp:http

spring的BeanFactory和ApplicationContext原始碼

轉自http://www.sandzhang.com/blog/2011/04/10/Spring-BeanFactory-ApplicationContext-Detail-1/ 版本:spring-framework-3.0.5.RELEASE Spring的最核心的部分就是BeanFactory了,

YOLO原始碼- YOLO中的7*7個grid和RPN中的9個anchors

一直不知道7×7的網格到底是幹什麼的,不就是結果預測7×7×2個框嗎,這跟把原圖分成7×7有什麼關係?不分成7×7就不能預測7×7×2個框嗎? 之前跟一個朋友討論,他說7×7的網格是作為迴歸框的初始位置,我後來的很長一段時間一直這麼認為,後來想想不對啊

YOLO原始碼- 函式剖析

1、網路引數解析函式:parse_network_cfg network parse_network_cfg(char *filename) { //read_cfg這個函式將所有的引數讀到一個圖中,如下所示,希望能幫助理解下程式碼

YOLO原始碼- 反向傳播back propagation

反向傳播是CNN中非常重要的一個環節,對於理論部分,這裡不做介紹,如果對反向傳播理論部分不熟悉,可以檢視以下網站。 非常詳細:零基礎入門深度學習(3) - 神經網路和反向傳播演算法 非常詳細:零基礎入門深度學習(4) - 卷積神經網路 非常生動:如

EventBus原始碼:基本使用

寫在前面 對於Android程式設計師來說,相信大家都聽過EventBus的大名。EventBus是一個Android平臺上基於事件釋出和訂閱的輕量級框架,可以對釋出者和訂閱者解耦,並簡化Android的事件傳遞。正如官方介紹其優勢: 簡化了元件之間的通訊

Android程式設計之DialogFragment原始碼

DialogFragment是Fragment家族成員之一,如果你把它簡單的理解成Dialog,那就錯了。它的確可以做作dialog顯示,還可以顯示出自己定義的Dialog或者AlertDialog,但它同時也是一個Fragment。 按照官方的話來理解就是,你既可以把它當

jdbc原始碼:示例+Driver註冊流程

0x00 前言 自己一直說要某個開源專案的原始碼,但是一直沒有真正地好好開始,一是以為看原始碼其實不容易看懂,而是因為選擇猶豫,最後也敲定看哪個。 這次正式開始看jdbc的原始碼有兩個三個:一是因為《java程式設計思想》這本書快看完了,折騰一個多月的時間,

gRPC 原始碼配置化的結構體

grpc 原始碼結構詳解 DialOptions DialOptions 是最重要的一環,負責配置每一次 rpc 請求的時

elastic-job:數據分片

count 任務 不同的 應該 center shc 偶數 int ext 數據分片的目的在於把一個任務分散到不同的機器上運行,既可以解決單機計算能力上限的問題,也能降低部分任務失敗對整體系統的影響。elastic-job並不直接提供數據處理的功能,框架只會將分片項分配至各

JVM的基本結構及其各部分

後臺 棧幀 結束 依次 方法參數 ati 0.00 實例 同時存在 JVM的基本結構及其各部分詳解(一)(轉載) 1 java虛擬機的基本結構如圖: 1)類加載子系統負責從文件系統或者網絡中加載Class信息,加載的類信息存放於一塊稱為方法區的內存空間。除了類的信息外,方

設計模式

att 定義 面向對象設計 設計 sig com 繼承 行為模式 接口 一、設計模式定義 設計模式(Design Pattern)是一套被反復使用、多數人知曉的、經過分類的、代碼設計經驗的總結。 使用設計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。

mybatis ------JDBC

jdbc javax 發出 一段 true his 實例 用戶名 移植 1、什麽是MyBatis?   MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,

Maven------ Maven概述

粘貼 cvs 模塊 strong ron 標準化 pom 標準 只需要 1、引言     你能搜到這個教程,說明你對 Maven 感興趣,但是又不是太理解。那麽接下來這個系列的教程將會詳細講解 Maven 的用法,相信你看完之後,一定能對 Maven 的理解更進一步!

.Net AppDomain

() arc .com args [] adas 功能 reading wpa AppDomain是CLR的運行單元,它可以加載Assembly、創建對象以及執行程序。AppDomain是CLR實現代碼隔離的基本機制。 每一個AppDomain可以單獨運行、停止;每個App

防火墻iptables

主從dns服務器 進行 所有 out show mountd 讀取 ppp 概念 -- 防火墻 常見的防火墻 :瑞星 江民 諾頓 卡巴斯基 天網...... iptables firewalld http://www.netfilter.org/ netfilter

Windows滲透利器之Pentest BOX使用

內存 標簽 配置 ram 添加 概覽 測試環境 功能 ruby 內容概覽: 知識科普 優缺點總結 功能參數詳解翻譯: 控制臺參

JVM類加載機制JVM類加載過程

進行 虛擬機啟動 類加載的時機 bsp 參與 tro ext 環境 java代碼 首先Throws(拋出)幾個自己學習過程中一直疑惑的問題: 1、什麽是類加載?什麽時候進行類加載? 2、什麽是類初始化?什麽時候進行類初始化? 3、什麽時候會為變量分配內存? 4、什麽時候會為

Java的反射機制

pbc spa 詳解 uno face target lan tor cin 8n72q傅釁8戰sig叢http://www.docin.com/app/user/userinfo?userid=179185461 8u炊3F7LB椒1http://huiyi.docin.