deeplearning.ai学习笔记:第一课第三周

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cdknight_happy/article/details/84997267

1 神经网络的表示

在计算神经网络的层数时,一般不把输入层计算在内。如一个由输入层、单隐藏层、输出层组成的神经网络,一般叫做是两层的神经网络。
在这里插入图片描述
上述单隐藏神经元的神经网络,神经元要做两件事情,一是计算 z = w T x + b z = w^Tx+b ,即计算输入和权重的内积;二是应用非线性激活函数,计算 a = σ ( z ) a = \sigma(z) ,增强神经网络的表达能力。

在这里插入图片描述
对第一个隐藏层神经元,用矩阵进行计算表示:
z [ 1 ] z^{[1]} = [ w 1 [ 1 ] T w 2 [ 1 ] T w 3 [ 1 ] T w 4 [ 1 ] T ] \left[ \begin{matrix}-- & {w^{[1]}_1}^T & -- \\ -- & {w^{[1]}_2}^T & --\\ -- & {w^{[1]}_3}^T & --\\ -- & {w^{[1]}_4}^T & --\end{matrix} \right] [ x 1 x 2 x 3 ] \left[ \begin{matrix}x_1 \\ x_2 \\x_3\end{matrix} \right] + [ b 1 b 2 b 3 b 4 ] \left[ \begin{matrix}b_1 \\ b_2 \\b_3 \\b_4\end{matrix} \right] = [ w 1 [ 1 ] T x + b 1 w 2 [ 1 ] T x + b 2 w 3 [ 1 ] T x + b 3 w 4 [ 1 ] T x + b 4 ] \left[ \begin{matrix} {w^{[1]}_1}^Tx + b_1\\ {w^{[1]}_2}^Tx + b_2\\ {w^{[1]}_3}^Tx + b_3\\ {w^{[1]}_4}^Tx + b_4\end{matrix} \right] = [ z 1 [ 1 ] T z 2 [ 1 ] T z 3 [ 1 ] T z 4 [ 1 ] T ] \left[ \begin{matrix} {z^{[1]}_1}^T\\ {z^{[1]}_2}^T \\ {z^{[1]}_3}^T \\ {z^{[1]}_4}^T \end{matrix} \right]              w [ 1 ] , ( 4 , 3 )              ( 4 , 1 ) \\ ~\\ \\~~~~~~~~~~w^{[1]},(4,3)的矩阵 ~~~~~~~~~~~~(4,1)的向量

a [ 1 ] = σ ( z [ 1 ] ) \\a^{[1]} = \sigma(z^{[1]})

上述神经网络的计算过程用矩阵表示为:
在这里插入图片描述
多个样本的向量化计算:

m个样本,显式的for循环进行前向计算过程
在这里插入图片描述
使用向量化消除for循环,即将输入样本组成一个 ( n x , m ) (n_x,m) 的矩阵X, n x n_x 表示各输入样本的特征维度,m表示训练样本的总数目。即每一个样本变成一个列向量依次排列车矩阵。如下图所示。
在这里插入图片描述

那么,计算过程就变成了:
z [ 1 ] = w [ 1 ] X + b [ 1 ] a [ 1 ] = σ ( z [ 1 ] ) z [ 2 ] = w [ 2 ] z [ 1 ] + b [ 2 ] a [ 2 ] = σ ( z [ 2 ] ) z^{[1]} = w^{[1]}X + b^{[1]} \\a^{[1]} = \sigma(z^{[1]}) \\z^{[2]} = w^{[2]}z^{[1]} + b^{[2]} \\a^{[2]} = \sigma(z^{[2]})
在矩阵 X z [ 1 ] a [ 1 ] z [ 2 ] a [ 2 ] X,z^{[1]},a^{[1]},z^{[2]},a^{[2]} 中,不同的列表示不同的样本;同一列的不同行对应不同的隐藏神经元。

在这里插入图片描述
把X表示成 A [ 0 ] A^{[0]} ,可以看到神经网络就是重复进行下述两个计算过程:
Z [ i ] = W [ i ] A [ i 1 ] + b [ i ] Z^{[i]} = W^{[i]}A^{[i-1]}+b^{[i]}
A [ i ] = σ ( Z [ i ] ) A^{[i]} = \sigma(Z^{[i]})

2 激活函数

在这里插入图片描述

s i g m o i d ( x ) = 1 1 + e ( x ) sigmoid(x) = \frac{1}{1+e^{(-x)}} ,输出值范围(0,1);
  ~
t a n h ( x ) = e z e z e z + e z tanh(x) = \frac{e^z - e^{-z}}{e^z + e^{-z}} ,输出值范围(-1,1);

tanh(x)和sigmoid(x)是一个系列的激活函数,但是由于tanh(x)的中心点为0,对输入数据有类似于中心化的效果,使输入数据变换后的中心点为0,而不是sigmoid的中心点0.5,可以使得下一层的学习过程相对容易些,所以tanh一般要优于sigmoid。

