YOLO源码(结构体)解读

原文出处
1. src/network.h(darknet中网络结构体:network)

typedef struct network {
    int n;  // 网络总层数
    int batch;//一张图像被划分成batch x batch个小方块
    uint64_t *seen;  // 目前已经读入的图片张数(网络已经处理的图片张数)(在make_network()中动态分配内存)
    int *t;
    float epoch;
    int subdivisions;
    layer *layers;// 存储网络所有的层,在make_network()中动态分配内存
    float *output;
    learning_rate_policy policy;

    float learning_rate;  //学习率
    float learning_rate_min;
    float learning_rate_max;
    int batches_per_cycle;
    int batches_cycle_mult;
    float momentum;
    float decay;
    float gamma;
    float scale;
    float power;
    int time_steps;
    int step;
    int max_batches;
    int num_boxes;
    int train_images_num;
    float *seq_scales;
    float *scales;
    int   *steps;
    int num_steps;
    int burn_in;
    int cudnn_half;

    int adam;
    float B1;
    float B2;
    float eps;

    int inputs;   // 一张输入图片的元素个数,如果网络配置文件中未指定,则默认等于net->h * net->w * net->c,在parse_net_options()中赋值
    int outputs;// 一张输入图片对应的输出元素个数,对于一些网络,可由输入图片的尺寸及相关参数计算出,比如卷积层,可以
    通过输入尺寸以及跨度、核大小计算出; 对于另一些尺寸,则需要通过网络配置文件指定,如未指定,取默认值1,比如全连接层
    int truths;
    int notruth;
    int h, w, c;
    int max_crop;
    int min_crop;
    float max_ratio;
    float min_ratio;
    int center;
    int flip; // horizontal flip 50% probability augmentaiont for classifier training (default = 1)
    int blur;
    int mixup;
    int letter_box;
    float angle;
    float aspect;
    float exposure;
    float saturation;
    float hue;
    int random;
    int track;
    int augment_speed;
    int sequential_subdivisions;
    int init_sequential_subdivisions;
    int current_subdivision;
    int try_fix_nan;

    int gpu_index;
    tree *hierarchy;

    float *input;// 中间变量,用来暂存某层网络的输入(包含一个batch的输入,比如某层网络完成前向,将其输出赋给该变量,作为下一层的输入,可以参看network.c中的forward_network()与backward_network()两个函数),
                        // 当然,也是网络接受最原始输入数据(即第一层网络接收的输入)的变量(比如在图像检测训练中,最早在train_detector()->train_network()->get_next_batch()函数中赋值)

    float *truth; // 中间变量,与上面的input对应,用来暂存input数据对应的标签数据(真实数据)
    float *delta;// 中间变量,用来暂存某层网络的敏感度图(反向传播处理当前层时,用来存储上一层的敏感度图,因为当前层会计算部分上一层的敏感度图,可以参看network.c中的backward_network()函数),
                        // net.delta并没有在创建网络之初就为其动态分配了内存,而是等到反向传播时,直接将其等于某一层的l.delta(l.delta是在创建每一层网络之初就动态为其分配了内存),这才为net.delta分配了内存,
                        // 如果没有令net.delta=l.delta,则net.delta是未定义的(没有动态分配内存的)
    float *workspace;// 整个网络的工作空间,其元素个数为所有层中最大的l.workspace_size = l.out_h*l.out_w*l.size*l.size*l.c
                        // (在make_convolutional_layer()计算得到workspace_size的大小,在parse_network_cfg()中动态分配内存,
                        // 此值对应未使用gpu时的情况),该变量貌似不轻易被释放内存,目前只发现在network.c的resize_network()函数对其进行了释放。
                        // net.workspace充当一个临时工作空间的作用,存储临时所需要的计算参数,比如每层单张图片重排后的结果
                        // (这些参数马上就会参与卷积运算),一旦用完,就会被马上更新(因此该变量的值的更新频率比较大)

    int train; // 标志参数,网络是否处于训练阶段,如果是,则值为1(这个参数一般用于训练与测试有不同操作的情况,比如dropout层,对于训练,才需要进行forward_dropout_layer()函数,对于测试,不需要进入到该函数)
    int index;// 标志参数,当前网络的活跃层(活跃包括前向和反向,可参考network.c中forward_network()与backward_network()函数)
    float *cost;
    float clip;

#ifdef GPU
    //float *input_gpu;
    //float *truth_gpu;
    float *delta_gpu;
    float *output_gpu;

    float *input_state_gpu;
    float *input_pinned_cpu;
    int input_pinned_cpu_flag;

    float **input_gpu;
    float **truth_gpu;
    float **input16_gpu;
    float **output16_gpu;
    size_t *max_input16_size;
    size_t *max_output16_size;
    int wait_stream;
#endif
} network;

