1. 神经网络概览
在之前的学习中,关于逻辑回归问题的流程图计算方式可以看作是一个简单的神经网络,给定输入变量
x
x
x,能够得到输出$$y,类似的,神经网络的表示可以如下如所示:
x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3这些特征称之为输入层(input layer),中间的一层称之为隐藏层(hidden layer),最后的一层称之为输出层(output layer),在监督学习训练中,只能够看到输入层的数据和输出层的结果,而中间隐藏层的数据是不可见的。
以上神经网络中,令 a [ 0 ] = X a^{[0]} = X a[0]=X,表示输入层(第0层)的输入向量,而令 a 1 [ 1 ] , a 2 [ 1 ] , a 3 [ 1 ] , a 4 [ 1 ] a^{[1]}_1,a^{[1]}_2,a^{[1]}_3,a^{[1]}_4 a1[1],a2[1],a3[1],a4[1]表示隐藏层的四个单元,并且隐藏层是一个4×1的列向量。用 a [ 2 ] a^[2] a[2]表示输出层的单元,并且 a [ 2 ] ] = y ^ a^{[2]]}= \hat{y} a[2]]=y^
2. 神经网络的输出计算
如上图所示的神经网络,其计算过程可以由下图表示:
如上所示,神经网络的输入有3个特征,
w
w
w是一个4×3的矩阵,
输入
x
x
x是一个
3
×
1
3×1
3×1的列向量,而
b
b
b是一个4×1的列向量,所以,根据公式
z
=
w
T
x
+
b
z = w^Tx+b
z=wTx+b,
z
z
z也是一个4×1的列向量,如下图所示:
3.多个样本的向量化
根据已经规定好的符号,多个样本的神经网络实现方式可以有以下伪代码所示:
对于多个样本,输入变量
x
x
x可以视之为一个n×m的矩阵,
n
n
n代表的是输入变量的特征数,
m
m
m代表的是输入的样本数。
假设有三个样本,则其计算方式可以如下表示,,为了简化计算,令
b
=
0
b = 0
b=0,则有:
z
[
1
]
(
1
)
=
w
[
1
]
x
(
1
)
z^{[1](1)} = w^{[1]}x^{(1)}
z[1](1)=w[1]x(1)
z
[
1
]
(
2
)
=
w
[
1
]
x
(
2
)
z^{[1](2)} = w^{[1]}x^{(2)}
z[1](2)=w[1]x(2)
z
[
1
]
(
3
)
=
w
[
1
]
x
(
3
)
z^{[1](3)} = w^{[1]}x^{(3)}
z[1](3)=w[1]x(3)
根据之前所述, w [ 1 ] w^{[1]} w[1]是一个矩阵, x x x是一个列向量,而 w [ 1 ] ∗ x w^{[1]}*x w[1]∗x也会得到一个列向量,根据样本数目,将所得到的列向量组合成一个新的矩阵 Z [ 1 ] Z^{[1]} Z[1],整个计算过程,可以由下图所示:
对于2层神经网络,向量化得实现公式,如下所示:
4. 激活函数
神经网络中,隐藏层和输出层需要选择激活函数,在逻辑回归中,选择的激活函数是 s i g m o i d sigmoid sigmoid激活函数,除了此激活函数外,还有一些可供选择的激活函数。
除了 s i g m o i d sigmoid sigmoid函数,还可以选择双曲正切函数,正切函数的表达式如下所示:
KaTeX parse error: \tag works only in display equations
函数图像,如下所示,事实上可以看成是
s
i
g
m
o
i
d
sigmoid
sigmoid函数的一个平移变化得到的
事实上,在隐藏层中使用 t a n h tanh tanh函数,输出层使用 s i g m o i d sigmoid sigmoid函数是一个更好的选择,因为其输出值的范围是(-1,1)之间,其平均值更有可能是0,具有数据中心化的作用。
对于
t
a
n
h
tanh
tanh函数和
s
i
g
m
o
i
d
sigmoid
sigmoid函数而言,当
z
z
z的值较大或者较小的时候,函数的斜率几乎为0,会导致收敛速度过慢,为此,特意引入线性修正单元,称之为Relu单元,正如以下函数图像所示,可以明显的看出该函数不可微,通常其表达式可以写成
KaTeX parse error: \tag works only in display equations
除了以上一种线性修正单元外,还有另外一种线性修正单元,其函数表示为KaTeX parse error: \tag works only in display equations
被称之为带泄漏激活函数(Leaky ReLu),此种激活函数保证了当
z
=
0
z = 0
z=0时,其导数是一个常数,而不是0,其图像如下所示:
对二元分类问题(0,1)的激活函数选择,有以下经验:
- 在输出层选择 s i g m o i d sigmoid sigmoid作为激活函数,而在其他层选择ReLu,即线性激活单元。
激活函数在神经网络中的应用是十分必要的,如果没有激活函数,那么输出只不过是输入的线性组合,而且隐藏层也无法发挥其作用,不如直接去掉整个隐藏层。
5. 激活函数的导数
神经网络反向传播算法的计算过程,需要计算激活函数的导数。
对于上述激活函数,其导数计算分别如下所示:
-
s i g m o i d sigmoid sigmoid函数,有:
g ′ ( z ) = g ( z ) ∗ ( 1 − g ( z ) ) (4) g^{'}(z) = g(z)*(1-g(z))\tag{4} g′(z)=g(z)∗(1−g(z))(4) -
t a n h tanh tanh函数,其导数为
g ′ ( z ) = 1 − t a n h 2 ( z ) (5) g^{'}(z) = 1-tanh^{2}(z)\tag{5} g′(z)=1−tanh2(z)(5) -
线性修正单元(ReLu)的激活函数,有:
g ′ ( z ) = { 1 , i f z ≥ 0 0 , i f z < 0 (6) g^{'}(z)=\begin{cases} 1,\quad if \quad z\ge 0\\ 0, \quad if \quad z<0 \end{cases}\tag{6} g′(z)={1,ifz≥00,ifz<0(6) -
带泄漏的线性修正单元(leaky - ReLu)的激活函数,有:
g ′ ( z ) = { 1 , i f z ≥ 0 0.01 , i f z < 0 (7) g^{'}(z)=\begin{cases} 1,\quad \quad if \quad z\ge 0\\ 0.01, \quad if \quad z<0 \end{cases}\tag{7} g′(z)={1,ifz≥00.01,ifz<0(7)
6. 神经网络的梯度下降
在上一周的课程中,已经推导过了神经网络的反向传播算法,以一个双层的神经网络为例,其梯度下降的推导过程如下所示:
在前向传播过程中,先计算
z
[
1
]
z^{[1]}
z[1],
a
[
1
]
a^{[1]}
a[1],再计算
z
[
2
]
z^{[2]}
z[2],
a
[
2
]
a^{[2]}
a[2],最后得到损失函数。
其反向传播算法,正好与前向传播算法想反,整个计算过程,以双层神经网络为例,如下公式所示:
d
Z
[
2
]
=
A
[
2
]
−
Y
(8)
dZ^{[2]} = A^{[2]} -Y\tag{8}
dZ[2]=A[2]−Y(8)
d
W
[
2
]
=
1
m
d
Z
[
2
]
A
[
1
]
T
(9)
dW^{[2]} = \frac{1}{m}dZ^{[2]}A^{[1]T}\tag{9}
dW[2]=m1dZ[2]A[1]T(9)
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
)
(10)
db^{[2]} = \frac{1}{m}np.sum(dZ^{[2]},axis= 1,keepdims= True)\tag{10}
db[2]=m1np.sum(dZ[2],axis=1,keepdims=True)(10)
d
Z
[
1
]
=
W
[
2
]
T
d
Z
[
2
]
∗
g
[
1
]
′
(
Z
[
1
]
)
(11)
dZ^{[1]} = W^{[2]T}dZ^{[2]} * g[1]^{'}(Z^{[1]})\tag{11}
dZ[1]=W[2]TdZ[2]∗g[1]′(Z[1])(11)
d
W
[
1
]
1
m
d
Z
[
1
]
x
T
(12)
dW^{[1]} \frac{1}{m}dZ^{[1]}x^T\tag{12}
dW[1]m1dZ[1]xT(12)
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
)
(13)
db^{[1]} = \frac{1}{m}np.sum(dZ^{[1]},axis=1,keepdims = True)\tag{13}
db[1]=m1np.sum(dZ[1],axis=1,keepdims=True)(13)
7. 随机初始化
神经网络开始计算之前,需要初始化参数,逻辑回归中,将参数初始化为0,而在其他神经网络中,这一做法通常不可取。
就以以下神经网络为例,有两个输入特征,当我们将初始化参数
w
w
w和
b
b
b全部设置为0时,
a
1
[
1
]
=
a
2
[
1
]
a^{[1]}_1 = a^{[1]}_2
a1[1]=a2[1],并且
d
z
1
[
1
]
=
d
z
2
[
1
]
dz^{[1]}_1 = dz^{[1]}_2
dz1[1]=dz2[1],这意味着你的神经网络在中两个隐藏层是对称的,都在计算同样的函数,造成了冗余,这种情况通常称之为 symmetry breaking problem.
对神经网络中的初始化参数
w
w
w的取值,通常可以采用随机初始化参数,如上所述的神经网络,在python中,通常可以如下所示(生成高斯分布,并乘以0.01):
w
[
1
]
=
n
p
.
r
a
n
d
o
m
.
r
a
n
d
n
(
(
2
,
2
)
)
∗
0.01
w^{[1]} = np.random.randn((2,2)) * 0.01
w[1]=np.random.randn((2,2))∗0.01
b
[
1
]
=
n
p
.
z
e
r
o
s
(
(
2
,
1
)
)
b^{[1]} = np.zeros((2,1))
b[1]=np.zeros((2,1))
w
[
2
]
=
n
p
.
r
a
n
d
o
m
.
r
a
n
d
n
(
(
1
,
2
)
)
∗
0.01
w^{[2]} = np.random.randn((1,2))*0.01
w[2]=np.random.randn((1,2))∗0.01
b
[
2
]
=
0
b^{[2]} = 0
b[2]=0
生成的每个权重乘以0.01的原因是,如果激活函数是 s i g m o i d ( z ) sigmoid(z) sigmoid(z)函数或者 t a n h ( z ) tanh(z) tanh(z)函数,避免造成国道的 z z z值,使得函数值进入饱和区,收敛速度太慢。