本文主要是介绍【darknet】阅读理解(5)——batchnorm和activation,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. batchnorm
1.1 原理
大致的原理可以参考:https://blog.csdn.net/qq_25737169/article/details/79048516
如果了解个大概的话,就是:(x-均值)/ 偏差 * 缩放系数 + 一个偏置
1.2 darknet实现
说明:
- darknet cpu采用C实现的,能更有助于原理的理解
- 或者也可以用numpy等高级框架实现
总之,darknet的实现和想象中的实现还是有点区别的。关键的一句是:对channel之外的所有维度进行平均,所以,一个batch_norm有n个均值,方差,缩放系数,偏移值。n = 卷积核的个数。
1.3 具体实现和注释
1.batch_norm
void forward_batchnorm_layer(layer l, network net)
{if(l.type == BATCHNORM) copy_cpu(l.outputs*l.batch, net.input, 1, l.output, 1);copy_cpu(l.outputs*l.batch, l.output, 1, l.x, 1); // 将l.output copy到l.xif(net.train){mean_cpu(l.output, l.batch, l.out_c, l.out_h*l.out_w, l.mean); // 均值 // 对channel之外的所有维度进行平均,这里是模仿ANN的batchnorm对每个神经元归一化,CNN是对把每个卷积核当成了神经元variance_cpu(l.output, l.mean, l.batch, l.out_c, l.out_h*l.out_w, l.variance); // 方差 // 可参考https://www.zhihu.com/question/269658514scal_cpu(l.out_c, .99, l.rolling_mean, 1); // 初始化32个rolling_mean,保存全局的平均值,用于推理时axpy_cpu(l.out_c, .01, l.mean, 1, l.rolling_mean, 1); // 这里l.mean和l.roling_mean二者的位置是不是反了scal_cpu(l.out_c, .99, l.rolling_variance, 1); // 推理时用到的方差axpy_cpu(l.out_c, .01, l.variance, 1, l.rolling_variance, 1);normalize_cpu(l.output, l.mean, l.variance, l.batch, l.out_c, l.out_h*l.out_w); copy_cpu(l.outputs*l.batch, l.output, 1, l.x_norm, 1);} else {normalize_cpu(l.output, l.rolling_mean, l.rolling_variance, l.batch, l.out_c, l.out_h*l.out_w);}scale_bias(l.output, l.scales, l.batch, l.out_c, l.out_h*l.out_w); // scale,add,和normalize可以一起做,减少循环add_bias(l.output, l.biases, l.batch, l.out_c, l.out_h*l.out_w); // 偏置
}2. 求均值
void mean_cpu(float *x, int batch, int filters, int spatial, float *mean)
{float scale = 1./(batch * spatial); int i,j,k;for(i = 0; i < filters; ++i){ // 卷积核的个数mean[i] = 0;for(j = 0; j < batch; ++j){for(k = 0; k < spatial; ++k){int index = j*filters*spatial + i*spatial + k;mean[i] += x[index];}}mean[i] *= scale;}
}
2. activation
-
如果用numpy实现的话是一个高级函数的问题
np.maximum(x, 0)
-
darknet采用了一个for循环+内联函数实现,内联函数便于激活函数的同一格式,for循环(难道还有其他实现吗?)
1. for 循环
void activate_array(float *x, const int n, const ACTIVATION a)
{int i;for(i = 0; i < n; ++i){x[i] = activate(x[i], a); // 激活函数}
}2. 内联函数
static inline float leaky_activate(float x){return (x>0) ? x : .1*x;}
这篇关于【darknet】阅读理解(5)——batchnorm和activation的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!