2. src/layer.h(darknet中的每一层操作的结构体)

struct layer {
    LAYER_TYPE type;// 网络层的类型,枚举类型,取值比如DROPOUT,CONVOLUTIONAL,MAXPOOL分别表示dropout层,卷积层,最大池化层,可参见LAYER_TYPE枚举类型的定义
    ACTIVATION activation; //激活函数的类型
    COST_TYPE cost_type;//损失函数的类型
    void(*forward)   (struct layer, struct network_state);
    void(*backward)  (struct layer, struct network_state);
    void(*update)    (struct layer, int, float, float, float);
    void(*forward_gpu)   (struct layer, struct network_state);
    void(*backward_gpu)  (struct layer, struct network_state);
    void(*update_gpu)    (struct layer, int, float, float, float);
    layer *share_layer;
    int batch_normalize;
    int shortcut;
    int batch;
    int forced;
    int flipped;
    int inputs;
    int outputs;
    int nweights;
    int nbiases;
    int extra;
    int truths;
    int h, w, c; // 该层输入图片的高、宽、通道数(一般在各网络层构建函数中赋值,比如make_connected_layer()),
                                // 第一层网络的h,w,c就是网络初始能够的接收的图片尺寸,而后每一层的h,w,c都与自动匹配上一层相应的输出参数,
                                // 不再需要配置文件指定(参见parse_network_cfg(),在构建每一层后,会更新params.h,params.w,params.c及params.inputs为上一层相应的输出参数),
                                // 对于全连接层,h,w直接置为1,c置为l.inputs(参见make_connected_layer())

    int out_h, out_w, out_c;// 该层输出图片的高、宽、通道数(一般在各网络层构建函数中赋值,比如make_connected_layer()),
                                // 对于卷积层,可由上面的h,w,c以及卷积核尺寸、跨度计算出;对于全连接层,out_h,out_w的值直接置为1,
                                // out_c直接置为l.outputs(参见make_connected_layer())

    int n; // 对于卷积层,该参数表示卷积核个数,等于out_c,其值由网络配置文件指定;对于region_layerc层,该参数等于配置文件中的num值
                                // (该参数通过make_region_layer()函数赋值,而在parser.c中调用的make_region_layer()函数),
                                // 可以在darknet/cfg文件夹下执行命令:grep num *.cfg便可以搜索出所有设置了num参数的网络,这里面包括yolo.cfg等,其值有
                                // 设定为3,5,2的,该参数就是Yolo论文中的B,也就是一个cell中预测多少个box。

    int max_boxes;
    int groups;
    int size; // 核尺寸(比如卷积核,池化核等)
    int side;
    int stride;//步长
    int dilation;
    int maxpool_depth;
    int out_channels;
    int reverse;
    int flatten;
    int spatial;
    int pad;// 该层对输入数据四周的补0长度(现在发现在卷积层,最大池化层中有用到该参数),一般在构建具体网络层时赋值(比如make_maxpool_layer()中)
    int sqrt;
    int sqrt;
    int flip;
    int index;
    int binary;
    int xnor;
    int peephole;
    int use_bin_output;
    int steps;
    int state_constrain;
    int hidden;
    int truth;
    float smooth;
    float dot;
    float angle;
    float jitter;
    float saturation;
    float exposure;
    float shift;
    float ratio;
    float learning_rate_scale;
    float clip;
    int focal_loss;
    int noloss;
    int softmax;
    int classes;// 物体类别种数,一个训练好的网络,只能检测指定所有物体类别中的物体,比如yolo9000.cfg,设置该值为9418,
                                // 也就是该网络训练好了之后可以检测9418种物体。该参数由网络配置文件指定。目前在作者给的例子中,
                                // 有设置该值的配置文件大都是检测模型,纯识别的网络模型没有设置该值,我想是因为检测模型输出的一般会为各个类别的概率,
                                // 所以需要知道这个种类数目,而识别的话,不需要知道某个物体属于这些所有类的具体概率,因此可以不知道。

    int coords; // 这个参数一般用在检测模型中,且不是所有层都有这个参数,一般在检测模型最后一层有,比如region_layer层,该参数的含义
                                // 是定位一个物体所需的参数个数,一般为4个,包括物体所在矩形框中心坐标x,y两个参数以及矩形框长宽w,h两个参数,
                                // 可以在darknet/cfg文件夹下,执行grep coords *.cfg,会搜索出所有使用该参数的模型,并可看到该值都设置位4

