终于记起账号系列,接上篇。
1.神经网络表示
- 输入层 :通过输入层输入数据。
- 隐藏层 :通过隐藏的中间层对输入数据进行训练,训练过程中中间节点的真正数值无法通过训练集看到。
- 输出层 :输出模型的预测值。
2.符号约束
- 网络层数 :等于隐藏层加输出层数的和,如上图为一个双层神经网络。(注意:不算入输入层)
- 不同层数据 :采用 a [ i ] a^{[i]} a[i]表示第i层的计算后数据。对于隐藏层而言, a [ i ] a^{[i]} a[i]指的是该层经过激活后的数据;对于输入层,用 a [ 0 ] = X a^{[0]}=X a[0]=X表示。
- 同层数据 :采用 a j [ i ] a^{[i]}_j aj[i]表示第i层第j个节点(/单元),有此可知 a [ i ] a^{[i]} a[i]为一个维数等于该层节点数的列向量,如上图中 a [ 1 ] a^{[1]} a[1]为一个四维向量。
- 参数表示 :隐藏层与输出层均有对应参数,采用 w [ i ] w^{[i]} w[i]表示第i层参数 w w w,采用 b [ i ] b^{[i]} b[i]表示第i层参数 b b b。
- 样本:用右上角圆括号表示样本i,如: x ( i ) x^{(i)} x(i),则: a [ i ] ( j ) a^{[i](j)} a[i](j)表示第j个样本计算至网络第i层后的值, y ^ ( i ) \hat{y}^{(i)} y^(i)表示网络最终计算出的第i个样本的预测值。
3.计算神经网络的输出
- 计算过程
1.每层单个神经元上的计算
对于第i层的第j个神经元,该节点的计算与Logistic回归类似,分为两步,如上图圆环中左右两部分所示。
首先对该层输入的数据 x x x,计算 z j [ i ] = w j [ i ] T x + b j [ i ] z^{[i]}_j=w^{[i]T}_jx+b^{[i]}_j zj[i]=wj[i]Tx+bj[i],然后采用激活函数 a j [ i ] = σ ( z j [ i ] ) a^{[i]}_j=\sigma(z^{[i]}_j) aj[i]=σ(zj[i])激活。,每个神经元计算过程如下图所示。
2.向量化计算
对于某层隐藏层,将该层所有神经元的参数
w
j
[
i
]
w^{[i]}_j
wj[i]的转置竖向堆叠起来,组成该层参数w的矩阵
W
[
i
]
W^{[i]}
W[i],由于
w
j
[
i
]
w^{[i]}_j
wj[i]维度与该层输入数据维度相同,则
w
j
[
i
]
w^{[i]}_j
wj[i]为一个,将参数
b
j
[
i
]
b^{[i]}_j
bj[i]同样竖向堆叠起来,得到参数b的列向量
b
[
i
]
b^{[i]}
b[i],对于单个样本x,该层激活前有:
Z
[
i
]
=
W
[
i
]
a
[
i
−
1
]
+
b
[
i
]
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]})
a[i]=σ(Z[i])。
→推广至多样本情形:
将不同样本用右上角圆括号标注,则有:
Z
[
i
]
(
j
)
=
W
[
i
]
a
[
i
−
1
]
(
j
)
+
b
[
i
]
Z^{[i](j)}=W^{[i]}a^{[i-1](j)}+b^{[i]}
Z[i](j)=W[i]a[i−1](j)+b[i],
a
[
i
]
(
j
)
=
σ
(
Z
[
i
]
(
j
)
)
a^{[i](j)}=\sigma(Z^{[i](j)})
a[i](j)=σ(Z[i](j))
→对训练集采用矩阵表示:
与逻辑回归相同,将训练集中m个样本横向排列,构成训练集矩阵X的列,形成一个
(
n
x
,
m
)
(n_x,m)
(nx,m)维矩阵,矩阵横向对应不同样本,竖向对应每个样本的特征。
同理,训练样本标签矩阵维度为:
(
1
,
m
)
(1,m)
(1,m),横向对应不同样本,竖向对应每个样本的真实标签。
每层参数矩阵仍为
W
[
i
]
W^{[i]}
W[i]与
b
[
i
]
b^{[i]}
b[i],其中
W
[
i
]
W^{[i]}
W[i]矩阵维度为
(
n
[
i
]
,
n
[
i
−
1
]
)
(n^{[i]},n^{[i-1]})
(n[i],n[i−1]),
n
[
i
]
n^{[i]}
n[i]与
n
[
i
−
1
]
n^{[i-1]}
n[i−1]表示该层与前一层单元数;
b
[
i
]
b^{[i]}
b[i]维度为
(
n
[
i
]
,
1
)
(n^{[i]},1)
(n[i],1)
每层激活前矩阵
Z
[
i
]
Z^{[i]}
Z[i]的维度为
(
n
[
i
]
,
m
)
(n^{[i]},m)
(n[i],m),其中横向对应不同样本,竖向
n
[
i
]
n^{[i]}
n[i]表示该层神经元的个数。
同理,每层激活后矩阵
A
[
i
]
=
σ
(
Z
[
i
]
)
A^{[i]}=\sigma(Z^{[i]})
A[i]=σ(Z[i])的维度仍为
(
n
[
i
]
,
m
)
(n^{[i]},m)
(n[i],m)。
→每个隐藏层的矩阵计算为: A [ i ] = σ ( W [ i ] A [ i − 1 ] + b [ i ] ) A^{[i]}=\sigma(W^{[i]}A^{[i-1]}+b^{[i]}) A[i]=σ(W[i]A[i−1]+b[i])
4.激活函数
-
常用激活函数
1.sigmoid函数:
函数公式为 s i g m o i d ( x ) = 1 1 + e − x sigmoid(x)=\frac{1}{1+e^{-x}} sigmoid(x)=1+e−x1,函数值在0与1之间,函数图像如下图所示,通常作用于二元分类输出层。
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,函数值在-1与1之间,多数情况下,在隐藏层使用tanh函数的效果优于使用sigmoid函数,tanh函数可使数据平均值接近0而非sigmoid函数的0.5,其有类似数据中心化的效果。函数图像如下图所示。
3.ReLU函数:
sigmoid和tanh函数都存在的缺点是,当函数输入值很大或很小时,函数曲线的斜率很小(接近于0),函数值变化缓慢,将导致梯度下降变慢,拖慢网络学习速度。
ReLU函数(线性整流函数/修正线性单元)则规避了这一问题。ReLU函数公式为 m a x ( 0 , z ) max(0,z) max(0,z),函数输入值为正时,导数为1,输入值为负时,导数为0。
实际实践过程中,由于ReLU函数没有在函数斜率接近0时减慢学习速度的效应,因此应用ReLU作为激活函数的神经网络比采用tanh和sigmoid的网络学习速度更快。函数图像如下图所示。
4.带泄漏的ReLU函数:
对ReLU函数进行改进,使得当输入值为负数时,函数值与导数不再为0,而是有一个平缓的斜率。函数公式为 m a x ( k z , z ) max(kz,z) max(kz,z),其中k小于1,函数图像如下图所示。
经验法则:
二元分类时,将sigmoid函数作为输出层的激活函数,其他所有单元采用ReLU作为激活函数。 -
为什么需要非线性激活函数
因为若采用线性激活函数(/恒等激活函数),则神经网络将把线性函数作用于输入的线性组合然后再输出,不管网络定义了多少个隐藏层,网络学习一直在进行线性组合过程,多个线性组合的本身就是线性函数,其模型复杂度与逻辑回归相同,失去了使用神经网络的意义。
唯一可能使用线性激活函数的情况是,当机器要学习的是回归问题,此时机器的输出为一个实数,可以将线性激活函数作用于输出层,隐藏层仍然使用非线性激活函数。(ps:实际过程中,在确定要预测输出为一个正实数时,可以在输出层采用ReLU,避免线性激活函数。) -
激活函数的导数
1.sigmoid函数:
g ( z ) = 1 1 + e − z g(z)=\frac{1}{1+e^{-z}} g(z)=1+e−z1, g ′ ( z ) = d d z g ( z ) = g ( z ) ( 1 − g ( z ) ) g'(z)=\frac{d}{dz}g(z)=g(z)(1-g(z)) g′(z)=dzdg(z)=g(z)(1−g(z))
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, g ′ ( z ) = d d z g ( z ) = 1 − g 2 ( z ) g'(z)=\frac{d}{dz}g(z)=1-g^2(z) g′(z)=dzdg(z)=1−g2(z)
3.ReLU函数:
g ( z ) = m a x ( 0 , z ) g(z)=max(0,z) g(z)=max(0,z)
g ′ ( z ) = { 1 i f z > 0 0 i f z < 0 n u l l i f z = 0 g'(z)=\left\{\begin{aligned} 1 if z>0\\ 0 if z<0\\ null ifz=0 \end{aligned} \right. g′(z)=⎩⎪⎨⎪⎧1 ifz>00 ifz<0null ifz=0
2.带泄漏的ReLU函数:
g ( z ) = m a x ( k z , z ) k < 1 g(z)=max(kz,z) k<1 g(z)=max(kz,z) k<1
g ′ ( z ) = { 1 i f z > 0 k i f z < 0 n u l l i f z = 0 g'(z)=\left\{\begin{aligned} 1 if z>0\\ k if z<0\\ null ifz=0 \end{aligned} \right. g′(z)=⎩⎪⎨⎪⎧1 ifz>0k ifz<0null ifz=0 -
神经网络的梯度下降
成本函数:假设网络有n层, n [ i ] n^{[i]} n[i]表示第i层神经元的数量,则成本函数: J ( W [ 1 ] , b [ 1 ] , . . . , W [ n ] , b [ n ] ) = 1 m ∑ i = 1 m l ( y ^ ( i ) , y ( i ) ) J(W^{[1]},b^{[1]},...,W^{[n]},b^{[n]})=\frac{1}{m}\sum_{i=1}^ml(\hat{y}^{(i)},y^{(i)}) J(W[1],b[1],...,W[n],b[n])=m1∑i=1ml(y^(i),y(i))
方法:首先初始化 ω , b \omega,b ω,b,然后进行梯度下降,直至参数收敛。
参数更新公式: W [ i ] = W [ i ] − α d W [ i ] W^{[i]}=W^{[i]}-\alpha dW^{[i]} W[i]=W[i]−αdW[i], b [ i ] = b [ i ] − α d b [ i ] b^{[i]}=b^{[i]}-\alpha db^{[i]} b[i]=b[i]−αdb[i],其中 α \alpha α为学习率。
推导:
对神经网络的第i个隐藏层(若神经网络有n层,则其有n-1个隐藏层),假设该层激活函数为g,则: Z [ i ] = W [ i ] A [ i − 1 ] + b [ i ] Z^{[i]}=W^{[i]}A^{[i-1]}+b^{[i]} Z[i]=W[i]A[i−1]+b[i], A [ i ] = g [ i ] ( Z [ i ] ) A^{[i]}=g^{[i]}(Z^{[i]}) A[i]=g[i](Z[i]), Z [ i + 1 ] = W [ i + 1 ] A [ i ] + b [ i + 1 ] Z^{[i+1]}=W^{[i+1]}A^{[i]}+b^{[i+1]} Z[i+1]=W[i+1]A[i]+b[i+1]。
从而,根据链式求导法则,对于训练集所有样本,由于 J = 1 m ∑ i = 1 m l ( y ^ , y ) J=\frac{1}{m}\sum_{i=1}^ml(\hat{y},y) J=m1∑i=1ml(y^,y),则对第i个隐藏层有:
{ d A [ i ] = d d A [ i ] d Z [ i + 1 ] = W [ i + 1 ] T d Z [ i + 1 ] d Z [ i ] = d d Z [ i ] d A [ i ] = W [ i + 1 ] T d Z [ i + 1 ] ∗ g ′ ( Z [ i ] ) d W [ i ] = d d W [ i ] d Z [ i ] = 1 m d Z [ i ] A [ i − 1 ] T d b [ i ] = d d b [ i ] d Z [ i ] = n p . s u m ( d Z [ i ] , a x i s = 1 , k e e p d i m s = t r u e ) \begin{cases} dA^{[i]}=\frac{d}{dA^{[i]}}dZ^{[i+1]}=W^{[i+1]T}dZ^{[i+1]}\\ dZ^{[i]}=\frac{d}{dZ^{[i]}}dA^{[i]}=W^{[i+1]T}dZ^{[i+1]}*g'(Z^{[i]})\\ dW^{[i]}=\frac{d}{dW^{[i]}}dZ^{[i]}=\frac{1}{m}dZ^{[i]}A^{[i-1]T}\\ db^{[i]}=\frac{d}{db^{[i]}}dZ^{[i]}=np.sum(dZ^{[i]},axis=1,keepdims=true) \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧dA[i]=dA[i]ddZ[i+1]=W[i+1]TdZ[i+1]dZ[i]=dZ[i]ddA[i]=W[i+1]TdZ[i+1]∗g′(Z[i])dW[i]=dW[i]ddZ[i]=m1dZ[i]A[i−1]Tdb[i]=db[i]ddZ[i]=np.sum(dZ[i],axis=1,keepdims=true)
注意1:上面几个式子中,有的矩阵加了转置,在神经网络中,为了避免矩阵维度出错,需要经常回顾不同矩阵的维度,以判断是否该加转置以及如何加。
注意2:矩阵求导后维度与求导前相同,如: d Z [ i ] dZ^{[i]} dZ[i]与 Z [ i ] Z^{[i]} Z[i]的维度相同, d W [ i ] dW^{[i]} dW[i]与 W [ i ] W^{[i]} W[i]维度相同。
###5.参数随机初始化
在训练神经网络之前,首先要对参数进行随机初始化,注意参数不能全部初始化为0,因为若其全部初始为0,则每层的所有隐藏单元完全对称,每个隐藏单元都计算同样的函数,得到的是完全相同的输出,在进行梯度下降时,每个单元得到的梯度相同,设置隐藏单元将失去意义。
正确的初始化方法为将W随机初始化,参数b可以初始化为0,令 W [ i ] = n p . r a n d o m . r a n d n ( ( n [ i ] , n [ i − 1 ] ) ) ∗ 0.01 , b [ i ] = n p . z e r o s ( ( n [ i ] , 1 ) ) W^{[i]}=np.random.randn((n^{[i]},n^{[i-1]}))*0.01, b^{[i]}=np.zeros((n^{[i]},1)) W[i]=np.random.randn((n[i],n[i−1]))∗0.01,b[i]=np.zeros((n[i],1)),对W随机初始化时乘以0.01的目的是将各项权重初始化为很小的值,这是因为在对 Z [ i ] Z^{[i]} Z[i]进行激活时,若W很大,则 Z [ i ] Z^{[i]} Z[i]将很大,若采用tanh或sigmoid函数激活,则将导致梯度变化缓慢而拖慢学习速度。(ps:在训练浅层神经网络时,采用0.01是可行的,但训练一个深层神经网络时,可能尝试选用0.01以外的其他常数效果会更好。)