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。最后计算网络的损失。
- Apriori算法介绍(Python实现)
- linux学习第六十二篇:添加自定义监控项目,配置邮件告警,测试告警,不发邮件的问题处理
- Entity Framework Core 2.0 入门
- Nodejs开发框架Express3.0开发手记–从零开始
- 使用 nvm 管理不同版本的 node 与 npm
- svg矢量图绘制以及转换为Android可用的VectorDrawable资源
- CListCtrl控件使用方法总结
- JavaScript基础考核真题——你能全做对吗?
- 拉手网面试题,不一样的难度
- Html 5 video/audio 格式转换 ogg
- ASP.NET MVC 开源项目Kigg解读(1)
- 一个setInterval的小问题
- scrollLeft等属性介绍
- ASP.NET MVC 开源项目Kigg解读(2)——Kigg.Core第一部分
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- K8S Ingress使用|常见问题列表
- 部署Tomcat及负载均衡
- Jenkins常用插件Publish Over SSH
- Zabbix 4.0配置监控Linux客户端
- esp8266+oled+DHT 11温湿度显示
- esp8266+oled 显示时间日期
- esp8266+DHT11温湿传感器 制作web室内温度计
- Linux端口转发的几种常用方法
- kali破解wifi密码
- 面向对象的7种设计原则(7)-开闭原则
- [数据库介绍]一站式表达谱数据分析
- windows下hashcat利用GPU显卡性能破解密码
- TCGAG多组学联合分析数据库
- Docker安装及使用
- CVE-2020-0796漏洞复现(RCE)