【Python实现卷积神经网络】:激活层RELU的正向与反向传播+python实现代码

1.神经网络激活函数介绍

1.1 为什么使用激活函数

  首先摆结论,因为线性模型的表达能力不够,引入激活函数是为了添加非线性因素。(知乎回答1解释了这句话。)

  简单来说就是如下图所示没有激活函数时,我们的整个网络还是线性的。当我们的输出需要拟合曲线时,我们只能通过更多的线性函数去逼近曲线:

这里写图片描述

  而如果我们在每层网络中加入非线性函数如sigmoid函数之后,可以拟合出曲线:

这里写图片描述

激活函数通常有如下一些性质: 2

  • 非线性:当激活函数是线性的时候,一个两层的神经网络就可以逼近基本上所有的函数了。但是,如果激活函数是恒等激活函数的时候(即f(x)=x),就不满足这个性质了,而且如果MLP使用的是恒等激活函数,那么其实整个网络跟单层神经网络是等价的。

  • 可微性:当优化方法是基于梯度的时候,这个性质是必须的。

  • 单调性:当激活函数是单调的时候,单层网络能够保证是凸函数。

  • 激活函数输出约等于输入【f(x)≈x】:当激活函数满足这个性质的时候,如果参数的初始化是random的很小的值,那么神经网络的训练将会很高效;如果不满足这个性质,那么就需要很用心的去设置初始值。

  • 输出值的范围:当激活函数输出值是有限的时候,基于梯度的优化方法会更加 稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是无限的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的learning rate。

1.2 常用的激活函数

  该部分需要一篇专门的文章【卷积神经网络专题】:6.激活函数来介绍,这里先引用其他博主的介绍:

  各个激活函数的用的地方:https://blog.csdn.net/leo_xu06/article/details/53708647
  各个激活函数的优缺点:https://blog.csdn.net/Jaster_wisdom/article/details/78380839

2.Relu函数的正向传播

Relu 的图像如下:

这里写图片描述

Relu 的公式如下:

Relu(x)={x,0,x>0x0 R e l u ( x ) = { x , x > 0 0 , x ≤ 0

Relu正向传播的python-numpy代码如下:

in_data[in_data<0] = 0

3.Relu函数的反向传播

3.1 反向传播公式:

  其在x=0处是不可微的,但是在深度学习框架的代码中为了解决这个直接将其在x=0处的导数置为1,所以它的导数也就变为了 :
  

δRelu(x)={1,0,x>0x0 δ R e l u ( x ) = { 1 , x > 0 0 , x ≤ 0

3.2反向传播python-numpy代码:

return (self.top_val > 0) * residual                                    
# (self.top_val > 0)表示大于0的为1,不大于0的为0;为relu对输入导数

4.Relu的优点

  1. relu的稀疏性(激活函数的作用);
  2. 还是防止梯度弥散(也叫作梯度消失,是针对sigmoid函数这一缺点的);3
  3. 加快计算(正反向传播代码好实现)

下面展开叙述:4

首先我们看下sigmoid和relu的曲线

这里写图片描述

然后可以得到sigmoid的导数

这里写图片描述

以及relu的导数

这里写图片描述

结论:

  1.sigmoid的导数只有在0附近的时候有比较好的激活性,在正负饱和区的梯度都接近于0,所以这会造成梯度弥散,而relu函数在大于0的部分梯度为常数,所以不会产生梯度弥散现象
  
  2.relu函数在负半区的导数为0 ,所以一旦神经元激活值进入负半区,那么梯度就会为0,也就是说这个神经元不会经历训练,即所谓的稀疏性
  
  3.relu函数的导数计算更快,程序实现就是一个if-else语句,而sigmoid函数要进行浮点四则运算。

反向传播算法中的 BPTT(Backpropagation Through Time,透过时间反向传播)方法主要用来训练循环神经网络(RNN)。BPTT算法的基本思想是将RNN展开成一个非循环的前馈神经网络,然后使用标准的反向传播算法进行训练。 在BPTT算法中,我们将一个长度为T的输入序列$x_{1:T}=(x_1,x_2,...,x_T)$传入RNN,得到一个长度为T的输出序列$y_{1:T}=(y_1,y_2,...,y_T)$。假设我们的RNN有L,其中第l包含$h_l$个隐藏单元,则我们可以将其表示为: $h_t^{(l)}=f(W_{xh}^{(l)}x_t+W_{hh}^{(l)}h_{t-1}^{(l)}+b_h^{(l)})$ 其中,$W_{xh}^{(l)}$、$W_{hh}^{(l)}$和$b_h^{(l)}$分别表示第l的输入权重矩阵、隐藏状态权重矩阵和偏置向量。$f$是激活函数,通常采用Tanh或ReLU函数。 得到每一时刻的隐藏状态后,我们可以计算输出$y_t$: $y_t=W_{hy}h_t^{(L)}+b_y$ 其中,$W_{hy}$和$b_y$是输出的权重矩阵和偏置向量。 BPTT算法的目标是最小化输出序列$y_{1:T}$与目标序列$y_{1:T}^*$之间的误差。假设我们使用平方误差作为损失函数,则损失函数为: $L=\frac{1}{2}\sum_{t=1}^T\|y_t-y_t^*\|^2$ 接下来,我们需要计算每个参数对损失函数的梯度,然后使用梯度下降算法进行更新。为了计算梯度,我们需要使用链式法则对网络中的每个参数求偏导数。 具体地,我们以权重矩阵$W_{hy}$为例,假设$t=T$时,损失函数$L$对输出$y_T$的偏导数为: $\frac{\partial L}{\partial y_T}=y_T-y_T^*$ 然后,我们可以使用链式法则依次计算出$L$对每一时刻的隐藏状态$h_t^{(L)}$、每一的权重矩阵$W_{hh}^{(l)}$和$W_{xh}^{(l)}$,以及每一的偏置向量$b_h^{(l)}$和输出的偏置向量$b_y$的偏导数。 最后,我们可以根据每个参数的偏导数使用梯度下降算法进行更新。 需要注意的是,由于RNN的展开长度可能非常长,因此在实际应用中,我们通常采用BPTT的截断版本,即只计算一部分时刻的梯度,而不是对整个序列进行计算。这样可以有效地减少计算量,同时还可以防止梯度消失或爆炸的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值