    int background;
    int rescore;
    int objectness;
    int does_cost;
    int joint;
    int noadjust;
    int reorg;
    int log;
    int tanh;
    int *mask;
    int total;
    float bflops;

    int adam;
    float B1;
    float B2;
    float eps;

    int t;

    float alpha;
    float beta;
    float kappa;

    float coord_scale;
    float object_scale;
    float noobject_scale;
    float mask_scale;
    float class_scale;
    int bias_match;
    int random;
    float ignore_thresh;
    float truth_thresh;
    float thresh;
    float focus;
    int classfix;
    int absolute;
    int assisted_excitation;

    int onlyforward;
    int stopbackward;
    int dontload;
    int dontsave;
    int dontloadscales;
    int numload;

    float temperature;
    float probability;
    float scale;

    char  * cweights;
    int   * indexes;
    int   * input_layers;
    int   * input_sizes;
    int   * map;
    int   * counts;
    float ** sums;
    float * rand;
    float * cost;
    float * state;
    float * prev_state;
    float * forgot_state;
    float * forgot_delta;
    float * state_delta;
    float * combine_cpu;
    float * combine_delta_cpu;

    float *concat;
    float *concat_delta;

    float *binary_weights;

    float *biases;
    float *bias_updates;

    float *scales;
    float *scale_updates;

    float *weights; // 当前层所有权重系数(连接当前层和上一层的系数,但记在当前层上),对于卷积层,维度为l.n*l.c*l.size*l.size,即卷积核个数乘以卷积核尺寸再乘以输入通道数(各个通道上的权重系数独立不一样);
                                // 对于全连接层,维度为单张图片输入与输出元素个数之积inputs*outputs,一般在各网络构建函数中动态分配内存(比如make_connected_layer())

    float *weight_updates;

    float scale_x_y;
    float iou_normalizer;
    float cls_normalizer;
    IOU_LOSS iou_loss;

    char *align_bit_weights_gpu;
    float *mean_arr_gpu;
    float *align_workspace_gpu;
    float *transposed_align_workspace_gpu;
    int align_workspace_size;

    char *align_bit_weights;
    float *mean_arr;
    int align_bit_weights_size;
    int lda_align;
    int new_lda;
    int bit_align;

    float *col_image;
    float * delta;
    float * output;// 存储该层所有的输出,维度为l.out_h * l.out_w * l.out_c * l.batch,可知包含整个batch输入图片的输出,一般在构建具体网络层时动态分配内存(比如make_maxpool_layer()中)。
                                // 按行存储:每张图片按行铺排成一大行,图片间再并成一行。

    float * output_sigmoid;
    int delta_pinned;
    int output_pinned;
    float * loss;
    float * squared;
    float * norms;

    float * spatial_mean;
    float * mean;
    float * variance;

    float * mean_delta;
    float * variance_delta;

    float * rolling_mean;
    float * rolling_variance;

    float * x;
    float * x_norm;

    float * m;
    float * v;

    float * bias_m;
    float * bias_v;
    float * scale_m;
    float * scale_v;


    float *z_cpu;
    float *r_cpu;
    float *h_cpu;
    float *stored_h_cpu;
    float * prev_state_cpu;

    float *temp_cpu;
    float *temp2_cpu;
    float *temp3_cpu;

    float *dh_cpu;
    float *hh_cpu;
    float *prev_cell_cpu;
    float *cell_cpu;
    float *f_cpu;
    float *i_cpu;
    float *g_cpu;
    float *o_cpu;
    float *c_cpu;
    float *stored_c_cpu;
    float *dc_cpu;

    float *binary_input;
    uint32_t *bin_re_packed_input;
    char *t_bit_input;

    struct layer *input_layer;
    struct layer *self_layer;
    struct layer *output_layer;

    struct layer *reset_layer;
    struct layer *update_layer;
    struct layer *state_layer;

    struct layer *input_gate_layer;
    struct layer *state_gate_layer;
    struct layer *input_save_layer;
    struct layer *state_save_layer;
    struct layer *input_state_layer;
    struct layer *state_state_layer;

    struct layer *input_z_layer;
    struct layer *state_z_layer;

    struct layer *input_r_layer;
    struct layer *state_r_layer;

    struct layer *input_h_layer;
    struct layer *state_h_layer;

    struct layer *wz;
    struct layer *uz;
    struct layer *wr;
    struct layer *ur;
    struct layer *wh;
    struct layer *uh;
    struct layer *uo;
    struct layer *wo;
    struct layer *vo;
    struct layer *uf;
    struct layer *wf;
    struct layer *vf;
    struct layer *ui;
    struct layer *wi;
    struct layer *vi;
    struct layer *ug;
    struct layer *wg;

