YOLO 算法时实践

yolo 目标检测也已经被玩坏了,现在开始我的学习之路。

最简单的,先修改下网络的输出形式,传统的输出如下所示:

YOLO 算法时实践

修改为如下所示的输出形式,和原来的没啥区别,主要是加如了“X”的效果,这个在src/image.c文件下实现。

YOLO 算法时实践

好了,简单的开始后就是复杂的了。

先来解析下yolov3的源码:

yolov3 包含了多个不同的层,包括卷积层,池化层、残差网络等都是在cfg下预先定义好的,由YOLO源码的network 先读取网络,保存在net * 类中,还有再读取权重,然后开始计算。

yolov3 的算法流程由cfg 定义,parser.c中实现了这一文件的解析

network *parse_network_cfg(char *filename)

while(n){
        params.index = count;
        fprintf(stderr, "%5d ", count);
        s = (section *)n->val;
        options = s->options;
        layer l = {0};
        LAYER_TYPE lt = string_to_layer_type(s->type);
        if(lt == CONVOLUTIONAL){
            l = parse_convolutional(options, params);
        }else if(lt == DECONVOLUTIONAL){
            l = parse_deconvolutional(options, params);
        }else if(lt == LOCAL){
            l = parse_local(options, params);
        }else if(lt == ACTIVE){
            l = parse_activation(options, params);
        }else if(lt == LOGXENT){
            l = parse_logistic(options, params);
        }else if(lt == L2NORM){
            l = parse_l2norm(options, params);
        }else if(lt == RNN){
            l = parse_rnn(options, params);
        }else if(lt == GRU){
            l = parse_gru(options, params);
        }else if (lt == LSTM) {
            l = parse_lstm(options, params);
        }else if(lt == CRNN){
            l = parse_crnn(options, params);
        }else if(lt == CONNECTED){
            l = parse_connected(options, params);
        }else if(lt == CROP){
            l = parse_crop(options, params);
        }else if(lt == COST){
            l = parse_cost(options, params);
        }else if(lt == REGION){
            l = parse_region(options, params);
        }else if(lt == YOLO){
            l = parse_yolo(options, params);
        }else if(lt == DETECTION){
            l = parse_detection(options, params);
        }else if(lt == SOFTMAX){
            l = parse_softmax(options, params);
            net->hierarchy = l.softmax_tree;
        }else if(lt == NORMALIZATION){
            l = parse_normalization(options, params);
        }else if(lt == BATCHNORM){
            l = parse_batchnorm(options, params);
        }else if(lt == MAXPOOL){
            l = parse_maxpool(options, params);
        }else if(lt == REORG){
            l = parse_reorg(options, params);
        }else if(lt == AVGPOOL){
            l = parse_avgpool(options, params);
        }else if(lt == ROUTE){
            l = parse_route(options, params, net);
        }else if(lt == UPSAMPLE){
            l = parse_upsample(options, params, net);
        }else if(lt == SHORTCUT){
            l = parse_shortcut(options, params, net);
        }else if(lt == DROPOUT){
            l = parse_dropout(options, params);
            l.output = net->layers[count-1].output;
            l.delta = net->layers[count-1].delta;

不同的层会定义不同的操作,文件解析并将l.forward 定义为不同的操作。

数据保存再net * 中。

所以这个算法确实是非常的浪费内存,有过测试,这个算法起码需要2G的内存,要不说这个算法快呢?

然后大家就可以按照这个分支去看源码了,就没有那么麻烦了。

还有就是Makefile 的解析,应为要生成GPU的程序,记得修改为GPU=1。