现在几乎任何使用sigmoid函数的地方都可以使用tanh代替,但唯一的例外是二分类任务中,输出层的概率介于(0,1)之间是最好的结果,所以这是目前唯一一个还使用sigmoid函数的地方。除非用在二分类的输出层,否则绝对不要再使用sigmoid激活函数。

现在一般也不再使用sigmoid和tanh做激活函数了,因为,sigmoid(x)的对输入的导数为sigmoid(x) * (1 - sigmoid(x)),tanh(x)的导数为 1 ( t a n h ( x ) ) 2 1 - (tanh(x))^2 ,那么当输入值很大或很小时,sigmoid函数和tanh函数的导数都接近于0,如果神经网络的隐藏层使用了这样的激活函数,那么在梯度反向传播时, x z [ i ] = x a [ i ] \frac{\partial x}{\partial z^{[i]}} = \frac{\partial x}{\partial a^{[i]}} * 激活函数对 z [ i ] z^{[i]} 的导数,如果此时 z [ i ] z^{[i]} 的值很大或很小,那么激活函数对 z [ i ] z^{[i]} 的导数就接近于0,所以 x z [ i ] \frac{\partial x}{\partial z^{[i]}} 也接近于0,因此就阻碍了梯度往底层的传播,前面的层也就几乎停止了训练过程,这种现象称之为“梯度弥散”。这就是为什么目前主流神经网络都不再使用sigmoid和tanh作为激活函数的原因。

而sigmoid函数最“陡峭”的地方,即x=0处,梯度也只有0.25,也会减小反向传播的梯度值。而tanh在x=0处,梯度为1,对梯度的反向传播不会造成影响。

  ~
