l = parse_reorg(options, params);
layer parse_reorg(list *options, size_params params)
{
//设置参数
int stride = option_find_int(options, "stride",1);
int reverse = option_find_int_quiet(options, "reverse",0);
int flatten = option_find_int_quiet(options, "flatten",0);
int extra = option_find_int_quiet(options, "extra",0);
int batch,h,w,c;
h = params.h;
w = params.w;
c = params.c;
batch=params.batch;
if(!(h && w && c)) error("Layer before reorg layer must output image.");
//设置网络层
layer layer = make_reorg_layer(batch,w,h,c,stride,reverse, flatten, extra);
return layer;
}
layer layer = make_reorg_layer(batch,w,h,c,stride,reverse, flatten, extra);
layer make_reorg_layer(int batch, int w, int h, int c, int stride, int reverse, int flatten, int extra)
{
layer l = {0};
l.type = REORG;
l.batch = batch;
l.stride = stride;
l.extra = extra;
l.h = h;
l.w = w;
l.c = c;
l.flatten = flatten;
//根据reverse获取输出特征图尺寸和通道
if(reverse){
l.out_w = w*stride;
l.out_h = h*stride;
l.out_c = c/(stride*stride);
}else{
l.out_w = w/stride;
l.out_h = h/stride;
l.out_c = c*(stride*stride);
}
l.reverse = reverse;
//输出大小
l.outputs = l.out_h * l.out_w * l.out_c;
l.inputs = h*w*c;
if(l.extra){
l.out_w = l.out_h = l.out_c = 0;
l.outputs = l.inputs + l.extra;
}
if(extra){
fprintf(stderr, "reorg %4d -> %4d\n", l.inputs, l.outputs);
} else {
fprintf(stderr, "reorg /%2d %4d x%4d x%4d -> %4d x%4d x%4d\n", stride, w, h, c, l.out_w, l.out_h, l.out_c);
}
//一个batch输出大小
int output_size = l.outputs * batch;
l.output = calloc(output_size, sizeof(float));
l.delta = calloc(output_size, sizeof(float));
l.forward = forward_reorg_layer;//前向网络层
l.backward = backward_reorg_layer;//反向传播
#ifdef GPU
l.forward_gpu = forward_reorg_layer_gpu;
l.backward_gpu = backward_reorg_layer_gpu;
l.output_gpu = cuda_make_array(l.output, output_size);
l.delta_gpu = cuda_make_array(l.delta, output_size);
#endif
return l;
}
l.forward = forward_reorg_layer;//前向网络层
void forward_reorg_layer(const layer l, network net)
{
int i;
if(l.flatten){
memcpy(l.output, net.input, l.outputs*l.batch*sizeof(float));
if(l.reverse){
flatten(l.output, l.w*l.h, l.c, l.batch, 0);
}else{
flatten(l.output, l.w*l.h, l.c, l.batch, 1);
}
} else if (l.extra) {
for(i = 0; i < l.batch; ++i){
copy_cpu(l.inputs, net.input + i*l.inputs, 1, l.output + i*l.outputs, 1);
}
} else if (l.reverse){
reorg_cpu(net.input, l.w, l.h, l.c, l.batch, l.stride, 1, l.output);
} else {//执行此步
reorg_cpu(net.input, l.w, l.h, l.c, l.batch, l.stride, 0, l.output);
}
}
//具体可查看博客https://blog.youkuaiyun.com/qq_17550379/article/details/78948839
void reorg_cpu(float *x, int w, int h, int c, int batch, int stride, int forward, float *out)
{
int b,i,j,k;
int out_c = c/(stride*stride);
for(b = 0; b < batch; ++b){
for(k = 0; k < c; ++k){
for(j = 0; j < h; ++j){
for(i = 0; i < w; ++i){
int in_index = i + w*(j + h*(k + c*b));
int c2 = k % out_c;
int offset = k / out_c;
int w2 = i*stride + offset % stride;
int h2 = j*stride + offset / stride;
int out_index = w2 + w*stride*(h2 + h*stride*(c2 + out_c*b));
if(forward) out[out_index] = x[in_index];
else out[in_index] = x[out_index];
}
}
}
}
}
void backward_reorg_layer(const layer l, network net)
{
int i;
if(l.flatten){
memcpy(net.delta, l.delta, l.outputs*l.batch*sizeof(float));
if(l.reverse){
flatten(net.delta, l.w*l.h, l.c, l.batch, 1);
}else{
flatten(net.delta, l.w*l.h, l.c, l.batch, 0);
}
} else if(l.reverse){
reorg_cpu(l.delta, l.w, l.h, l.c, l.batch, l.stride, 0, net.delta);
} else if (l.extra) {
for(i = 0; i < l.batch; ++i){
copy_cpu(l.inputs, l.delta + i*l.outputs, 1, net.delta + i*l.inputs, 1);
}
}else{
reorg_cpu(l.delta, l.w, l.h, l.c, l.batch, l.stride, 1, net.delta);
}
}