深入理解吴恩达深度学习(01神经网络和深度学习 第三周 单隐藏层神经网络)
- 1引言
- 第三周:浅层神经网络(Shallow neural networks)
- 3.1 神经网络概述(Neural Network Overview)
- 3.2 神经网络的表示(Neural Network Representation)
- 3.3 计算一个神经网络的输出(Computing a Neural Network's output)
- 3.4 多样本向量化(Vectorizing across multiple examples)
- 3.6 激活函数(Activation functions)
- 3.7 为什么需要非线性激活函数?(why need a nonlinear activation function?)
- 3.8 神经网络的梯度下降(Gradient descent for neural networks)
- 3.10(选修)直观理解反向传播(Backpropagation intuition)
- 3.11 随机初始化(Random+Initialization)
1引言
大家好,我是博主斌斌,一个27岁的java攻城狮,最近想转行人工智能,最近我发现了斯坦福大学吴恩达老师的深度学习微专业讲的特别好,不过可能还会有不少难以理解的地方。本人才疏学浅,想尽量将课程中的重要知识点用自己能够理解的方式记录下来,希望能够在帮助自己的同时也能够帮助别人。
废话不多说了,这里给出免费的课程地址:
内容 | 链接 |
---|---|
吴恩达深度学习 | 课程地址 |
深度学习上课内容 | 内容地址 |
深度学习课后作业 | 课后作业地址 |
第三周:浅层神经网络(Shallow neural networks)
文章目录
- 1引言
- 第三周:浅层神经网络(Shallow neural networks)
- 3.1 神经网络概述(Neural Network Overview)
- 3.2 神经网络的表示(Neural Network Representation)
- 3.3 计算一个神经网络的输出(Computing a Neural Network's output)
- 3.4 多样本向量化(Vectorizing across multiple examples)
- 3.6 激活函数(Activation functions)
- 3.7 为什么需要非线性激活函数?(why need a nonlinear activation function?)
- 3.8 神经网络的梯度下降(Gradient descent for neural networks)
- 3.10(选修)直观理解反向传播(Backpropagation intuition)
- 3.11 随机初始化(Random+Initialization)
3.1 神经网络概述(Neural Network Overview)
3.1.1 逻辑回归回顾
在描述神经网络之前,我们学习了逻辑回归,下面复习一下逻辑回归。
图3.1.1 :
公式3.1:
x
w
b
}
  
⟹
  
z
=
w
T
x
+
b
\left. \begin{array}{l} x\\ w\\ b \end{array} \right\} \implies{z={w}^Tx+b}
xwb⎭⎬⎫⟹z=wTx+b
如上所示,首先你需要输入特征
x
x
x,参数
w
w
w和
b
b
b,通过这些你就可以计算出
z
z
z,公式3.2:
x
w
b
}
  
⟹
  
z
=
w
T
x
+
b
  
⟹
  
α
=
σ
(
z
)
  
⟹
  
L
(
a
,
y
)
  
⟹
  
L
(
a
,
y
)
=
−
y
log
(
a
)
−
(
1
−
y
)
log
(
1
−
a
)
\left. \begin{array}{l} x\\ w\\ b \end{array} \right\} \implies{z={w}^Tx+b} \implies{\alpha = \sigma(z)}\\ \implies{{L}(a,y)}\\ \\ \implies{L\left(a,y \right)=-y\log(a)-(1-y)\log (1-a)}
xwb⎭⎬⎫⟹z=wTx+b⟹α=σ(z)⟹L(a,y)⟹L(a,y)=−ylog(a)−(1−y)log(1−a)
接下来使用
z
z
z就可以计算出
a
a
a。我们将的符号换为表示输出
y
^
  
⟹
  
a
=
σ
(
z
)
\hat{y}\implies{a = \sigma(z)}
y^⟹a=σ(z),然后可以计算出loss function
L
(
a
,
y
)
L(a,y)
L(a,y)
3.1.2 神经网络介绍
神经网络看起来是如下这个样子(图3.1.2)。其中图中每一个节点(圆圈)表示上述的一个逻辑回归单元,如果我们的输出函数都使用sigmoid函数,那么可以看成神经网络就是多个sigmoid单元堆叠起来的网络。对于图3.1.1中的节点,它包含了之前讲的计算的两个步骤:首先通过公式3.1计算出值
z
z
z,然后通过
σ
(
z
)
\sigma(z)
σ(z)计算值
a
a
a。
符号说明:
- W [ 1 ] W^{[1]} W[1]表示第一层神经网络的 W W W系数矩阵数值。
- W 1 [ 1 ] W^{[1]}_{1} W1[1]表示第一层神经网络的第一个逻辑回归单元的 W W W系数矩阵数值。
- 同理, b [ 2 ] b^{[2]} b[2]表示第二层神经网络的 b b b系数矩阵数值。
那么我们从
X
X
X输入矩阵计算出
y
^
\hat{y}
y^的过程(前向传播过程)可以描述如下:
1.先计算第一层的输出结果:
x
W
[
1
]
b
[
1
]
}
  
⟹
  
z
[
1
]
=
W
[
1
]
x
+
b
[
1
]
  
⟹
  
a
[
1
]
=
σ
(
z
[
1
]
)
公
式
3.4
:
\left. \begin{array}{r} {x }\\ {W^{[1]}}\\ {b^{[1]}} \end{array} \right\} \implies{z^{[1]}=W^{[1]}x+b^{[1]}} \implies{a^{[1]} = \sigma(z^{[1]})}公式3.4:
xW[1]b[1]⎭⎬⎫⟹z[1]=W[1]x+b[1]⟹a[1]=σ(z[1])公式3.4:
2.再使用第一层的输出结果
σ
(
z
[
1
]
)
\sigma(z^{[1]})
σ(z[1])作为第二层的输入,再计算第二层的输出结果:
a
[
1
]
=
σ
(
z
[
1
]
)
W
[
2
]
b
[
2
]
}
  
⟹
  
z
[
2
]
=
W
[
2
]
a
[
1
]
+
b
[
2
]
  
⟹
  
a
[
2
]
=
σ
(
z
[
2
]
)
\left. \begin{array}{r} \text{$a^{[1]} = \sigma(z^{[1]})$}\\ \text{$W^{[2]}$}\\ \text{$b^{[2]}$}\\ \end{array} \right\} \implies{z^{[2]}=W^{[2]}a^{[1]}+b^{[2]}} \implies{a^{[2]} = \sigma(z^{[2]})}\\
a[1]=σ(z[1])W[2]b[2]⎭⎬⎫⟹z[2]=W[2]a[1]+b[2]⟹a[2]=σ(z[2])
3.再使用第二层的输出结果
σ
(
z
[
2
]
)
\sigma(z^{[2]})
σ(z[2])计算出损失函数:
这里
σ
(
z
[
2
]
)
=
a
[
2
]
\sigma(z^{[2]})=a^{[2]}
σ(z[2])=a[2]
  
⟹
  
L
(
a
[
2
]
,
y
)
\implies{{L}\left(a^{[2]},y \right)}
⟹L(a[2],y)
  
⟹
  
L
(
a
[
2
]
,
y
)
=
−
y
log
(
a
[
2
]
)
−
(
1
−
y
)
log
(
1
−
a
[
2
]
)
\implies{L\left(a^{[2]},y \right)=-y\log(a^{[2]})-(1-y)\log (1-a^{[2]})}
⟹L(a[2],y)=−ylog(a[2])−(1−y)log(1−a[2])
3.2 神经网络的表示(Neural Network Representation)
这是一张神经网络的图片,让我们给此图的不同部分取一些名字:
1.输入层:将特征转换为输入矩阵
X
X
X。
功能:将输入特征
x
1
x_1
x1、
x
2
x_2
x2、
x
3
x_3
x3,转换为列向量
[
x
1
,
x
2
,
x
3
]
T
[x_1,x_2,x_3]^T
[x1,x2,x3]T,然后输入下一层进行计算。
2.隐藏层:图中第一层的神经网络单元组成。
由于从输入端看进去看见输入层,从输出端看进去只能看见模型的输出层,因此第一层是不可见的,我们称之为隐藏层。
功能:计算出第一层的输出给下一层作为输入。
x
W
[
1
]
b
[
1
]
}
  
⟹
  
z
[
1
]
=
W
[
1
]
x
+
b
[
1
]
  
⟹
  
a
[
1
]
=
σ
(
z
[
1
]
)
\left. \begin{array}{r} {x }\\ {W^{[1]}}\\ {b^{[1]}} \end{array} \right\} \implies{z^{[1]}=W^{[1]}x+b^{[1]}} \implies{a^{[1]} = \sigma(z^{[1]})}
xW[1]b[1]⎭⎬⎫⟹z[1]=W[1]x+b[1]⟹a[1]=σ(z[1])
3.输出层:再次进行逻辑回归运算,给出输出结果。
功能:计算最终结果,过程如下:
a
[
1
]
=
σ
(
z
[
1
]
)
W
[
2
]
b
[
2
]
}
  