r e l u ( x ) = m a x ( 0 , x ) = { x , x 0 0 , x < 0 relu(x) = max(0,x) = \begin{cases} x,x\geq 0 \\ 0,x < 0 \end{cases}

relu目前是神经网络默认的隐藏层激活函数。

两个优点:

  • 输入值大于0时,激活函数的输出对输入的导数为1,不会造成梯度弥散,影响梯度的反向传播。实践证明,使用relu做激活函数,神经网络收敛速度比较快;
  • relu有一半区域为0,这样也增加了数据的稀疏性,减少了计算量。

一个缺点:
如果输入值为负值,则输出为0,这样对负的输入值无法进行梯度反向传播。

一个要解释的点:
严格来说Relu函数并非全部可导, x = 0 x = 0 处左右导数不相等。但是因为我们输入值无限接近于0的可能性很小,因此这个问题一般都忽略不计。

  ~
l e a k y   r e l u ( x ) = { x , x 0 0.01 x , x < 0 leaky~relu(x) = \begin{cases} x , x \geq 0 \\ 0.01x,x < 0 \end{cases}

leaky relu为解决relu的缺点而提出的。输入为负时,也可以进行梯度的前传,只是相对正值输入的梯度要小一些。

  ~
p r e l u ( x ) = { x , x 0 α x , x < 0 prelu(x) = \begin{cases} x , x \geq 0 \\ \alpha x,x < 0 \end{cases}
α \alpha 可以作为一个参数进行学习。prelu是leaky relu的泛化版本,增加了一个参数,但相比leaky relu提升有限。

为什么要使用非线性激活函数?
如果使用线性函数作为激活函数,因为线性函数的乘积任然是线性函数,那么无论神经网络有多深,输出都是输入的线性变换,这样和单层的线性激活函数是没有区别的,这样是没有任何意义的。只有使用非线性激活函数,才可以使神经网络学到有趣的变换,也才能完成一些有趣的应用。

唯一有可能需要线性激活函数的地方是,对于回归问题,输出是倒数第二层的输出的线性变换,此时用线性激活函数是合理的。

3 神经网络的梯度下降

在这里插入图片描述
二分类任务,假设输入样本为 n x n_x 个单元,隐藏层有 n 1 n_1 个单元,输出层有 n 2 n_2 个单元。因此对单个样本而言, x R n x × 1 , W [ 1 ] R n 1 × n x , b [ 1 ] R n 1 × 1 z [ 1 ] R n 1 × 1 a [ 1 ] R n 1 × 1 , W [ 2 ] R n 2 × n 1 , b [ 2 ] R n 2 × 1 z [ 2 ] R n 2 × 1 a [ 2 ] R n 2 × 1 y R n 2 × 1 x \in R^{n_x \times1},W^{[1]} \in R^{n_1 \times n_x},b^{[1]} \in R^{n_1 \times 1},z^{[1]} \in R^{n_1 \times 1},a^{[1]} \in R^{n_1 \times 1},W^{[2]} \in R^{n_2 \times n_1},b^{[2]} \in R^{n_2 \times 1},z^{[2]} \in R^{n_2 \times 1},a^{[2]} \in R^{n_2 \times 1},y \in R^{n_2 \times 1}
对于单个样本而言,其反向传播的梯度为:
d z [ 2 ] = a [ 2 ] y dz^{[2]} = a^{[2]} - y
d W [ 2 ] = d z [ 2 ] a [ 1 ] T dW^{[2]} = dz^{[2]}{a^{[1]}}^T (之所以转置是因为 d W [ 2 ] R n 2 × n 1 dW^{[2]} \in R^{n_2 \times n_1} ,而这里 z [ 2 ] z^{[2]} a [ 1 ] a^{[1]} 都是列向量,需要将 a [ 1 ] a^{[1]} 转置才可以计算外积得到矩阵)
d b [ 2 ] = d z [ 2 ] db^{[2]} = dz^{[2]}
d a [ 1 ] = W [ 2 ] T d z [ 2 ] da^{[1]} = {W^{[2]}}^Tdz^{[2]}
d z [ 1 ] = d a [ 1 ] g [ 1 ] ( z [ 1 ] ) dz^{[1]} = da^{[1]} * {g^{[1]}}^{'}(z^{[1]}) (这里的“*”表示逐元素相乘)
d W [ 1 ] = d z [ 1 ] x T dW^{[1]} = dz^{[1]}x^T
d b [ 1 ] = d z [ 1 ] db^{[1]} = dz^{[1]}

m个样本,向量化之后为:
X R n x × m , W [ 1 ] R n 1 × n x , b [ 1 ] R n 1 × 1 Z [ 1 ] R n 1 × m A [ 1 ] R n 1 × m , W [ 2 ] R n 2 × n 1 , b [ 2 ] R n 2 × 1 Z [ 2 ] R n 2 × m A [ 2 ] R n 2 × m Y R n 2 × m X \in R^{n_x \times m},W^{[1]} \in R^{n_1 \times n_x},b^{[1]} \in R^{n_1 \times 1},Z^{[1]} \in R^{n_1 \times m},A^{[1]} \in R^{n_1 \times m},W^{[2]} \in R^{n_2 \times n_1},b^{[2]} \in R^{n_2 \times 1},Z^{[2]} \in R^{n_2 \times m},A^{[2]} \in R^{n_2 \times m},Y \in R^{n_2 \times m}

d Z [ 2 ] = A [ 2 ] Y dZ^{[2]} = A^{[2]} - Y
d W [ 2 ] = 1 m d z [ 2 ] A [ 1 ] T dW^{[2]} = \frac{1}{m}dz^{[2]}{A^{[1]}}^T (之所以有 1 m \frac{1}{m} 是因为计算损失函数时包含了 1 m \frac{1}{m} )
d b [ 2 ] = 1 m n p . s u m ( d Z [ 2 ] , a x i s = 1 , k e e p d i m s = T r u e ) db^{[2]} = \frac{1}{m}np.sum(dZ^{[2]},axis=1,keepdims = True) (使用keepdims = True是为了保障输出形状为( n 2 n_2 ,1),而不是( n 2 n_2 ,),更容易计算)
d A [ 1 ] = W [ 2 ] T d Z [ 2 ] dA^{[1]} = {W^{[2]}}^TdZ^{[2]}
d Z [ 1 ] = d A [ 1 ] g [ 1 ] ( Z [ 1 ] ) dZ^{[1]} = dA^{[1]} * {g^{[1]}}^{'}(Z^{[1]}) (这里的“*”表示逐元素相乘)
$dW^{[1]} = 1 m d Z [ 1 ] X T \frac{1}{m}dZ^{[1]}X^T
d b [ 1 ] = 1 m n p . s u m ( d Z [ 1 ] , a x i s = 1 , k e e p d i m s = T r u e ) db^{[1]} = \frac{1}{m}np.sum(dZ^{[1]},axis=1,keepdims = True)
在这里插入图片描述

4 权重随机初始化

如果同一层的不同神经元具有相同的初始化参数,那么前向计算时,该层的不同神经元具有相同的输出。同样,多次梯度下降更新之后不同的神经元依然具有相同的参数,这种情况下,无论某一隐藏层有多少神经元,它们都是在学习相同的参数。这种对称性对神经网络的学习是相当不利的,我们还是希望不同的神经元去学习不同的函数。

因此,正确的权重初始化策略是使用随机初始化以破坏对称性。

w = np.random.randn((n_1,n_x)) * 0.01,b=np.zeros((n_1,1))。

  • 一般权重进行随机初始化,偏置b还是初始化为0;
  • 权重一般会随机初始化为比较小的值,之所以这样是因为,若使用sigmoid/tanh做激活函数,太大的权重易于使得输出进入函数饱和区,造成梯度弥散阻碍梯度反向传播;即便使用relu系的激活函数,不会出现梯度弥散现象,使用比较大的初始化权重也更容易破坏对称性。但是,比较大的初始化权重也易于造成梯度值比较大,称之为梯度爆炸,当然梯度爆炸可以通过梯度截断来缓解。

总之,一般对权重进行比较小的随机初始化,偏置项初始化为0.

猜你喜欢

转载自blog.csdn.net/cdknight_happy/article/details/84997267
今日推荐