今天来看include文件夹下的darknet.h头文件,里面定义了darknet这个框架的结构体和几个枚举变量,这里记录几个我认为比较重要的。
1.LAYER_TYPE
这个枚举变量用来指定你要定义的网络层是什么类型,可以指定为卷积层、反卷积层、池化层、激活层、YOLO层等等
typedef enum {
CONVOLUTIONAL,
DECONVOLUTIONAL,
CONNECTED,
MAXPOOL,
SOFTMAX,
DETECTION,
DROPOUT,
CROP,
ROUTE,
COST,
NORMALIZATION,
AVGPOOL,
LOCAL,
SHORTCUT,
ACTIVE,
RNN,
GRU,
LSTM,
CRNN,
BATCHNORM,
NETWORK,
XNOR,
REGION,
YOLO,
ISEG,
REORG,
UPSAMPLE,
LOGXENT,
L2NORM,
BLANK
} LAYER_TYPE;
2.update_args结构
这个结构需要指定你选择的是批量梯度下降更新参数的方式还是自适应的梯度下降,如果是批量的梯度下降,可以设置学习率、动量、延迟率而当是自适应梯度下降的话,据还可以制定Adam算法的各种参数
typedef struct{
int batch;
float learning_rate;
float momentum;
float decay;
int adam;
float B1;
float B2;
float eps;
int t;
} update_args;
3.layer与network结构
这两个是很重要的结构,首先我们会看到定义这两个结构前还有四行代码
struct network;
typedef struct network network;
struct layer;
typedef struct layer layer;
首先第一行struct network是一种不完整的声明,因为layer与network是相互之间存在依赖的结构,layer中包含network结构的一个或者多个成员,network也同样包含layer中的成员,这样的话就无法确定这两个结构哪个要先声明,这时就需要不完整声明来解决,声明一个作为结构标签的标识符,然后就可以把这个标签用在无需知道这个结构长度的声明中。stuct layer同理。
然后是第四行 typedef struct layer layer,这行代码的意思是为stuct layer定义一个新名字layer,相当于:
typedef struct layer{
……
}layer
这样我们看network结构的成员列表中 layer *layers才成立,不然要写作struct layer *layers
typedef struct network{
int n;
int batch;
size_t *seen;
int *t;
float epoch;
int subdivisions;
layer *layers;
再者可以看到layer结构里边有很多结构的自引用,注意自引用一定要是指针,不然会陷入无限循环
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 *uf;
struct layer *wf;
struct layer *ui;
struct layer *wi;
struct layer *ug;
struct layer *wg;
4.node与list结构
这两种结构链表的实现会使用到
typedef struct node{
void *val;
struct node *next;
struct node *prev;
} node;
typedef struct list{
int size;
node *front;
node *back;
} list;
除了枚举变量和一些重要的结构,darknet.h中还有很多函数原形,函数原型是为了向编译器提供一些关于函数的特定信息,这样编译器就会记住函数的参数数量和类型以及返回值,这样编译器就可以检查后续的函数调用确保函数调用方式是正确的。通常函数原型都写到头文件中,因为这样原型的一份拷贝可以用在整个源文件,相比较于在函数调用前单独写一份函数原型要容易很多