Caffe源码解析6:Neuron_Layer
2017-07-17 12:05
507 查看
转自楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/
NeuronLayer,顾名思义这里就是神经元,激活函数的相应层。我们知道在blob进入激活函数之前和之后他的size是不会变的,而且激活值也就是输出 yy 只依赖于相应的输入 xx。在Caffe里面所有的layer的实现都放在src文件夹下的layer文件夹中,基本上很多文章里应用到的layer类型它都有cpu和cuda的实现。在caffe里面NeuronLayer比较多,在此罗列了一下
AbsValLayer
BNLLLayer
DropoutLayer
ExpLayer
LogLayer
PowerLayer
ReLULayer
CuDNNReLULayer
SigmoidLayer
CuDNNSigmoidLayer
TanHLayer
CuDNNTanHLayer
ThresholdLayer
PReLULayer
Caffe里面的Neuron种类比较多方便人们使用,这里我们着重关注几个主要的Neuro_layer
ReLULayer
目前在激活层的函数中使用ReLU是非常普遍的,一般我们在看资料或者讲义中总是提到的是Sigmoid函数,它比Sigmoid有更快的收敛性,因为sigmoid在收敛的时候越靠近目标点收敛的速度会越慢,也是其函数的曲线形状决定的。而ReLULayer则相对收敛更快,具体可以看Krizhevsky 12年的那篇ImageNet CNN文章有更详细的介绍。其计算的公式是:
y=max(0,x)y=max(0,x)
如果有负斜率式子变为:
y=max(0,x)+νmin(0,x)y=max(0,x)+νmin(0,x)
反向传播的公式
∂E∂x=⎧⎩⎨ν∂E∂y∂E∂yifx≤0ifx>0∂E∂x={ν∂E∂yifx≤0∂E∂yifx>0
其在cafffe中的forward和backward函数为
template <typename Dtype> void ReLULayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); const int count = bottom[0]->count(); Dtype negative_slope = this->layer_param_.relu_param().negative_slope(); for (int i = 0; i < count; ++i) { top_data[i] = std::max(bottom_data[i], Dtype(0)) + negative_slope * std::min(bottom_data[i], Dtype(0)); } } template <typename Dtype> void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { if (propagate_down[0]) { const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); const int count = bottom[0]->count(); Dtype negative_slope = this->layer_param_.relu_param().negative_slope(); for (int i = 0; i < count; ++i) { bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0) + negative_slope * (bottom_data[i] <= 0)); } } }
SigmoidLayer
Sigmoid函数,也称为阶跃函数,函数曲线是一个优美的S形。目前使用Sigmoid函数已经不多了,大多使用ReLU来代替,其对应的激活函数为:y=(1+exp(−x))−1y=(1+exp(−x))−1
其反向传播时
∂E∂x=∂E∂yy(1−y)∂E∂x=∂E∂yy(1−y)
其相应的forward和backward的函数为
template <typename Dtype> void SigmoidLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); const int count = bottom[0]->count(); for (int i = 0; i < count; ++i) { top_data[i] = sigmoid(bottom_data[i]); } } template <typename Dtype> void SigmoidLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { if (propagate_down[0]) { const Dtype* top_data = top[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); const int count = bottom[0]->count(); for (int i = 0; i < count; ++i) { const Dtype sigmoid_x = top_data[i]; bottom_diff[i] = top_diff[i] * sigmoid_x * (1. - sigmoid_x); } } }
DropoutLayer
DropoutLayer现在是非常常用的一种网络层,只用在训练阶段,一般用在网络的全连接层中,可以减少网络的过拟合问题。其思想是在训练过程中随机的将一部分输入x之置为0。ytrain={x1−p0if u>potherwiseytrain={x1−pif u>p0otherwise
其forward_cpu和backward_cpu为:
template <typename Dtype> void DropoutLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); unsigned int* mask = rand_vec_.mutable_cpu_data(); const int count = bottom[0]->count(); if (this->phase_ == TRAIN) { // Create random numbers构造随机数,这里是通过向量掩码来和bottom的数据相乘,scale_是控制undropped的比例 caffe_rng_bernoulli(count, 1. - threshold_, mask); for (int i = 0; i < count; ++i) { top_data[i] = bottom_data[i] * mask[i] * scale_; } } else { caffe_copy(bottom[0]->count(), bottom_data, top_data); } } template <typename Dtype> void DropoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { if (propagate_down[0]) { const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); if (this->phase_ == TRAIN) { const unsigned int* mask = rand_vec_.cpu_data(); const int count = bottom[0]->count(); for (int i = 0; i < count; ++i) { bottom_diff[i] = top_diff[i] * mask[i] * scale_; } } else { caffe_copy(top[0]->count(), top_diff, bottom_diff); } } }
相关文章推荐
- Caffe源码解析6:Neuron_Layer
- Caffe源码解析6:Neuron_Layer
- Caffe源码解析6:Neuron_Layer
- Caffe源码解析4: Data_layer
- Caffe源码解析4: Data_layer
- caffe源码解析之添加新的Layer(maxout)
- Caffe源码解析3:Layer
- caffe源码解析-BaseConvolutionLayer
- Caffe源码解析2:Layer
- Caffe源码解析4: Data_layer
- Caffe源码解析5:Conv_Layer
- 代码笔记:caffe-reid中PairEuclideanLayer源码解析
- caffe源码解析之Layer层(1)
- Caffe源码解析3:Layer
- Caffe源码解析4: Data_layer
- Caffe源码解析7:Pooling_Layer
- 代码笔记:caffe-reid中reid_data_layer源码解析
- [Caffe]源码解析之Layer
- Caffe源码解析5:Conv_Layer
- Caffe源码解析3: Data_layer