文章全部YOLOv2源码分析
0x01 parse_network_cfg
我们继续前面没有说完的parse_network_cfg
//parse_network_cfg
node *n = sections->front;
if(!n) error("Config file has no sections");
我么先要了解一下list
结构
typedef struct list{
int size;
node *front;
node *back;
} list;
typedef struct node{
void *val;
struct node *next;
struct node *prev;
} node;
这其实是一个双向链表,前向和后项都是一个node
数据结构。这里,如果,这个链表后没有节点的话,就报错。
接着往后
//parse_network_cfg
network *net = make_network(sections->size - 1);
这里使用了一个make_network
函数
network *make_network(int n)
{
network *net = calloc(1, sizeof(network));
net->n = n;
net->layers = calloc(net->n, sizeof(layer));
net->seen = calloc(1, sizeof(size_t));
net->t = calloc(1, sizeof(int));
net->cost = calloc(1, sizeof(float));
return net;
}
注意这里的这个make_network
可能和早期的不太一样。我们先看看这里他做了什么。先看看network
这个结构
//这个文件现在放在了darknet.h文件中
typedef enum {
CONSTANT, STEP, EXP, POLY, STEPS, SIG, RANDOM
} learning_rate_policy;
typedef struct network{
int n; //网络总层数
int batch; //一个batch包含的图片数目,看下面的subdivisions
size_t *seen; //已经读取的图片数量
int *t;
float epoch; //训练的次数
int subdivisions; //注意前面的batch/subdivisions才是网络的batch大小,可能目的是防止gpu显存不够
layer *layers; //指向网络的层
float *output;
learning_rate_policy policy;//学习率的策略,是一个枚举类型
float learning_rate;//学习率
float momentum; //动量,一般0.9
float decay; //权重衰减正则项,防止过拟合
float gamma; //用于计算学习率,见后面0x0102
float scale; //用于计算学习率,见后面0x0102
float power; //用于计算学习率,见后面0x0102
int time_steps;
int step; //用于计算学习率,见后面0x0102
int max_batches; //最大的训练batch数目
float *scales; //用于计算学习率,见后面0x0102
int *steps; //用于计算学习率,见后面0x0102
int num_steps; //steps中的数据个数
int burn_in;
int adam; //adam算法
float B1; //一阶矩估计的指数衰减率
float B2; //二阶矩估计的指数衰减率
float eps; //为了防止在实现中除以零
int inputs; //h*w*c
int outputs;
int truths;
int notruth;
int h, w, c; //输入图像的高,宽,通道数
int max_crop; //控制图片缩放的最大值
int min_crop; //控制图片缩放的最小值
float max_ratio; //控制图片缩放的最大比例
float min_ratio; //控制图片缩放的最小比例
int center;
float angle; //设置旋转角度,扩充数据
float aspect; //设置方位,扩充数据
float exposure; //设置曝光量,扩充数据
float saturation; //设置饱和度,扩充数据
float hue; //设置色调,扩充数据
int random; //random为1时随机使用不同尺寸的图片进行训练
int gpu_index; //设置第几个gpu
tree *hierarchy;
float *input;
float *truth;
float *delta;
float *workspace;
int train;
int index;
float *cost;
#ifdef GPU
float *input_gpu;
float *truth_gpu;
float *delta_gpu;
float *output_gpu;
#endif
} network;
由于参数太多,用到哪个说哪个,这个结构的主要作用就是存储网络的配置参数。make_network
的作用就是产生network
这种数据结构。接着往下
//parse_network_cfg
net->gpu_index = gpu_index;//设置gpu
size_params params;
又出现一个新的结构size_params
typedef struct size_params{
int batch; //一个batch包含的图片数目
int inputs;
int h; //图像的高
int w; //输入图像的宽
int c; //输入图像的通道数
int index;
int time_steps;
network *net;
} size_params;
接着往下
//parse_network_cfg
section *s = (section *)n->val;//section这个结构我在(一)中提过
n
是一个node
结构,这个结构中的val
是一个void*
,所以这里就是将node
结构中的val
强转为section*
,相当于我在(一)中图上画的[net]
等节点。
//parse_network_cfg
list *options = s->options;//这里就是之前说的kvp,也就是size=3,stride=1,pad=1这些
if(!is_network(s)) error("First section must be [net] or [network]");
看一下这个is_network
函数
int is_network(section *s)
{
return (strcmp(s->type, "[net]")==0
|| strcmp