⟹
  
z
[
2
]
=
W
[
2
]
a
[
1
]
+
b
[
2
]
  
⟹
  
a
[
2
]
=
σ
(
z
[
2
]
)
\left. \begin{array}{r} \text{$a^{[1]} = \sigma(z^{[1]})$}\\ \text{$W^{[2]}$}\\ \text{$b^{[2]}$}\\ \end{array} \right\} \implies{z^{[2]}=W^{[2]}a^{[1]}+b^{[2]}} \implies{a^{[2]} = \sigma(z^{[2]})}\\
a[1]=σ(z[1])W[2]b[2]⎭⎬⎫⟹z[2]=W[2]a[1]+b[2]⟹a[2]=σ(z[2])
现在我们再引入几个符号,就像我们之前用向量
x
x
x表示输入特征。这里有个可代替的记号
a
[
0
]
a^{[0]}
a[0]可以用来表示输入特征。
a
a
a表示激活的意思,它意味着网络中不同层的值会传递到它们后面的层中,输入层将
x
x
x传递给隐藏层,所以我们将输入层的激活值称为
a
[
0
]
a^{[0]}
a[0];下一层即隐藏层也同样会产生一些激活值,那么我将其记作
a
[
1
]
a^{[1]}
a[1],所以具体地,这里的第一个单元或结点我们将其表示为
a
1
[
1
]
a^{[1]}_{1}
a1[1],第二个结点的值我们记为
a
2
[
1
]
a^{[1]}_{2}
a2[1]以此类推。所以这里的是一个四维的向量如果写成Python代码,那么它是一个规模为4x1的矩阵或一个大小为4的列向量,如下公式,它是四维的,因为在本例中,我们有四个结点或者单元,或者称为四个隐藏层单元;
公式3.7
a
[
1
]
=
[
a
1
[
1
]
a
2
[
1
]
a
3
[
1
]
a
4
[
1
]
]
a^{[1]} = \left[ \begin{array}{ccc} a^{[1]}_{1}\\ a^{[1]}_{2}\\ a^{[1]}_{3}\\ a^{[1]}_{4} \end{array} \right]
a[1]=⎣⎢⎢⎢⎡a1[1]a2[1]a3[1]a4[1]⎦⎥⎥⎥⎤
最后输出层将产生某个数值
a
a
a,它只是一个单独的实数,所以的
y
^
\hat{y}
y^值将取为
a
[
2
]
a^{[2]}
a[2]
3.3 计算一个神经网络的输出(Computing a Neural Network’s output)
图3.3.1
其中, x x x表示输入特征, a a a表示每个神经元的输出, W W W表示特征的权重,上标表示神经网络的层数(隐藏层为1),下标表示该层的第几个神经元。这是神经网络的符号惯例,下同。
神经网络的计算
关于神经网络是怎么计算的,从我们之前提及的逻辑回归开始,如下图所示。用圆圈表示神经网络的计算单元,逻辑回归的计算有两个步骤,首先你按步骤计算出 z z z,然后在第二步中你以sigmoid函数为激活函数计算 z z z(得出 a a a),一个神经网络只是这样子做了好多次重复计算。
图3.3.2
回到两层的神经网络,我们从隐藏层的第一个神经元开始计算,如上图第一个最上面的箭头所指。从上图可以看出,输入与逻辑回归相似,这个神经元的计算与逻辑回归一样分为两步,小圆圈代表了计算的两个步骤。
第一步,计算 z 1 [ 1 ] , z 1 [ 1 ] = w 1 [ 1 ] T x + b 1 [ 1 ] z^{[1]}_1,z^{[1]}_1 = w^{[1]T}_1x + b^{[1]}_1 z1[1],z1[1]=w1[1]Tx+b1[1]。
第二步,通过激活函数计算 a 1 [ 1 ] , a 1 [ 1 ] = σ ( z 1 [ 1 ] ) a^{[1]}_1,a^{[1]}_1 = \sigma(z^{[1]}_1) a1[1],a1[1]=σ(z1[1])。
隐藏层的第二个以及后面两个神经元的计算过程一样,只是注意符号表示不同,最终分别得到 a 2 [ 1 ] 、 a 3 [ 1 ] 、 a 4 [ 1 ] a^{[1]}_2、a^{[1]}_3、a^{[1]}_4 a2[1]、a3[1]、a4[1],详细结果见下:
z 1 [ 1 ] = w 1 [ 1 ] T x + b 1 [ 1 ] , a 1 [ 1 ] = σ ( z 1 [ 1 ] ) z^{[1]}_1 = w^{[1]T}_1x + b^{[1]}_1, a^{[1]}_1 = \sigma(z^{[1]}_1) z1[1]=w1[1]Tx+b1[1],a1[1]=σ(z1[1])
z 2 [ 1 ] = w 2 [ 1 ] T x + b 2 [ 1 ] , a 2 [ 1 ] = σ ( z 2 [ 1 ] ) z^{[1]}_2 = w^{[1]T}_2x + b^{[1]}_2, a^{[1]}_2 = \sigma(z^{[1]}_2) z2[1]=w2[1]Tx+b2[1],a2[1]=σ(z2[1])
z 3 [ 1 ] = w 3 [ 1 ] T x + b 3 [ 1 ] , a 3 [ 1 ] = σ ( z 3 [ 1 ] ) z^{[1]}_3 = w^{[1]T}_3x + b^{[1]}_3, a^{[1]}_3 = \sigma(z^{[1]}_3) z3[1]=w3[1]Tx+b3[1],a3[1]=σ(z3[1])
z 4 [ 1 ] = w 4 [ 1 ] T x + b 4 [ 1 ] , a 4 [ 1 ] = σ ( z 4 [ 1 ] ) z^{[1]}_4 = w^{[1]T}_4x + b^{[1]}_4, a^{[1]}_4 = \sigma(z^{[1]}_4) z4[1]=w4[1]Tx+b4[1],a4[1]=σ(z4[1])
3.3.1 向量化计算
如果你执行神经网络的程序,用for循环来做这些看起来真的很低效。所以接下来我们要做的就是把这四个等式向量化。向量化的过程是将神经网络中的一层神经元参数纵向堆积起来,例如隐藏层中的 w w w纵向堆积起来变成一个 ( 4 , 3 ) (4,3) (4,3)的矩阵,用符号 W [ 1 ] W^{[1]} W[1]表示。另一个看待这个的方法是我们有四个逻辑回归单元,且每一个逻辑回归单元都有相对应的参数——向量 w w w,把这四个向量堆积在一起,你会得出这4×3的矩阵。
注:为什么是4*3的矩阵:可以这么想,我们有3个特征,并且有4个神经元。我们的目标是将每个特征输入到各个神经元中进行计算,我们将W进行纵向堆叠, W T x + b W^{T}x+b WTx+b是不可分的,因此b也是纵向堆叠,因为一个逻辑回归中b是一个常量,维度为1,b堆叠之后就是一个[4,1]的列向量。因此 W T X W^{T}X WTX输出的行数也应该是4(这样才能跟b进行求和呀), 所以根据矩阵乘法法则, W X WX WX应该是 4 ∗ 3 ∗ 3 ∗ m 4*3*3*m 4∗3∗3∗m 的 形式,这里m表示样本数量。
总结:隐藏层理解如下:
W 维度:[当前层的神经元个数,每个样本的特征个数]
X 维度 : [每个样本的特征个数,样本数量]
b 维度 : [当前层的神经元个数,1]
第n层维度理解如下:
W维度:[当前层的神经元个数,当前层输入特征个数]
X维度 :[当前层输入特征个数,样本数量m]
b维度 : [当前层的神经元个数,1]
从上边公式不难得出
W
[
1
]
W^{[1]}
W[1]维度:[当前层的神经元个数,当前层输入特征个数]=[4,3]
X
[
1
]
X^{[1]}
X[1]维度 :[当前层输入特征个数,样本数量] = [3,1]
b
[
1
]
b^{[1]}
b[1]维度 :[当前层的神经元个数,1] = [4,1]
W
[
2
]
W^{[2]}
W[2]维度:[当前层的神经元个数,当前层输入特征个数]=[1,4]
X
[
2
]
X^{[2]}
X[2]维度 :[当前层输入特征个数,样本数量] = [4,1]
b
[
2
]
b^{[2]}
b[2]维度 :[当前层的神经元个数,1] = [1,1]
因此,
公式3.8:
z
[
n
]
=
w
[
n
]
x
+
b
[
n
]
z^{[n]} = w^{[n]}x + b^{[n]}
z[n]=w[n]x+b[n]
公式3.9:
a [ n ] = σ ( z [ n ] ) a^{[n]}=\sigma(z^{[n]}) a[n]=σ(z[n])
详细过程见下:
公式3.10:
a
[
1
]
=
[
a
1
[
1
]
a
2
[
1
]
a
3
[
1
]
a
4
[
1
]
]
=
σ
(
z
[
1
]
)
a^{[1]} = \left[ \begin{array}{c} a^{[1]}_{1}\\ a^{[1]}_{2}\\ a^{[1]}_{3}\\ a^{[1]}_{4} \end{array} \right] = \sigma(z^{[1]})
a[1]=⎣⎢⎢⎢⎡a1[1]a2[1]a3[1]a4[1]⎦⎥⎥⎥⎤=σ(z[1])
公式3.11:
[
z
1
[
1
]
z
2
[
1
]
z
3
[
1
]
z
4
[
1
]
]
=
[
.
.
.
W
1
[
1
]
T
.
.
.
.
.
.
W
2
[
1
]
T
.
.
.
.
.
.
W
3
[
1
]
T
.
.
.
.
.
.
W
4
[
1
]
T
.
.
.
]
⏞
W
[
1
]
∗
[
x
1
x
2
x
3
]
⏞
i
n
p
u
t
+
[
b
1
[
1
]
b
2
[
1
]
b
3
[
1
]
b
4
[
1
]
]
⏞
b
[
1
]
\left[ \begin{array}{c} z^{[1]}_{1}\\ z^{[1]}_{2}\\ z^{[1]}_{3}\\ z^{[1]}_{4}\\ \end{array} \right] = \overbrace{ \left[ \begin{array}{c} ...W^{[1]T}_{1}...\\ ...W^{[1]T}_{2}...\\ ...W^{[1]T}_{3}...\\ ...W^{[1]T}_{4}... \end{array} \right] }^{W^{[1]}} * \overbrace{ \left[ \begin{array}{c} x_1\\ x_2\\ x_3\\ \end{array} \right] }^{input} + \overbrace{ \left[ \begin{array}{c} b^{[1]}_1\\ b^{[1]}_2\\ b^{[1]}_3\\ b^{[1]}_4\\ \end{array} \right] }^{b^{[1]}}
⎣⎢⎢⎢⎡z1[1]z2[1]z3[1]z4[1]⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡...W1[1]T......W2[1]T......W3[1]T......W4[1]T...⎦⎥⎥⎥⎤
W[1]∗⎣⎡x1x2x3⎦⎤
input+⎣⎢⎢⎢⎡b1[1]b2[1]b3[1]b4[1]⎦⎥⎥⎥⎤
b[1]
对于神经网络的第一层,给予一个输入
x
x
x,得到
a
[
1
]
a^{[1]}
a[1],
x
x
x可以表示为
a
[
0
]
a^{[0]}
a[0]。通过相似的衍生你会发现,后一层的表示同样可以写成类似的形式,得到
a
[
2
]
a^{[2]}
a[2],
y
^
=
a
[
2
]
\hat{y} = a^{[2]}
y^=a[2],具体过程见公式3.8、3.9。
如上图左半部分所示为神经网络,把网络左边部分盖住先忽略,那么最后的输出单元就相当于一个逻辑回归的计算单元。当你有一个包含一层隐藏层的神经网络,你需要去实现以计算得到输出的是右边的四个等式,并且可以看成是一个向量化的计算过程,计算出隐藏层的四个逻辑回归单元和整个隐藏层的输出结果,如果编程实现需要的也只是这四行代码。
3.4 多样本向量化(Vectorizing across multiple examples)
从3.3中我们总结了如下维度规律:
第n层维度理解如下:
W维度:[当前层的神经元个数,当前层输入特征个数]
X维度 :[当前层输入特征个数,样本数量]
b维度 : [当前层的神经元个数,1]
逻辑回归是将各个训练样本组合成矩阵,对矩阵的各列进行计算。神经网络是通过对逻辑回归中的等式简单的变形,让神经网络计算出输出值。这种计算是所有的训练样本同时进行的,以下是实现它具体的步骤:
图3.4.1
如果有一个非向量化形式的实现,而且要计算出它的预测值,对于所有训练样本,需要让 i i i从1到 m m m实现这四个等式:
z [ 1 ] ( i ) = W [ 1 ] ( i ) x ( i ) + b [ 1 ] ( i ) z^{[1](i)}=W^{[1](i)}x^{(i)}+b^{[1](i)} z[1](i)=W[1](i)x(i)+b[1](i)
a [ 1 ] ( i ) = σ ( z [ 1 ] ( i ) ) a^{[1](i)}=\sigma(z^{[1](i)}) a[1](i)=σ(z[1](i))
z [ 2 ] ( i ) = W [ 2 ] ( i ) a [ 1 ] ( i ) + b [ 2 ] ( i ) z^{[2](i)}=W^{[2](i)}a^{[1](i)}+b^{[2](i)} z[2](i)=W[2](i)a[1](i)+b[2](i)
a [ 2 ] ( i ) = σ ( z [ 2 ] ( i ) ) a^{[2](i)}=\sigma(z^{[2](i)}) a[2](i)=σ(z[2](i))
对于上面的这个方程中的 ( i ) ^{(i)} (i),是所有依赖于训练样本的变量,即将 ( i ) (i) (i)添加到 x x x, z z z和 a a a。如果想计算 m m m个训练样本上的所有输出,就应该向量化整个计算,以简化这列。
接下来讲讲如何向量化这些数值:
-
对于m个样本的输入集X:
注:这里就是说输入层的作用,将输入特征 x 1 x_1 x1、 x 2 x_2 x2、 x 3 x_3 x3,转换为列向量 [ x 1 , x 2 , x 3 ] T [x_1,x_2,x_3]^T [x1,x2,x3]T,然后输入下一层进行计算。只不过这里是将m个列向量 [ x ( 1 ) , x ( 2 ) , … … x ( m ) ] [x^{(1)},x^{(2)},……x^{(m)}] [x(1),x(2),……x(m)]进行列堆叠。因此得到:
公式3.12:
x = [ ⋮ ⋮ ⋮ ⋮ x ( 1 ) x ( 2 ) ⋯ x ( m ) ⋮ ⋮ ⋮ ⋮ ] x = \left[ \begin{array}{c} \vdots & \vdots & \vdots & \vdots\\ x^{(1)} & x^{(2)} & \cdots & x^{(m)}\\ \vdots & \vdots & \vdots & \vdots\\ \end{array} \right] x=⎣⎢⎢⎡⋮x(1)⋮⋮x(2)⋮⋮⋯⋮⋮x(m)⋮⎦⎥⎥⎤
所以输入集X的维度是:[特征数量k,样本数量m] -
对于第一层的输出:
注: 由矩阵的乘法 Z [ 1 ] = W [ 1 ] X + b [ 1 ] , z [ 1 ] ( 1 ) = = W [ 1 ] ( 1 ) x ( 1 ) + b [ 1 ] ( 1 ) Z^{[1]}=W^{[1]}X+b^{[1]},z^{[1](1)}==W^{[1](1)}x^{(1)}+b^{[1](1)} Z[1]=W[1]X+b[1],z[1](1)==W[1](1)x(1)+b[1](1)
公式3.13:
Z [ 1 ] = [ ⋮ ⋮ ⋮ ⋮ z [ 1 ] ( 1 ) c ⋯ z [ 1 ] ( m ) ⋮ ⋮ ⋮ ⋮ ] Z^{[1]} = \left[ \begin{array}{c} \vdots & \vdots & \vdots & \vdots\\ z^{[1](1)} &c & \cdots & z^{[1](m)}\\ \vdots & \vdots & \vdots & \vdots\\ \end{array} \right] Z[1]=⎣⎢⎢⎡⋮z[1](1)⋮⋮c⋮⋮⋯⋮⋮z[1](m)⋮⎦⎥⎥⎤
对于矩阵 Z Z Z从水平方向上看,对应于不同的训练样本;竖直方向上,对应不同的输入特征,而这就是神经网络输入层中各个节点。
所以输入集W的维度是:[当前层的神经元个数,当前层输入样本的个数]
公式3.14:
A [ 1 ] = [ ⋮ ⋮ ⋮ ⋮ α [ 1 ] ( 1 ) α [ 1 ] ( 2 ) ⋯ α [ 1 ] ( m ) ⋮ ⋮ ⋮ ⋮ ] A^{[1]} = \left[ \begin{array}{c} \vdots & \vdots & \vdots & \vdots\\ \alpha^{[1](1)} & \alpha^{[1](2)} & \cdots & \alpha^{[1](m)}\\ \vdots & \vdots & \vdots & \vdots\\ \end{array} \right] A[1]=⎣⎢⎢⎡⋮α[1](1)⋮⋮α[1](2)⋮⋮⋯⋮⋮α[1](m)⋮⎦⎥⎥⎤
从水平上看,矩阵 A A A代表了各个训练样本的输出。从竖直上看,矩阵 A A A的不同的索引对应于不同的隐藏单元。 -
同理,进行第二层向量化,我们得出第一,第二层的输出公式如下:
公式3.15:
z [ 1 ] ( i ) = W [ 1 ] ( i ) x ( i ) + b [ 1 ] α [ 1 ] ( i ) = σ ( z [ 1 ] ( i ) ) z [ 2 ] ( i ) = W [ 2 ] ( i ) α [ 1 ] ( i ) + b [ 2 ] α [ 2 ] ( i ) = σ ( z [ 2 ] ( i ) ) }    ⟹    { A [ 1 ] = σ ( z [ 1 ] ) z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ] A [ 2 ] = σ ( z [ 2 ] ) \left. \begin{array}{r} \text{$z^{[1](i)} = W^{[1](i)}x^{(i)} + b^{[1]}$}\\ \text{$\alpha^{[1](i)} = \sigma(z^{[1](i)})$}\\ \text{$z^{[2](i)} = W^{[2](i)}\alpha^{[1](i)} + b^{[2]}$}\\ \text{$\alpha^{[2](i)} = \sigma(z^{[2](i)})$}\\ \end{array} \right\} \implies \begin{cases} \text{$A^{[1]} = \sigma(z^{[1]})$}\\ \text{$z^{[2]} = W^{[2]}A^{[1]} + b^{[2]}$}\\ \text{$A^{[2]} = \sigma(z^{[2]})$}\\ \end{cases} z[1](i)=W[1](i)x(i)+b[1]α[1](i)=σ(z[1](i))z[2](i)=W[2](i)α[1](i)+b[2]α[2](i)=σ(z[2](i))⎭⎪⎪⎬⎪⎪⎫⟹⎩⎪⎨⎪⎧A[1]=σ(z[1])z[2]=W[2]A[1]+b[2]A[2]=σ(z[2])
3.6 激活函数(Activation functions)
3.6.1 sigmoid函数
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{{1 + e}^{- z}} σ(z)=1+e−z1
激活函数 | 公式 | 导数 |
---|---|---|
sigmoid | σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{{1 + e}^{- z}} σ(z)=1+e−z1 | σ ( z ) ′ = σ ( z ) ( 1 − σ ( z ) ) \sigma(z)^{'}= \sigma(z)(1-\sigma(z)) σ(z)′=σ(z)(1−σ(z)) |
- 优点: 中值为0.5适合做[0,1]范围内概率判断的函数,此时阈值为0.5。
- 缺点: 当z特别大或者特别小时候,导数趋向0使得梯度下降缓慢导数趋向0使得梯度下降缓慢。
3.6.2 tanh函数
t a n h ( z ) = e z − e − z e z + e − z tanh(z) = \frac{e^z-e^{- z}}{e^z+e^{- z}} tanh(z)=ez+e−zez−e−z
激活函数 | 公式 | 导数 |
---|---|---|
tanh | t a n h ( z ) = e z − e − z e z + e − z tanh(z) = \frac{e^z-e^{- z}}{e^z+e^{- z}} tanh(z)=ez+e−zez−e−z | tanh ( z ) ′ = 1 − t a n h ( z ) 2 \tanh(z)^{'}= 1-tanh(z)^{2} tanh(z)′=1−tanh(z)2 |
- 优点: 中值为0适合做[-1,1]值域范围内概率判断的函数,因此比较适合在隐藏层中使用。
- 缺点: 当z特别大或者特别小时候,导数趋向0使得梯度下降缓慢导数趋向0使得梯度下降缓慢。
- 求导过程:
t a n h ( z ) = e z − e − z e z + e − z tanh(z) = \frac{e^z-e^{- z}}{e^z+e^{- z}} tanh(z)=ez+e−zez−e−z
t a n h ( z ) ′ = ( e z − e − z ) ′ ( e z + e − z ) − ( e z − e − z ) ( e z + e − z ) ′ ( e z + e − z ) 2 tanh(z)^{'}= \frac{(e^z-e^{- z})^{'}(e^z+e^{- z})-(e^z-e^{- z})(e^z+e^{- z})^{'}}{(e^z+e^{- z})^2} tanh(z)′=(ez+e−z)2(ez−e−z)′(ez+e−z)−(ez−e−z)(ez+e−z)′
t a n h ( z ) ′ = ( e z + e − z ) 2 − ( e z − e − z ) ( e z − e − z ) ( e z + e − z ) 2 tanh(z)^{'}= \frac{(e^z+e^{- z})^2-(e^z-e^{- z})(e^z-e^{- z})}{(e^z+e^{- z})^2} tanh(z)′=(ez+e−z)2(ez+e−z)2−(ez−e−z)(ez−e−z)
t a n h ( z ) ′ = 1 − [ ( e z − e − z ) ( e z + e − z ) ] 2 tanh(z)^{'}=1- [\frac{(e^z-e^{- z})}{(e^z+e^{- z})}]^2 tanh(z)′=1−[(ez+e−z)(ez−e−z)]2
t a n h ( z ) ′ = 1 − t a n h ( z ) 2 tanh(z)^{'}=1- tanh(z)^2 tanh(z)′=1−tanh(z)2
3.6.3 Relu函数(修正线性单元函数)
R e l u ( z ) = m a x ( 0 , z ) Relu(z) = max(0,z) Relu(z)=max(0,z)
激活函数 | 公式 | 导数 |
---|---|---|
Relu | R e l u ( z ) = m a x ( 0 , z ) Relu(z) = max(0,z) Relu(z)=max(0,z) | R e l u ( z ) ′ = { 1 , z > 0 0 , z < 0 u n d e f i n e d , z = 0 Relu(z)^{'}=\begin{cases}{1,z>0}\\{0,z<0}\\ {undefined,z=0}\end{cases} Relu(z)′=⎩⎪⎨⎪⎧1,z>00,z<0undefined,z=0 |
- 优点: 具有线性的导数,求导简单,梯度下降法收敛速度快,因此比较适合在隐藏层和输出层中使用。
- 缺点: 1.函数在x=0处时候不连续,无法求导,但是这里的0是严格的0实际上遇到这种情况可以使用特殊处理来解决。
2.当x<0的时候,函数值直接为0,因此不适合在z的值域范围为[-inf,+inf]的输入值中使用。
3.6.5 Leaky Relu函数(弱修正线性单元函数)
L e a k y R e l u ( z ) = { 0.01 z , z > = 0 z , z < 0 LeakyRelu(z) = \begin{cases}{0.01z,z>=0}\\{z,z<0}\\ \end{cases} LeakyRelu(z)={0.01z,z>=0z,z<0
激活函数 | 公式 | 导数 |
---|---|---|
Relu | L e a k y R e l u ( z ) = m a x ( 0 , z ) LeakyRelu(z) = max(0,z) LeakyRelu(z)=max(0,z) | L e a k y R e l u ( z ) ′ = { 1 , z > 0 0.01 , z < 0 u n d e f i n e d , z = 0 LeakyRelu(z)^{'}=\begin{cases}{1,z>0}\\{0.01,z<0}\\{undefined,z=0}\\ \end{cases} LeakyRelu(z)′=⎩⎪⎨⎪⎧1,z>00.01,z<0undefined,z=0 |
- 优点: 具有线性的导数,求导简单,梯度下降法收敛速度快,因此比较适合在隐藏层中使用。
- 缺点: 1.函数在x=0处时候不连续,无法求导,但是这里的0是严格的0实际上遇到这种情况可以使用特殊处理来解决。
所以通常的建议是:如果不确定哪一个激活函数效果更好,可以把它们都试试,然后在验证集或者发展集上进行评价。然后看哪一种表现的更好,就去使用它。
3.7 为什么需要非线性激活函数?(why need a nonlinear activation function?)
为什么神经网络需要非线性激活函数?事实证明:要让你的神经网络能够计算出有趣的函数,你必须使用非线性激活函数,证明如下:
这是神经网络正向传播的方程,现在我们去掉函数 g g g,然后令 a [ 1 ] = z [ 1 ] a^{[1]} = z^{[1]} a[1]=z[1],或者我们也可以令 g ( z ) = z g(z)=z g(z)=z,这个有时被叫做线性激活函数(更学术点的名字是恒等激励函数,因为它们就是把输入值输出)。为了说明问题我们把 a [ 2 ] = z [ 2 ] a^{[2]} = z^{[2]} a[2]=z[2],那么这个模型的输出 y y y或仅仅只是输入特征 x x x的线性组合。
如果我们改变前面的式子,令:
(1) $ a^{[1]} = z^{[1]} = W^{[1]}x + b^{[1]}$
(2)
a
[
2
]
=
z
[
2
]
=
W
[
2
]
a
[
1
]
+
b
[
2
]
a^{[2]} = z^{[2]} = W^{[2]}a^{[1]}+ b^{[2]}
a[2]=z[2]=W[2]a[1]+b[2]
将式子(1)代入式子(2)中,则:
a
[
2
]
=
z
[
2
]
=
W
[
2
]
(
W
[
1
]
x
+
b
[
1
]
)
+
b
[
2
]
a^{[2]} = z^{[2]} = W^{[2]}(W^{[1]}x + b^{[1]}) + b^{[2]}
a[2]=z[2]=W[2](W[1]x+b[1])+b[2]
(3)
a
[
2
]
=
z
[
2
]
=
W
[
2
]
W
[
1
]
x
+
W
[
2
]
b
[
1
]
+
b
[
2
]
a^{[2]} = z^{[2]} = W^{[2]}W^{[1]}x + W^{[2]}b^{[1]} + b^{[2]}
a[2]=z[2]=W[2]W[1]x+W[2]b[1]+b[2]
简化多项式得
a
[
2
]
=
z
[
2
]
=
W
′
x
+
b
′
a^{[2]} = z^{[2]} = W^{'}x + b^{'}
a[2]=z[2]=W′x+b′
如果你是用线性激活函数或者叫恒等激励函数,那么神经网络只是把输入线性组合再输出。也就是说加入多少层的
我们稍后会谈到深度网络,有很多层的神经网络,很多隐藏层。事实证明,如果你使用线性激活函数或者没有使用一个激活函数,那么无论你的神经网络有多少层一直在做的只是计算线性函数,所以不如直接去掉全部隐藏层。在我们的简明案例中,事实证明如果你在隐藏层用线性激活函数,在输出层用sigmoid函数,那么这个模型的复杂度和没有任何隐藏层的标准Logistic回归是一样的,如果你愿意的话,可以证明一下。
在这里线性隐层一点用也没有,因为这两个线性函数的组合本身就是线性函数,所以除非你引入非线性,否则你无法计算更有趣的函数,即使你的网络层数再多也不行;只有一个地方可以使用线性激活函数------ g ( z ) = z g(z)=z g(z)=z,就是你在做机器学习中的回归问题。 y y y 是一个实数,举个例子,比如你想预测房地产价格, y y y 就不是二分类任务0或1,而是一个实数,从0到正无穷。如果 y y y 是个实数,那么在输出层用线性激活函数也许可行,你的输出也是一个实数,从负无穷到正无穷。
总而言之,不能在隐藏层用线性激活函数,可以用ReLU或者tanh或者leaky ReLU或者其他的非线性激活函数,唯一可以用线性激活函数的通常就是输出层;除了这种情况,会在隐层用线性函数的,除了一些特殊情况,比如与压缩有关的,那方面在这里将不深入讨论。在这之外,在隐层使用线性激活函数非常少见。因为房价都是非负数,所以我们也可以在输出层使用ReLU函数这样你的 y ^ \hat{y} y^都大于等于0。
3.8 神经网络的梯度下降(Gradient descent for neural networks)
在这个视频中,我会给你实现反向传播或者说梯度下降算法的方程组,在下一个视频我们会介绍为什么这几个特定的方程是针对你的神经网络实现梯度下降的正确方程。
你的单隐层神经网络会有 W [ 1 ] W^{[1]} W[1], b [ 1 ] b^{[1]} b[1], W [ 2 ] W^{[2]} W[2], b [ 2 ] b^{[2]} b[2]这些参数,还有个 n x n_x nx表示输入特征的个数, n [ 1 ] n^{[1]} n[1]表示隐藏单元个数, n [ 2 ] n^{[2]} n[2]表示输出单元个数。
在我们的例子中,我们只介绍过的这种情况,那么参数:
矩阵
W
[
1
]
W^{[1]}
W[1]的维度就是(
n
[
1
]
,
n
[
0
]
n^{[1]}, n^{[0]}
n[1],n[0]),
b
[
1
]
b^{[1]}
b[1]就是
n
[
1
]
n^{[1]}
n[1]维向量,可以写成
(
n
[
1
]
,
1
)
(n^{[1]}, 1)
(n[1],1),就是一个的列向量。
矩阵
W
[
2
]
W^{[2]}
W[2]的维度就是(
n
[
2
]
,
n
[
1
]
n^{[2]}, n^{[1]}
n[2],n[1]),
b
[
2
]
b^{[2]}
b[2]的维度就是
(
n
[
2
]
,
1
)
(n^{[2]},1)
(n[2],1)维度。
你还有一个神经网络的成本函数,假设你在做二分类任务,那么你的成本函数等于:
Cost function:
公式:
J
(
W
[
1
]
,
b
[
1
]
,
W
[
2
]
,
b
[
2
]
)
=
1
m
∑
i
=
1
m
L
(
y
^
,
y
)
J(W^{[1]},b^{[1]},W^{[2]},b^{[2]}) = {\frac{1}{m}}\sum_{i=1}^mL(\hat{y}, y)
J(W[1],b[1],W[2],b[2])=m1∑i=1mL(y^,y)
loss function和之前做logistic回归完全一样。
训练参数需要做梯度下降,在训练神经网络的时候,随机初始化参数很重要,而不是初始化成全零。当你参数初始化成某些值后,每次梯度下降都会循环计算以下预测值:
y
^
(
i
)
,
(
i
=
1
,
2
,
…
,
m
)
\hat{y}^{(i)},(i=1,2,…,m)
y^(i),(i=1,2,…,m)
公式3.28:
d
W
[
1
]
=
d
J
d
W
[
1
]
,
d
b
[
1
]
=
d
J
d
b
[
1
]
dW^{[1]} = \frac{dJ}{dW^{[1]}},db^{[1]} = \frac{dJ}{db^{[1]}}
dW[1]=dW[1]dJ,db[1]=db[1]dJ
公式3.29:
d
W
[
2
]
=
d
J
d
W
[
2
]
,
d
b
[
2
]
=
d
J
d
b
[
2
]
{d}W^{[2]} = \frac{{dJ}}{dW^{[2]}},{d}b^{[2]} = \frac{dJ}{db^{[2]}}
dW[2]=dW[2]dJ,db[2]=db[2]dJ
其中
公式3.30:
W
[
1
]
  
⟹
  
W
[
1
]
−
a
d
W
[
1
]
,
b
[
1
]
  
⟹
  
b
[
1
]
−
a
d
b
[
1
]
W^{[1]}\implies{W^{[1]} - adW^{[1]}},b^{[1]}\implies{b^{[1]} -adb^{[1]}}
W[1]⟹W[1]−adW[1],b[1]⟹b[1]−adb[1]
公式3.31:
W
[
2
]
  
⟹
  
W
[
2
]
−
α
d
W
[
2
]
,
b
[
2
]
  
⟹
  
b
[
2
]
−
α
d
b
[
2
]
W^{[2]}\implies{W^{[2]} - \alpha{\rm d}W^{[2]}},b^{[2]}\implies{b^{[2]} - \alpha{\rm d}b^{[2]}}
W[2]⟹W[2]−αdW[2],b[2]⟹b[2]−αdb[2]
正向传播方程如下(之前讲过):
forward propagation:
(1)
z
[
1
]
=
W
[
1
]
x
+
b
[
1
]
z^{[1]} = W^{[1]}x + b^{[1]}
z[1]=W[1]x+b[1]
(2)
a
[
1
]
=
σ
(
z
[
1
]
)
a^{[1]} = \sigma(z^{[1]})
a[1]=σ(z[1])
(3)
z
[
2
]
=
W
[
2
]
a
[
1
]
+
b
[
2
]
z^{[2]} = W^{[2]}a^{[1]} + b^{[2]}
z[2]=W[2]a[1]+b[2]
(4)
a
[
2
]
=
g
[
2
]
(
z
[
z
]
)
=
σ
(
z
[
2
]
)
a^{[2]} = g^{[2]}(z^{[z]}) = \sigma(z^{[2]})
a[2]=g[2](z[z])=σ(z[2])
反向传播方程如下:
back propagation:
公式3.32:
d
z
[
2
]
=
A
[
2
]
−
Y
,
Y
=
[
y
[
1
]
y
[
2
]
⋯
y
[
m
]
]
dz^{[2]} = A^{[2]} - Y , Y = \begin{bmatrix}y^{[1]} & y^{[2]} & \cdots & y^{[m]}\\ \end{bmatrix}
dz[2]=A[2]−Y,Y=[y[1]y[2]⋯y[m]]
公式3.33:
$dW^{[2]} = {\frac{1}{m}}dz{[2]}A{[1]T} $
公式3.34:
$ {\rm d}b^{[2]} = {\frac{1}{m}}np.sum({d}z^{[2]},axis=1,keepdims=True)$
公式3.35:
d
z
[
1
]
=
W
[
2
]
T
d
z
[
2
]
⎵
(
n
[
1
]
,
m
)
∗
g
[
1
]
′
⎵
a
c
t
i
v
a
t
i
o
n
  
f
u
n
c
t
i
o
n
  
o
f
  
h
i
d
d
e
n
  
l
a
y
e
r
∗
(
z
[
1
]
)
⎵
(
n
[
1
]
,
m
)
dz^{[1]} = \underbrace{W^{[2]T}{\rm d}z^{[2]}}_{(n^{[1]},m)}\quad*\underbrace{{g^{[1]}}^{'}}_{activation \; function \; of \; hidden \; layer}*\quad\underbrace{(z^{[1]})}_{(n^{[1]},m)}
dz[1]=(n[1],m)
W[2]Tdz[2]∗activationfunctionofhiddenlayer
g[1]′∗(n[1],m)
(z[1])
公式3.36:
d
W
[
1
]
=
1
m
d
z
[
1
]
x
T
dW^{[1]} = {\frac{1}{m}}dz^{[1]}x^{T}
dW[1]=m1dz[1]xT
公式3.37:
d
b
[
1
]
⎵
(
n
[
1
]
,
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
)
{\underbrace{db^{[1]}}_{(n^{[1]},1)}} = {\frac{1}{m}}np.sum(dz^{[1]},axis=1,keepdims=True)
(n[1],1)
db[1]=m1np.sum(dz[1],axis=1,keepdims=True)
上述是反向传播的步骤,注:这些都是针对所有样本进行过向量化,
Y
Y
Y是
1
×
m
1×m
1×m的矩阵;这里np.sum
是python的numpy命令,axis=1
表示水平相加求和,keepdims
是防止python输出那些古怪的秩数
(
n
,
)
(n,)
(n,),加上这个确保阵矩阵
d
b
[
2
]
db^{[2]}
db[2]这个向量输出的维度为
(
n
,
1
)
(n,1)
(n,1)这样标准的形式。
目前为止,我们计算的都和Logistic回归十分相似,但当你开始计算反向传播时,你需要计算,是隐藏层函数的导数,输出在使用sigmoid函数进行二元分类。这里是进行逐个元素乘积,因为 W [ 2 ] T d z [ 2 ] W^{[2]T}dz^{[2]} W[2]Tdz[2]和 ( z [ 1 ] ) (z^{[1]}) (z[1])这两个都为 ( n [ 1 ] , m ) (n^{[1]},m) (n[1],m)矩阵;
还有一种防止python输出奇怪的秩数,需要显式地调用reshape
把np.sum
输出结果写成矩阵形式。
以上就是正向传播的4个方程和反向传播的6个方程,这里我是直接给出的,在下个视频中,我会讲如何导出反向传播的这6个式子的。如果你要实现这些算法,你必须正确执行正向和反向传播运算,你必须能计算所有需要的导数,用梯度下降来学习神经网络的参数;你也可以许多成功的深度学习从业者一样直接实现这个算法,不去了解其中的知识。
3.10(选修)直观理解反向传播(Backpropagation intuition)
这个视频主要是推导反向传播。
下图是逻辑回归的推导:
回想一下逻辑回归的公式(参考公式3.2、公式3.5、公式3.6、公式3.15)
公式3.38:
x
w
b
}
  
⟹
  
z
=
w
T
x
+
b
  
⟹
  
α
=
σ
(
z
)
  
⟹
  
L
(
a
,
y
)
\left. \begin{array}{l} {x }\\ {w }\\ {b } \end{array} \right\} \implies{z={w}^Tx+b} \implies{\alpha = \sigma(z)} \implies{{L}\left(a,y \right)}
xwb⎭⎬⎫⟹z=wTx+b⟹α=σ(z)⟹L(a,y)
所以回想当时我们讨论逻辑回归的时候,我们有这个正向传播步骤,其中我们计算
z
z
z,然后
a
a
a,然后损失函数
L
L
L。
公式3.39:
x
w
b
}
⎵
d
w
=
d
z
⋅
x
,
d
b
=
d
z
  
⟸
  
z
=
w
T
x
+
b
⎵
d
z
=
d
a
⋅
g
′
(
z
)
,
g
(
z
)
=
σ
(
z
)
,
d
L
d
z
=
d
L
d
a
⋅
d
a
d
z
,
d
d
z
g
(
z
)
=
g
′
(
z
)
  
⟸
  
a
=
σ
(
z
)
  
⟸
  
L
(
a
,
y
)
⎵
d
a
=
d
d
a
L
(
a
,
y
)
=
(
−
y
log
α
−
(
1
−
y
)
log
(
1
−
a
)
)
′
=
−
y
a
+
1
−
y
1
−
a
\underbrace{ \left. \begin{array}{l} {x }\\ {w }\\ {b } \end{array} \right\} }_{dw={dz}\cdot x, db =dz} \impliedby\underbrace{{z={w}^Tx+b}}_{dz=da\cdot g^{'}(z), g(z)=\sigma(z), {\frac{{dL}}{dz}}={\frac{{dL}}{da}}\cdot{\frac{da}{dz}}, {\frac{d}{ dz}}g(z)=g^{'}(z)} \impliedby\underbrace{{a = \sigma(z)} \impliedby{L(a,y)}}_{da={\frac{{d}}{da}}{L}\left(a,y \right)=(-y\log{\alpha} - (1 - y)\log(1 - a))^{'}={-\frac{y}{a}} + {\frac{1 - y}{1 - a}{}} }
dw=dz⋅x,db=dz
xwb⎭⎬⎫⟸dz=da⋅g′(z),g(z)=σ(z),dzdL=dadL⋅dzda,dzdg(z)=g′(z)
z=wTx+b⟸da=dadL(a,y)=(−ylogα−(1−y)log(1−a))′=−ay+1−a1−y
a=σ(z)⟸L(a,y)
神经网络的计算中,与逻辑回归十分类似,但中间会有多层的计算。下图是一个双层神经网络,有一个输入层,一个隐藏层和一个输出层。
前向传播:
计算 z [ 1 ] z^{[1]} z[1], a [ 1 ] a^{[1]} a[1],再计算 z [ 2 ] z^{[2]} z[2], a [ 2 ] a^{[2]} a[2],最后得到loss function。
反向传播:
向后推算出
d
a
[
2
]
da^{[2]}
da[2],然后推算出
d
z
[
2
]
dz^{[2]}
dz[2],接着推算出
d
a
[
1
]
da^{[1]}
da[1],然后推算出
d
z
[
1
]
dz^{[1]}
dz[1]。我们不需要对
x
x
x求导,因为
x
x
x是固定的,我们也不是想优化
x
x
x。向后推算出
d
a
[
2
]
da^{[2]}
da[2],然后推算出
d
z
[
2
]
dz^{[2]}
dz[2]的步骤可以合为一步:
公式3.40:
反向传播第二层的偏导数推导如下:
z
[
2
]
=
W
[
2
]
a
[
1
]
+
b
[
2
]
z^{[2]}=W^{[2]}a^{[1]}+b^{[2]}
z[2]=W[2]a[1]+b[2]
a
[
2
]
=
σ
(
z
[
2
]
)
=
σ
(
W
[
2
]
a
[
1
]
+
b
[
2
]
)
a^{[2]}=\sigma{(z^{[2]})}=\sigma{(W^{[2]}a^{[1]}+b^{[2]})}
a[2]=σ(z[2])=σ(W[2]a[1]+b[2])
∂
L
∂
b
[
2
]
=
∂
L
(
z
,
y
)
∂
z
∗
∂
z
∂
b
[
2
]
=
(
σ
(
z
[
2
]
)
−
y
)
∂
(
W
[
2
]
a
[
1
]
+
b
[
2
]
)
∂
b
[
2
]
=
a
[
2
]
−
y
\frac{\partial L}{\partial b^{[2]}}=\frac{\partial L\left( z,y \right)}{\partial z}*\frac{\partial z}{\partial b^{[2]}}=({\sigma(z^{[2]})-y})\frac{\partial (W^{[2]}a^{[1]}+b^{[2]})}{ \partial b^{[2]}}=a^{[2]}-y
∂b[2]∂L=∂z∂L(z,y)∗∂b[2]∂z=(σ(z[2])−y)∂b[2]∂(W[2]a[1]+b[2])=a[2]−y
∂
L
∂
W
[
2
]
=
∂
L
(
z
,
y
)
∂
z
∗
∂
z
∂
W
[
2
]
=
(
σ
(
z
[
2
]
)
−
y
)
∂
(
W
[
2
]
a
[
1
]
+
b
[
2
]
)
∂
W
[
2
]
=
(
a
[
2
]
−
y
)
∗
a
[
1
]
\frac{\partial L}{\partial W^{[2]}}=\frac{\partial L\left( z,y \right)}{\partial z}*\frac{\partial z}{\partial W^{[2]}}=({\sigma(z^{[2]})-y})\frac{\partial (W^{[2]}a^{[1]}+b^{[2]})}{ \partial W^{[2]}}=(a^{[2]}-y)*a^{[1]}
∂W[2]∂L=∂z∂L(z,y)∗∂W[2]∂z=(σ(z[2])−y)∂W[2]∂(W[2]a[1]+b[2])=(a[2]−y)∗a[1]
∂
L
∂
W
[
2
]
=
(
a
[
2
]
−
y
)
a
[
1
]
T
\frac{\partial L}{\partial W^{[2]}}=(a^{[2]}-y){a^{[1]}}^{T}
∂W[2]∂L=(a[2]−y)a[1]T
(注意:逻辑回归中;为什么
a
[
1
]
T
a^{[1]T}
a[1]T多了个转置:
d
w
dw
dw中的
W
W
W(视频里是
W
i
[
2
]
W^{[2]}_i
Wi[2])是一个列向量,而
W
[
2
]
W^{[2]}
W[2]是个行向量,故需要加个转置);
反向传播第二层的偏导数推导总结如下:
∂
L
(
z
,
y
)
∂
z
=
a
[
2
]
−
y
,
∂
L
∂
b
[
2
]
=
a
[
2
]
−
y
  
,
  
∂
L
∂
W
[
2
]
=
(
a
[
2
]
−
y
)
a
[
1
]
T
\frac{\partial L\left( z,y \right)}{\partial z}=a^{[2]}-y,\frac{\partial L}{\partial b^{[2]}}=a^{[2]}-y\;,\;\frac{\partial L}{\partial W^{[2]}}=(a^{[2]}-y){a^{[1]}}^{T}
∂z∂L(z,y)=a[2]−y,∂b[2]∂L=a[2]−y,∂W[2]∂L=(a[2]−y)a[1]T
现在我们来计算反向传播的第一层的偏导数:
由于有第二层前向传播公式:
a
[
2
]
=
σ
(
z
[
2
]
)
=
σ
(
W
[
2
]
a
[
1
]
+
b
[
2
]
)
,
z
[
2
]
=
W
[
2
]
a
[
1
]
+
b
[
2
]
a^{[2]}=\sigma{(z^{[2]})}=\sigma{(W^{[2]}a^{[1]}+b^{[2]})},z^{[2]}=W^{[2]}a^{[1]}+b^{[2]}
a[2]=σ(z[2])=σ(W[2]a[1]+b[2]),z[2]=W[2]a[1]+b[2]
由于有第一层前向传播公式:
a
[
1
]
=
σ
(
z
[
1
]
)
=
σ
(
W
[
1
]
X
+
b
[
1
]
)
,
z
[
1
]
=
W
[
1
]
a
[
0
]
+
b
[
1
]
=
W
[
1
]
X
+
b
[
1
]
a^{[1]}=\sigma{(z^{[1]})}=\sigma{(W^{[1]}X+b^{[1]})},z^{[1]}=W^{[1]}a^{[0]}+b^{[1]}=W^{[1]}X+b^{[1]}
a[1]=σ(z[1])=σ(W[1]X+b[1]),z[1]=W[1]a[0]+b[1]=W[1]X+b[1]
从链式求导法则可以知道:
∂
L
∂
b
[
1
]
=
∂
L
(
z
[
1
]
,
y
)
∂
z
[
2
]
∗
∂
z
[
2
]
∂
a
[
1
]
∗
∂
a
[
1
]
∂
z
[
1
]
∗
∂
z
[
1
]
∂
b
[
1
]
=
(
σ
(
z
[
2
]
)
−
y
)
∗
W
[
2
]
T
∗
σ
(
z
[
1
]
)
∗
(
1
−
σ
(
z
[
1
]
)
\frac{\partial L}{\partial b^{[1]}}=\frac{\partial L\left( z^{[1]},y \right)}{\partial z^{[2]}}*\frac{\partial z^{[2]} }{\partial a^{[1]}}*\frac{\partial a^{[1]} }{\partial z^{[1]}}*\frac{\partial z^{[1]} }{\partial b^{[1]}}=({\sigma(z^{[2]})-y})*W^{[2]}T*{\sigma(z^{[1]})*(1-\sigma(z^{[1]})}
∂b[1]∂L=∂z[2]∂L(z[1],y)∗∂a[1]∂z[2]∗∂z[1]∂a[1]∗∂b[1]∂z[1]=(σ(z[2])−y)∗W[2]T∗σ(z[1])∗(1−σ(z[1])
∂ L ∂ W [ 1 ] = ∂ L ( z [ 1 ] , y ) ∂ z [ 2 ] ∗ ∂ z [ 2 ] ∂ a [ 1 ] ∗ ∂ a [ 1 ] ∂ z [ 1 ] ∗ ∂ z [ 1 ] ∂ W [ 1 ] = ( σ ( z [ 2 ] ) − y ) ∗ W [ 2 ] T ∗ σ ( z [ 1 ] ) ∗ ( 1 − σ ( z [ 1 ] ) ∗ X \frac{\partial L}{\partial W^{[1]}}=\frac{\partial L\left( z^{[1]},y \right)}{\partial z^{[2]}}*\frac{\partial z^{[2]} }{\partial a^{[1]}}*\frac{\partial a^{[1]} }{\partial z^{[1]}}*\frac{\partial z^{[1]} }{\partial W^{[1]}}=({\sigma(z^{[2]})-y})*W^{[2]}T*{\sigma(z^{[1]})*(1-\sigma(z^{[1]})}*X ∂W[1]∂L=∂z[2]∂L(z[1],y)∗∂a[1]∂z[2]∗∂z[1]∂a[1]∗∂W[1]∂z[1]=(σ(z[2])−y)∗W[2]T∗σ(z[1])∗(1−σ(z[1])∗X
其实这就是吴恩达老师所说的最难的损失函数求导公式了,但是我们拆解一下,就能够很清晰的得到链式求导的真谛:
其实上述过程拆解可以成为这样子:
- 计算 ∂ L ( z [ 2 ] , y ) ∂ z [ 2 ] \frac{\partial L\left( z^{[2]},y \right)}{\partial z[2]} ∂z[2]∂L(z[2],y)
- 从 Z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ] , 将 A [ 1 ] Z^{[2]}=W^{[2]}A^{[1]}+b^{[2]} ,将A^{[1]} Z[2]=W[2]A[1]+b[2],将A[1] 看做常数求 W [ 2 ] , b [ 2 ] W^{[2]},b^{[2]} W[2],b[2]的偏导数。
- 计算 ∂ L ( z [ 1 ] , y ) ∂ z [ 1 ] \frac{\partial L\left( z^{[1]},y \right)}{\partial z[1]} ∂z[1]∂L(z[1],y),从第1步的结果我们已经求出了 ∂ L ( z [ 2 ] , y ) ∂ z [ 2 ] \frac{\partial L\left( z^{[2]},y \right)}{\partial z[2]} ∂z[2]∂L(z[2],y),因为神经网络中 z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 1 ] z[2]=W^{[2]}A^{[1]}+b^{[1]} z[2]=W[2]A[1]+b[1],因此 ∂ L ( z [ 1 ] , y ) ∂ z [ 1 ] = ∂ L ( z [ 2 ] , y ) ∂ z [ 2 ] ∗ W [ 2 ] ∗ \frac{\partial L\left( z^{[1]},y \right)}{\partial z[1]}=\frac{\partial L\left( z^{[2]},y \right)}{\partial z[2]}*W^{[2]}* ∂z[1]∂L(z[1],y)=∂z[2]∂L(z[2],y)∗W[2]∗ g ( z 1 ) ′ g(z1)^{'} g(z1)′,其中 g ( z 1 ) ′ g(z1)^{'} g(z1)′指的是第一层激活函数对Z1的导数。
- 从此我们可以推出来,对于L层神经网络应该有:
∂ L ( z [ 1 ] , y ) ∂ z [ 1 ] = ∂ L ( z [ L ] , y ) ∂ z [ L ] ∗ ∂ z [ L ] ∂ z [ L − 1 ] ∗ … … ∂ z 2 [ z 1 ] \frac{\partial L\left( z^{[1]},y \right)}{\partial z^{[1]}}=\frac{\partial L\left( z^{[L]},y \right)}{\partial z^{[L]}}*\frac{\partial z^{[L]} }{\partial z^{[L-1]}}*……\frac{\partial z^{2}}{[z^1]} ∂z[1]∂L(z[1],y)=∂z[L]∂L(z[L],y)∗∂z[L−1]∂z[L]∗……[z1]∂z2
= ∂ L ( z [ L ] , y ) ∂ z [ L ] ∗ W [ L ] ∗ g ( z [ L − 1 ] ) ′ ∗ W [ L − 1 ] ∗ g ( z [ L − 2 ] ) ′ … … W [ 2 ] ∗ g ( z [ 1 ] ) ′ =\frac{\partial L\left( z^{[L]},y \right)}{\partial z^{[L]}}*W^{[L]}*g(z^{[L-1]})^{'}*W^{[L-1]}*g(z^{[L-2]})^{'}……W^{[2]}*g(z^{[1]})^{'} =∂z[L]∂L(z[L],y)∗W[L]∗g(z[L−1])′∗W[L−1]∗g(z[L−2])′……W[2]∗g(z[1])′
接下来求代价函数就是求和之后求个平均值就好了,这里就不在赘述了。
J
(
W
[
1
]
,
b
[
1
]
,
W
[
2
]
,
b
[
2
]
)
=
1
m
∑
i
=
1
m
L
(
y
^
,
y
)
J(W^{[1]},b^{[1]},W^{[2]},b^{[2]}) = {\frac{1}{m}}\sum_{i=1}^mL(\hat{y}, y)
J(W[1],b[1],W[2],b[2])=m1i=1∑mL(y^,y)
吴恩达老师认为反向传播的推导是机器学习领域最难的数学推导之一,矩阵的导数要用链式法则来求,如果这章内容掌握不了也没大的关系,只要有这种直觉就可以了。还有一点,就是初始化你的神经网络的权重,不要都是0,而是随机初始化,下一章将详细介绍原因。
3.11 随机初始化(Random+Initialization)
当你训练神经网络时,权重随机初始化是很重要的。对于逻辑回归,把权重初始化为0当然也是可以的。但是对于一个神经网络,如果你把权重或者参数都初始化为0,那么梯度下降将不会起作用。
让我们看看这是为什么。有两个输入特征,
n
[
0
]
=
2
n^{[0]} = 2
n[0]=2,2个隐藏层单元
n
[
1
]
n^{[1]}
n[1]就等于2。
因此与一个隐藏层相关的矩阵,或者说
W
[
1
]
W^{[1]}
W[1]是2*2的矩阵,假设把它初始化为0的2*2矩阵,
b
[
1
]
b^{[1]}
b[1]也等于
[
0
  
0
]
T
[0\;0]^T
[00]T,把偏置项
b
b
b初始化为0是合理的,但是把
w
w
w初始化为0就有问题了。
那这个问题如果按照这样初始化的话,你总是会发现
a
1
[
1
]
a_{1}^{[1]}
a1[1] 和
a
2
[
1
]
a_{2}^{[1]}
a2[1]相等,这个激活单元和这个激活单元就会一样。因为两个隐含单元计算同样的函数,当你做反向传播计算时,这会导致
dz
1
[
1
]
\text{dz}_{1}^{[1]}
dz1[1] 和
dz
2
[
1
]
\text{dz}_{2}^{[1]}
dz2[1]也会一样,对称这些隐含单元会初始化得一样,这样输出的权值也会一模一样,由此
W
[
2
]
W^{[2]}
W[2]等于
[
0
  
0
]
[0\;0]
[00];
图3.11.1
但是如果你这样初始化这个神经网络,那么这两个隐含单元就会完全一样,因此他们完全对称,也就意味着计算同样的函数,并且肯定的是最终经过每次训练的迭代,这两个隐含单元仍然是同一个函数,令人困惑。
d
W
dW
dW会是一个这样的矩阵,每一行有同样的值因此我们做权重更新把权重
W
[
1
]
  
⟹
  
W
[
1
]
−
a
d
W
W^{[1]}\implies{W^{[1]}-adW}
W[1]⟹W[1]−adW每次迭代后的
W
[
1
]
W^{[1]}
W[1],第一行等于第二行。
由此可以推导,如果你把权重都初始化为0,那么由于隐含单元开始计算同一个函数,所有的隐含单元就会对输出单元有同样的影响。一次迭代后同样的表达式结果仍然是相同的,即隐含单元仍是对称的。通过推导,两次、三次、无论多少次迭代,不管你训练网络多长时间,隐含单元仍然计算的是同样的函数。因此这种情况下超过1个隐含单元也没什么意义,因为他们计算同样的东西。当然更大的网络,比如你有3个特征,还有相当多的隐含单元。
如果你要初始化成0,由于所有的隐含单元都是对称的,无论你运行梯度下降多久,他们一直计算同样的函数。这没有任何帮助,因为你想要两个不同的隐含单元计算不同的函数,这个问题的解决方法就是随机初始化参数。你应该这么做:把
W
[
1
]
W^{[1]}
W[1]设为np.random.randn(2,2)
(生成高斯分布),通常再乘上一个小的数,比如0.01,这样把它初始化为很小的随机数。然后
b
b
b没有这个对称的问题(叫做symmetry breaking problem),所以可以把
b
b
b 初始化为0,因为只要随机初始化
W
W
W你就有不同的隐含单元计算不同的东西,因此不会有symmetry breaking问题了。相似的,对于
W
[
2
]
W^{[2]}
W[2]你可以随机初始化,
b
[
2
]
b^{[2]}
b[2]可以初始化为0。
W
[
1
]
=
n
p
.
r
a
n
d
o
m
.
r
a
n
d
n
(
2
,
2
)
  
∗
  
0.01
  
,
  
b
[
1
]
=
n
p
.
z
e
r
o
s
(
(
2
,
1
)
)
W^{[1]} = np.random.randn(2,2)\;*\;0.01\;,\;b^{[1]} = np.zeros((2,1))
W[1]=np.random.randn(2,2)∗0.01,b[1]=np.zeros((2,1))
W
[
2
]
=
n
p
.
r
a
n
d
o
m
.
r
a
n
d
n
(
2
,
2
)
  
∗
  
0.01
  
,
  
b
[
2
]
=
0
W^{[2]} = np.random.randn(2,2)\;*\;0.01\;,\;b^{[2]} = 0
W[2]=np.random.randn(2,2)∗0.01,b[2]=0
你也许会疑惑,这个常数从哪里来,为什么是0.01,而不是100或者1000。我们通常倾向于初始化为很小的随机数。因为如果你用tanh或者sigmoid激活函数,或者说只在输出层有一个Sigmoid,如果(数值)波动太大,当你计算激活值时 z [ 1 ] = W [ 1 ] x + b [ 1 ]    ,    a [ 1 ] = σ ( z [ 1 ] ) = g [ 1 ] ( z [ 1 ] ) z^{[1]} = W^{[1]}x + b^{[1]}\;,\;a^{[1]} = \sigma(z^{[1]})=g^{[1]}(z^{[1]}) z[1]=W[1]x+b[1],a[1]=σ(z[1])=g[1](z[1])如果 W W W很大, z z z就会很大或者很小,因此这种情况下你很可能停在tanh/sigmoid函数的平坦的地方(见图3.8.2),这些地方梯度很小也就意味着梯度下降会很慢,因此学习也就很慢。
回顾一下:如果
w
w
w很大,那么你很可能最终停在(甚至在训练刚刚开始的时候)
z
z
z很大的值,这会造成tanh/Sigmoid激活函数饱和在龟速的学习上,如果你没有sigmoid/tanh激活函数在你整个的神经网络里,就不成问题。但如果你做二分类并且你的输出单元是Sigmoid函数,那么你不会想让初始参数太大,因此这就是为什么乘上0.01或者其他一些小数是合理的尝试。对于
w
[
2
]
w^{[2]}
w[2]一样,就是np.random.randn((1,2))
,我猜会是乘以0.01。
事实上有时有比0.01更好的常数,当你训练一个只有一层隐藏层的网络时(这是相对浅的神经网络,没有太多的隐藏层),设为0.01可能也可以。但当你训练一个非常非常深的神经网络,你可能要试试0.01以外的常数。下一节课我们会讨论怎么并且何时去选择一个不同于0.01的常数,但是无论如何它通常都会是个相对小的数。
好了,这就是这周的视频。你现在已经知道如何建立一个一层的神经网络了,初始化参数,用前向传播预测,还有计算导数,结合反向传播用在梯度下降中。