darknet源码剖析(六) 模型训练初探

时间:2019-02-11
本文章向大家介绍darknet源码剖析(六) 模型训练初探,主要包括darknet源码剖析(六) 模型训练初探使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

终于到了最核心的部分了,模型训练的过程由两个部分组成,分别是正向传播与反向传播的过程。

首先来看模型的正向传播过程,还是根据函数的调用过程。

(1)train_network(network.c)

    int batch = net->batch;
    int n = d.X.rows / batch;

根据yolov1的配置,batch的值为8,d.X.rows的值为64,因此n的值也为8。

    for(i = 0; i < n; ++i){
        get_next_batch(d, batch, i*batch, net->input, net->truth);
        float err = train_network_datum(net);
        sum += err;
    }
    return (float)sum/(n*batch);

通过上面的代码可以明确,yolo的训练过程是每次获取batch张图片,共执行n次。每次训练时调用train_network_datum函数进行训练,并返回损失。最后train_network函数返回平均损失。

(2)train_network_datum(network.c)

    *net->seen += net->batch;

batch表示每个batch训练的图片数量,seen表示已经训练的图片的数量。

    net->train = 1;
    forward_network(net);
    backward_network(net);
    float error = *net->cost;

将网络设置为训练模式,并执行正向传播与反向传播,同时获取网络的损失。

    if(((*net->seen)/net->batch)%net->subdivisions == 0) update_network(net);

如果(*net->seen)/net->batch是net->subdivisions的整倍数,则更新网络参数。此处的net->seen为64的整倍数则会更新一次网络,正好与yolov1.cfg中batch的设置相等,若当前GPU的内存较小,可以通过增大subdivisions的方式,之前的分析中已经发现,batch的实际数字是batch/subdivisions(yolov1.cfg配置)。此处((*net->seen)/net->batch)%net->subdivisions的值恰好等于batch的设置,表明网络每个batch张图片更新一次。

以上内容总结起来就是一句话:由于GPU内存不足可以增大subdivisions的值,此时net->batch的值就会减小,但是网络参数的更新仍然按照batch的大小(yolov1.cfg配置的值)

    return error;

最后返回损失。

forward、backward与update均包括GPU与非GPU版本。若在编译阶段定义了GPU,则执行每一层的forward_gpu函数,否则调用forward函数。backward与update的过程类似。以forward的CPU执行过程为例:

    network net = *netp;
    int i;
    for(i = 0; i < net.n; ++i){
        net.index = i;
        layer l = net.layers[i];
        if(l.delta){
            fill_cpu(l.outputs * l.batch, 0, l.delta, 1);
        }
        l.forward(l, net);
        net.input = l.output;
        if(l.truth) {
            net.truth = l.output;
        }
    }
    calc_network_cost(netp);

for循环逐层调用每一层的forward函数,forward函数调用结束后将net.input指向每一层的output。若当前层为dropout层则l.delta有效,否则为0。最后计算网络的损失。