本系列为darknet源码解析,本次解析为src/l2norm_layer.h 和 src/l2norm_layer.c 两个,l2norm_layer主要是完成在每个batch对每个通道进行l2标准化操作;
正向传播:
反向传播:
如果,则, 否则 ,这与源码上的反传存在差入;
l2norm_layer.h的详细定义如下:
#ifndef L2NORM_LAYER_H
#define L2NORM_LAYER_H
#include "layer.h"
#include "network.h"
// 构建l2标准化层
layer make_l2norm_layer(int batch, int inputs);
// l2标准化层的前向,反向传播函数
void forward_l2norm_layer(const layer l, network net);
void backward_l2norm_layer(const layer l, network net);
#ifdef GPU
void forward_l2norm_layer_gpu(const layer l, network net);
void backward_l2norm_layer_gpu(const layer l, network net);
#endif
#endif
l2norm_layer.c 的详细解析
#include "l2norm_layer.h"
#include "activations.h"
#include "blas.h"
#include "cuda.h"
#include
#include
#include
#include
#include
/**
* 构造l2标准化层
* @param batch
* @param inputs
* @return
*/
layer make_l2norm_layer(int batch, int inputs)
{
fprintf(stderr, "l2norm %4d\n", inputs);
layer l = {0};
l.type = L2NORM; // 层类别
l.batch = batch; // 一个batch包含图片的张数
l.inputs = inputs; // l2norm_layer层一张输入图片元素的个数
l.outputs = inputs; // l2norm_layer层对应输入图片的输出元素的个数,
l.output = calloc(inputs*batch, sizeof(float)); // l2norm_layer 所有输出(包含整个batch的)
l.scales = calloc(inputs*batch, sizeof(float)); //
l.delta = calloc(inputs*batch, sizeof(float)); // l2norm_layer 误差项(包含整个batch的)
l.forward = forward_l2norm_layer; // l2norm_layer 前向传播
l.backward = backward_l2norm_layer; // l2norm_layer 反向传播
#ifdef GPU
l.forward_gpu = forward_l2norm_layer_gpu;
l.backward_gpu = backward_l2norm_layer_gpu;
l.output_gpu = cuda_make_array(l.output, inputs*batch);
l.scales_gpu = cuda_make_array(l.output, inputs*batch);
l.delta_gpu = cuda_make_array(l.delta, inputs*batch);
#endif
return l;
}
// l2normalize_cpu(l.output, l.scales, l.batch, l.out_c, l.out_w*l.out_h);
void l2normalize_cpu(float *x, float *dx, int batch, int filters, int spatial)
{
int b,f,i;
for(b = 0; b < batch; ++b){ //遍历每一张图片
for(i = 0; i < spatial; ++i){ //遍历每一个通道上的所有元素
float sum = 0;
for(f = 0; f < filters; ++f){ // 遍历所有通道
int index = b*filters*spatial + f*spatial + i;
sum += powf(x[index], 2); // 计算每个batch中,每个像素点所有通道上平方和
}
sum = sqrtf(sum);//计算二范数
for(f = 0; f < filters; ++f){
int index = b*filters*spatial + f*spatial + i;
x[index] /= sum; //对每个元素进行l2标准化
dx[index] = (1 - x[index]) / sum; // 计算反传梯度
}
}
}
}
/**
* l2norm前向传播函数
* @param l 当前l2norm层
* @param net 整个网络
*/
void forward_l2norm_layer(const layer l, network net)
{
// l.output = net.input 初始化操作
copy_cpu(l.outputs*l.batch, net.input, 1, l.output, 1);
l2normalize_cpu(l.output, l.scales, l.batch, l.out_c, l.out_w*l.out_h);
}
void backward_l2norm_layer(const layer l, network net)
{
// l.delta = l.scales 多出一个l.scales奇葩;
axpy_cpu(l.inputs*l.batch, 1, l.scales, 1, l.delta, 1);
// net.data = l.delta
axpy_cpu(l.inputs*l.batch, 1, l.delta, 1, net.delta, 1);
}
#ifdef GPU
void forward_l2norm_layer_gpu(const layer l, network net)
{
copy_gpu(l.outputs*l.batch, net.input_gpu, 1, l.output_gpu, 1);
l2normalize_gpu(l.output_gpu, l.scales_gpu, l.batch, l.out_c, l.out_w*l.out_h);
}
void backward_l2norm_layer_gpu(const layer l, network net)
{
axpy_gpu(l.batch*l.inputs, 1, l.scales_gpu, 1, l.delta_gpu, 1);
axpy_gpu(l.batch*l.inputs, 1, l.delta_gpu, 1, net.delta_gpu, 1);
}
#endif
完,