l = parse_local(options, params);函数主体
local_layer parse_local(list *options, size_params params)
{
//设置网络参数
int n = option_find_int(options, "filters",1);
int size = option_find_int(options, "size",1);
int stride = option_find_int(options, "stride",1);
int pad = option_find_int(options, "pad",0);
char *activation_s = option_find_str(options, "activation", "logistic");
ACTIVATION activation = get_activation(activation_s);
int batch,h,w,c;
h = params.h;
w = params.w;
c = params.c;
batch=params.batch;
if(!(h && w && c)) error("Layer before local layer must output image.");
//创建local层
local_layer layer = make_local_layer(batch,h,w,c,n,size,stride,pad,activation);
return layer;
}
local_layer layer = make_local_layer(batch,h,w,c,n,size,stride,pad,activation);函数主体
local_layer make_local_layer(int batch, int h, int w, int c, int n, int size, int stride, int pad, ACTIVATION activation)
{
int i;
local_layer l = {0};//定义结构体local_layer l并初始化为0
l.type = LOCAL;//该网络层的名字
//设置输入特征图的参数
l.h = h;
l.w = w;
l.c = c;
l.n = n;
l.batch = batch;
l.stride = stride;
l.size = size;
l.pad = pad;
//设置输出特征图参数,
int out_h = local_out_height(l);
int out_w = local_out_width(l);
/*由于这里pad=1,stride=1所以运行后h不变
int local_out_height(local_layer l)
{
int h = l.h;
if (!l.pad) h -= l.size;
else h -= 1;
return h/l.stride + 1;
}
*/
//设置输出参数
int locations = out_h*out_w;
l.out_h = out_h;
l.out_w = out_w;
l.out_c = n;
l.outputs = l.out_h * l.out_w * l.out_c;
l.inputs = l.w * l.h * l.c;
//为权重分配空间,这里不再是使用卷积,所以权重参数多了很多,这里就可以看出卷积的好处了
l.weights = calloc(c*n*size*size*locations, sizeof(float));
l.weight_updates = calloc(c*n*size*size*locations, sizeof(float));
l.biases = calloc(l.outputs, sizeof(float));
l.bias_updates = calloc(l.outputs, sizeof(float));
// float scale = 1./sqrt(size*size*c);
// 初始化权重:缩放因子*标准均匀分布随机数(-1,1)之间,缩放因子等于sqrt(2./(size*size*c)),
float scale = sqrt(2./(size*size*c));
for(i = 0; i < c*n*size*size; ++i) l.weights[i] = scale*rand_uniform(-1,1);
l.output = calloc(l.batch*out_h * out_w * n, sizeof(float));//为该层所有的输出(包括mini-batch所有输入图片的输出)分配空间
l.delta = calloc(l.batch*out_h * out_w * n, sizeof(float));
l.workspace_size = out_h*out_w*size*size*c;//一个滤波器生成一个特征图的参数数量
//核心代码,设置前行后向和更新的卷积网络,令函数指针 l.forward l.backward l.update都设置指向函数,这里只是将函数指针指向函数入口地址,并不会运行,会在之后加载模型和网络是使用
l.forward = forward_local_layer;
l.backward = backward_local_layer;
l.update = update_local_layer;
#ifdef GPU//若是定义了GPU,则运行此处高效率代码
l.forward_gpu = forward_local_layer_gpu;
l.backward_gpu = backward_local_layer_gpu;
l.update_gpu = update_local_layer_gpu;
l.weights_gpu = cuda_make_array(l.weights, c*n*size*size*locations);
l.weight_updates_gpu = cuda_make_array(l.weight_updates, c*n*size*size*locations);
l.biases_gpu = cuda_make_array(l.biases, l.outputs);
l.bias_updates_gpu = cuda_make_array(l.bias_updates, l.outputs);
l.delta_gpu = cuda_make_array(l.delta, l.batch*out_h*out_w*n);
l.output_gpu = cuda_make_array(l.output, l.batch*out_h*out_w*n);
#endif
l.activation = activation;//设置激活函数
fprintf(stderr, "Local Layer: %d x %d x %d image, %d filters -> %d x %d x %d image\n", h,w,c,n, out_h, out_w, n);
return l;
}