深度学习21天实战Caffe学习笔记--笔记3--caffe代码梳理

来源:互联网 发布:最高人民法院网络拍卖 编辑:程序博客网 时间:2024/06/05 22:51

Caffe代码梳理

1. 卷积层

(1)信号处理中的卷积:

    以一维情况为例,信号处理中使用的卷积为:

设:f(x),g(x)是R1上的两个可积函数,则卷积f(x)*g(x)定义为:


    可以看出,卷积计算时对一个信号需要进行翻转。


图像处理和caffe中的卷积:

    图像处理中使用的卷积是离散形式的二维卷积,具体公式为



(2).定义卷积时为什么要对其中一个函数进行翻转

参考链接:http://www.zhihu.com/question/20500497

    对于信号x(n)和卷积核h(n),先明确如下概念:h(0)表示系统在当前时刻对于单位输入信号的响应,h(1)表示系统在下一时刻对于单位输入信号的响应,h(2)表示系统在下下时刻对于单位输入信号的响应。则在n时刻系统的响应为y(N)=x(N)*h(0)+ x(N-1)*h(1)+x(N-2)*h(2)+…+x(0)*h(N);这就是离散形式卷积公式。

    直观来看,并不是说要对卷积核进行翻转,而是说需要描述以前时刻对于当前时刻的影响。


参考:深度学习基础_TJU_刘昕

    


(3).卷积和相关的区别

    相关是两个时间序列(频域的当然也可以)相似的程度(这个相似程度不仅包含表示幅度这方面的形状表示幅度这方面的形状,还包含持还包含持续时间这方面的起始终止续时间这方面的起始终止),当两个信号形状一样且起始终止时刻一模一样时状一样且起始终止时刻一模一样时,其相关性是最高的。

    卷积描述的是系统对于输入信号的响应。

    计算相关时,无需翻转;计算卷积时,卷积核必须翻转。


2. 全连接层

    卷积层到全连接层之间是普通的神经网络连接,即输入层与输出层的神经元两两互联。

    在卷积神经网络中,卷积层一般计算量大,但参数数目较少;全连接层参数数目多,计算量少。


3. 激活函数

    激活函数用于对,来自前一层输入线性组合的结果进行非线性变换。

(1)误差反向传到过程中梯度消失问题。

在神经网络进行误差反向传播时,每一层都需要乘以激活函数的一阶导数,。对于绝大部分激活函数,,尤其是对于sigmoid函数,,在这种情况下,经过几层传播之后会存在严重的梯度消失问题。而ReLU函数,一阶导数为1,使用这类非饱和函数可以比较有效地解决问题。

在目前研究中,人们使用新的网络结构来进一步避免梯度消失问题,如高速公路网络(highway network)和深度残差学习(deep residual learning)等。


4. caffe中ReLU激活函数的声明和实现代码导读

声明文件:

//ReLULayer派生于NeuronLayer
template <typename Dtype>
class ReLULayer : public NeuronLayer<Dtype> {
public:
//显式构造函数
explicit ReLULayer(const LayerParameter& param)
: NeuronLayer<Dtype>(param) {}
//虚函数,将函数的绑定推迟
virtual inline const char* type() const { return "ReLU"; }
protected:
//前向传播
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
//反向传播
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
};


实现文件:



template <typename Dtype>
void ReLULayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  //(只读)获取输入blob的data指针
  const Dtype* bottom_data = bottom[0]->cpu_data();
  //(读写)获取输出blob的data指针
  Dtype* top_data = top[0]->mutable_cpu_data();
  //获取输入blob元素个数
  const int count = bottom[0]->count();
  //参数,从layer_param_中获得,默认为0,即普通ReLU
  Dtype negative_slope = this->layer_param_.relu_param().negative_slope();
  //执行ReLU操作
  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]) {
    //(只读)获取下一层的data指针
    const Dtype* bottom_data = bottom[0]->cpu_data();
//(只读)获取上一层的diff指针
    const Dtype* top_diff = top[0]->cpu_diff();
//(只读)获取下一层的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));
    }
  }
}

    




疑惑:

1. 离散形式的二维卷积公式对不对?

2. 卷积与相关的区别

3. caffe中前向计算过程是卷积,误差求导是卷积,卷基层梯度更新也是卷积,为什么卷积功能这么强大?

4. 为便于运算,将卷积转换为向量相乘,如何理解?



0 0
原创粉丝点击