    tree *softmax_tree;

    size_t workspace_size;

#ifdef GPU
    int *indexes_gpu;

    float *z_gpu;
    float *r_gpu;
    float *h_gpu;
    float *stored_h_gpu;

    float *temp_gpu;
    float *temp2_gpu;
    float *temp3_gpu;

    float *dh_gpu;
    float *hh_gpu;
    float *prev_cell_gpu;
    float *prev_state_gpu;
    float *last_prev_state_gpu;
    float *last_prev_cell_gpu;
    float *cell_gpu;
    float *f_gpu;
    float *i_gpu;
    float *g_gpu;
    float *o_gpu;
    float *c_gpu;
    float *stored_c_gpu;
    float *dc_gpu;

    // adam
    float *m_gpu;
    float *v_gpu;
    float *bias_m_gpu;
    float *scale_m_gpu;
    float *bias_v_gpu;
    float *scale_v_gpu;

    float * combine_gpu;
    float * combine_delta_gpu;

    float * forgot_state_gpu;
    float * forgot_delta_gpu;
    float * state_gpu;
    float * state_delta_gpu;
    float * gate_gpu;
    float * gate_delta_gpu;
    float * save_gpu;
    float * save_delta_gpu;
    float * concat_gpu;
    float * concat_delta_gpu;

    float *binary_input_gpu;
    float *binary_weights_gpu;
    float *bin_conv_shortcut_in_gpu;
    float *bin_conv_shortcut_out_gpu;

    float * mean_gpu;
    float * variance_gpu;

    float * rolling_mean_gpu;
    float * rolling_variance_gpu;

    float * variance_delta_gpu;
    float * mean_delta_gpu;

    float * col_image_gpu;

    float * x_gpu;
    float * x_norm_gpu;
    float * weights_gpu;
    float * weight_updates_gpu;
    float * weight_change_gpu;

    float * weights_gpu16;
    float * weight_updates_gpu16;

    float * biases_gpu;
    float * bias_updates_gpu;
    float * bias_change_gpu;

    float * scales_gpu;
    float * scale_updates_gpu;
    float * scale_change_gpu;

    float * output_gpu;
    float * output_sigmoid_gpu;
    float * loss_gpu;
    float * delta_gpu;
    float * rand_gpu;
    float * squared_gpu;
    float * norms_gpu;
#ifdef CUDNN
    cudnnTensorDescriptor_t srcTensorDesc, dstTensorDesc;
    cudnnTensorDescriptor_t srcTensorDesc16, dstTensorDesc16;
    cudnnTensorDescriptor_t dsrcTensorDesc, ddstTensorDesc;
    cudnnTensorDescriptor_t dsrcTensorDesc16, ddstTensorDesc16;
    cudnnTensorDescriptor_t normTensorDesc, normDstTensorDesc, normDstTensorDescF16;
    cudnnFilterDescriptor_t weightDesc, weightDesc16;
    cudnnFilterDescriptor_t dweightDesc, dweightDesc16;
    cudnnConvolutionDescriptor_t convDesc;
    cudnnConvolutionFwdAlgo_t fw_algo, fw_algo16;
    cudnnConvolutionBwdDataAlgo_t bd_algo, bd_algo16;
    cudnnConvolutionBwdFilterAlgo_t bf_algo, bf_algo16;
    cudnnPoolingDescriptor_t poolingDesc;
#endif  // CUDNN
#endif  // GPU
};
需要学习Windows系统YOLOv4的同学请前往《Windows版YOLOv4目标检测实战:原理与源码解析》,课程链接 https://edu.csdn.net/course/detail/29865【为什么要学习这门课】 Linux创始人Linus Torvalds有一句名言:Talk is cheap. Show me the code. 冗谈不够,放码过来!  代码阅读是从基础到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。【课程内容与收获】 本课程将解析YOLOv4的实现原理和源码,具体内容包括:- YOLOv4目标检测原理- 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算- 代码阅读工具及方法- 深度学习计算的利器:BLAS和GEMM- GPU的CUDA编程方法及在darknet的应用- YOLOv4的程序流程- YOLOv4各层及关键技术的源码解析本课程将提供注释后的darknet的源码程序文件。【相关课程】 除本课程《YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括:《YOLOv4目标检测实战:训练自己的数据集》《YOLOv4-tiny目标检测实战:训练自己的数据集》《YOLOv4目标检测实战:人脸口罩佩戴检测》《YOLOv4目标检测实战:中国交通标志识别》建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。【YOLOv4网络模型架构图】 下图由白勇老师绘制  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值