深度学习——第6章 浅层神经网络(NN)

第6章 浅层神经网络(NN)

目录

[6.1 神经网络模型概述](#6.1 神经网络模型概述)

[6.2 神经网络正向传播](#6.2 神经网络正向传播)

[6.3 神经网络反向传播](#6.3 神经网络反向传播)

[6.4 W和b的初始化](#6.4 W和b的初始化)

[6.5 总结](#6.5 总结)

上一课主要介绍了一些神经网络必备的基础知识,包括Sigmoid激活函数、损失函数、梯度下降和计算图。这些知识对学习神经网络非常有用。本节将开始真正的神经网络学习,从一个浅层的神经网络出发,详细推导其正向传播和反向传播完整过程。

6.1 神经网络模型概述

首先,我们来看一个简单的神经网络模型:

最简单的神经网络模型由输入层(Input Layer)、隐藏层(Hidden Layer)、输出层(Output Layer)组成,我们称之为2层神经网络。隐藏层和输出层都由个数不一的神经元组成。如上图所示,输入层有3个输入:x1、x2、x3,分别代表不同的输入特征。例如一张图片所有的像素值(当然不止3个)。一般地,输入层不标注 ◯ \bigcirc ◯,表示没有神经元。该神经网络模型隐藏层包含了4个神经元,输出层只有1个神经元。

需要特别注意的是,在解决二分类或者预测问题时,输出层神经元个数为1。如果是多分类问题,输出层就需要多个神经元。这里先介绍最简单的神经网络模型,多分类问题之后再详细介绍。

第1章已经介绍过单个神经元的结构:

单个神经元包含参数 W W W和 b b b,分别称之为权重系数(参数)和常数项。 W W W的维度与输入 x x x的维度相同, b b b是单个元素的标量。神经元整个计算过程分成两部分:线性计算和非线性计算。

我们来看上面的神经网络模型,输入层矩阵 x x x的维度是(3,1)。通常我们习惯把 X X X记为 a 0 a^{0} a0,上标0表示输入层。因为输入层没有神经元计算,所以用0标注。隐藏层有4个神经元,每个神经元均与 a 0 a^{0} a0 连接。因此,隐藏层的权重系数 W 1 W^{1} W1的维度是(4,3),注意这里的上标1表示隐藏层。隐藏层的常数项 b 1 b^{1} b1的维度是(4,1)。输出层只有1个神经元,与4个隐藏层神经元相连接。因此,输出层的权重

数 W 2 W^{2} W2的维度是(1,4),上标2表示输出层。同理,输出层常数项 b 2 b^{2} b2的维度是(1,1),即只有一个元素。

神经网络每次迭代训练由正向传播和反向传播两部分组成。正向传播就是训练样本数据通过输入层-->隐藏层-->输出层,经过各层神经元计算后得到预测值,预测值与真实样本标签误差产生损失函数。然后,再进行反向传播。为了让损失函数减小,利用梯度下降算法,更新权重系数 W W W和常数项 b b b。这样就完成了一次迭代训练。经过多次的迭代训练之后,通常能使损失函数逐渐减小,最终确定最优化时对应的 W W W和 b b b。这样,整个神经网络的训练过程就结束了。

6.2 神经网络正向传播

知道了输入 x x x,参数 W 1 W^{1} W1、 b 1 b^{1} b1、 W 2 W^{2} W2、 b 2 b^{2} b2的维度之后,接下来重点推导一下神经网络的正向传播过程。

6.2.1 网络输出

从输入层到隐藏层,h1、h2、h3、h4神经元计算分为线性部分和非线性部分,整个过程可以写成:

z 1 1 = W 1 1 x + b 1 1 , a 1 1 = g ( z 1 1 ) z_1^{1}=W_1^{1}x+b_1^{1},\ \ a_1^{1}=g(z_1^{1}) z11=W11x+b11, a11=g(z11)

z 2 1 = W 2 1 x + b 2 1 , a 2 1 = g ( z 2 1 ) z_2^{1}=W_2^{1}x+b_2^{1},\ \ a_2^{1}=g(z_2^{1}) z21=W21x+b21, a21=g(z21)

z 3 1 = W 3 1 x + b 3 1 , a 3 1 = g ( z 3 1 ) z_3^{1}=W_3^{1}x+b_3^{1},\ \ a_3^{1}=g(z_3^{1}) z31=W31x+b31, a31=g(z31)

z 4 1 = W 4 1 x + b 4 1 , a 4 1 = g ( z 4 1 ) z_4^{1}=W_4^{1}x+b_4^{1},\ \ a_4^{1}=g(z_4^{1}) z41=W41x+b41, a41=g(z41)

其中,下标表示第几个神经元。例如 z j l z_j^{l} zjl就表示第 l l l层的第 j j j个神经元。注意, j j j从1开始, l l l从0开始。 z j l z_j^{l} zjl是线性输出, a j l a_j^{l} ajl是非线性输出, g ( ⋅ ) g(\cdot) g(⋅)表示激活函数。关于激活函数,稍后详细介绍。

从隐藏层到输出层,只有一个out神经元。注意此时神经元的输入不是 x x x,而是隐藏层的输出 a 1 a^{1} a1。整个过程为:

z 1 2 = W 1 2 a 1 + b 1 2 , a 1 2 = g ( z 1 2 ) z_1^{2}=W_1^{2}a^{1}+b_1^{2},\ \ a_1^{2}=g(z_1^{2}) z12=W12a1+b12, a12=g(z12)

为了提高程序运算速度,我们利用之前介绍的向量化思想,将上述表达式转换成矩阵运算的形式:

z 1 = W 1 x + b 1 z^{1}=W^{1}x+b^{1} z1=W1x+b1

a 1 = g ( z 1 ) a^{1}=g(z^{1}) a1=g(z1)

z 2 = W 2 a 1 + b 2 z^{2}=W^{2}a^{1}+b^{2} z2=W2a1+b2

a 2 = g ( z 2 ) a^{2}=g(z^{2}) a2=g(z2)

以上介绍的是单个样本的正向传输过程,如果有m个样本,则输入X的维度为(3,m)。最简单的可以使用for循环来计算其正向输出。这里,我们用上标(i)表示第i个样本。过程如下:

for i=1 to m:

Z 1 ( i ) = W 1 X ( i ) + b 1 Z^{1(i)}=W^{1}X^{(i)}+b^{1} Z1(i)=W1X(i)+b1

A 1 ( i ) = g ( Z 1 ( i ) ) A^{1(i)}=g(Z^{1(i)}) A1(i)=g(Z1(i))

Z 2 ( i ) = W 2 A 1 ( i ) + b 2 Z^{2(i)}=W^{2}A^{1(i)}+b^{2} Z2(i)=W2A1(i)+b2

A 2 ( i ) = g ( Z 2 ( i ) ) A^{2(i)}=g(Z^{2(i)}) A2(i)=g(Z2(i))

这里,X、Z、A都采用大写的形式,表示矩阵。 Z 1 Z^{1} Z1和 A 1 A^{1} A1的维度为(4,m), Z 2 Z^{2} Z2和 A 2 A^{2} A2的维度为(1,m)。对这四个矩阵均可以这样理解:行表示第几个神经元,列表示样本数目m。

不使用for循环,直接采用矩阵运算的形式,可得:

Z 1 = W 1 X + b 1 Z^{1}=W^{1}X+b^{1} Z1=W1X+b1

A 1 = g ( Z 1 ) A^{1}=g(Z^{1}) A1=g(Z1)

Z 2 = W 2 A 1 + b 2 Z^{2}=W^{2}A^{1}+b^{2} Z2=W2A1+b2

A 2 = g ( Z 2 ) A^{2}=g(Z^{2}) A2=g(Z2)

这样,我们就完整地计算了神经网络模型的正向传播过程。有时候,为了便于理解, X X X也可以用 A 0 A^{0} A0表示。

6.2.2 激活函数

神经网络每个神经元都需要激活函数(Activation Function)来进行非线性运算。在上一篇中介绍的逻辑回归模型使用的Sigmoid函数,也是一种激活函数。下面重点介绍几个神经网络常用的激活函数 g ( x ) g(x) g(x),并作简单比较。

(1)Sigmoid函数

函数表达式为:

a = 1 1 + e − z a=\frac{1}{1+e^{-z}} a=1+e−z1

(2)tanh函数

函数表达式为:

a = e z − e − z e z + e − z a=\frac{e^z-e^{-z}}{e^z+e^{-z}} a=ez+e−zez−e−z

(3)ReLU函数

函数表达式为:

a = m a x ( 0 , z ) a = max(0,z) a=max(0,z)

(4)Leaky ReLU函数

函数表达式为:

a = { λ z , z ⩽ 0 z , z > 0 a=\left\{\begin{array}{cc} \lambda z, & z\leqslant0\\ z, & z> 0 \end{array}\right. a={λz,z,z⩽0z>0

其中, λ \lambda λ为可变参数,一般 λ ∈ ( 0 , 1 ) \lambda\in(0,1) λ∈(0,1),例如 λ = 0.01 \lambda=0.01 λ=0.01。

介绍完了这些常用的激活函数之后,考虑如何选择合适的激活函数呢?首先我们来比较Sigmoid函数和tanh函数。对于隐藏层的激活函数,一般来说,tanh函数要比Sigmoid函数表现更好一些。因为tanh函数的取值范围在(-1,+1),即隐藏层的输出被限定在(-1,+1)之间,可以看成是在0值附近分布,均值为0。这样从隐藏层到输出层,数据起到了归一化(均值为0)的效果。因此,隐藏层的激活函数,tanh比Sigmoid更好一些。而对于输出层的激活函数,因为二分类问题的输出取值为0, 1之间,所以一般会选择Sigmoid作为激活函数。

观察Sigmoid函数和tanh函数,我们发现有这样一个问题,就是当 ∣ z ∣ |z| ∣z∣很大的时候,激活函数的斜率(梯度)很小。因此,在这个区域内,梯度下降算法会运行得比较慢。在实际应用中,应尽量避免使z落在这个区域,使 ∣ z ∣ |z| ∣z∣尽可能限定在零值附近,从而提高梯度下降算法运算速度。

为了弥补Sigmoid函数和tanh函数的这个缺陷,就出现了ReLU激活函数。ReLU激活函数在 z z z大于零时梯度始终为1;在 z z z小于零时梯度始终为0; z z z等于零时的梯度可以当成1也可以当成0,实际应用中并不影响。对于隐藏层,选择ReLU作为激活函数能够保证 z z z大于零时梯度始终为1,从而提高神经网络梯度下降算法运算速度。但当 z z z小于零时,存在梯度为0的缺点。实际应用中,这个缺点影响不是很大,但为了弥补这个缺点,出现了Leaky ReLU激活函数,能够保证 z z z小于零时梯度不为0。

值得注意的是,如果是二分类问题,输出层可以使用Sigmoid激活函数。如果是预测问题,输出层则可以不需要使用激活函数,因为预测值一般在整个实数范围之间。又或者,如果输出值总是正数,例如房价预测问题,则可以使用ReLU激活函数。

因此,是否使用激活函数,使用哪个激活函数,并不是固定不变的,需要根据问题本身进行考量和判断,做到活学活用,真正理解。本文为了简化内容,仅仅以二分类为例,介绍神经网络的基本模型。更复杂的情况,后面的章节将会详细介绍。

有的人可能会有疑问:为什么每个神经元需要非线性单元,需要激活函数?以上面这个神经网络模型为例,我们来看如果没有激活函数,模型最后的输出是什么。

假设没有激活函数,则有 A = Z A = Z A=Z。那么,神经网络的各层输出为:

Z 1 = W 1 X + b 1 Z^{1}=W^{1}X+b^{1} Z1=W1X+b1

A 1 = Z 1 A^{1}=Z^{1} A1=Z1

Z 2 = W 2 A 1 + b 2 Z^{2}=W^{2}A^{1}+b^{2} Z2=W2A1+b2

A 2 = Z 2 A^{2}=Z^{2} A2=Z2

直接对 A 2 A^{2} A2表达式展开:

A 2 = W 2 A 1 + b 2 = W 2 ( W 1 X + b 1 ) + b 2 = ( W 2 W 1 X ) + ( W 2 b 1 + b 2 ) = W ′ X + b ′ A^{2}=W^{2}A^{1}+b^{2}=W^{2}(W^{1}X+b^{1})+b^{2}\\=(W^{2}W^{1}X)+(W^{2}b^{1}+b^{2})=W'X+b' A2=W2A1+b2=W2(W1X+b1)+b2=(W2W1X)+(W2b1+b2)=W′X+b′

经过推导,发现 A 2 A^{2} A2仍是输入变量 X X X的线性组合。这表明,使用神经网络与直接使用线性模型的效果并没有什么两样。即便是包含多层隐藏层的神经网络,如果不使用非线性激活函数,最终的输出仍然是输入 X X X的线性模型。这样的话神经网络就没有任何作用了。另外,如果只有输出层使用非线性激活函数,那么整个神经网络的结构就类似于一个简单的逻辑回归模型,而失去了神经网络模型本身的优势和价值。因此,隐藏层一般必须使用非线性激活函数。

6.3 神经网络反向传播

神经网络正向传播最终得到的输出 Y ^ = A 2 \hat Y=A^{2} Y^=A2。因为是二分类问题,其损失函数与逻辑回归模型一样,在上一篇已经推导过逻辑回归模型的损失函数:

L = − y l o g y \^ + ( 1 − y ) l o g ( 1 − y \^ ) L=-ylog\\hat y+(1-y)log(1-\\hat y) L=−ylogy\^+(1−y)log(1−y\^)

对于 m m m个样本的损失函数为:

J = − 1 m ∑ i = 1 m y ( i ) l o g y ^ ( i ) + ( 1 − y ( i ) ) l o g ( 1 − y ^ ( i ) ) J=-\frac{1}{m}\sum_{i=1}^my^{(i)}log\hat y^{(i)}+(1-y^{(i)})log(1-\hat y^{(i)}) J=−m1i=1∑my(i)logy^(i)+(1−y(i))log(1−y^(i))

接下来,我们来计算损失函数 J J J对各个变量 A 2 A^{2} A2, Z 2 Z^{2} Z2, W 2 W^{2} W2, b 2 b^{2} b2, A 1 A^{1} A1, Z 1 Z^{1} Z1, W 1 W^{1} W1, b 1 b^{1} b1的偏导数。

J J J对 A 2 A^{2} A2求偏导数:

d A 2 = ∂ J ∂ A 2 = A 2 − Y A 2 ( 1 − A 2 ) dA^{2}=\frac{\partial J}{\partial A^{2}}=\frac{A^{2}-Y}{A^{2}(1-A^{2})} dA2=∂A2∂J=A2(1−A2)A2−Y

J J J对 Z 2 Z^{2} Z2求偏导数:

d Z 2 = d A 2 ⋅ ∂ A 2 ∂ Z 2 dZ^{2}=dA^{2}\cdot\frac{\partial A^{2}}{\partial Z^{2}} dZ2=dA2⋅∂Z2∂A2

这里,若使用Sigmoid激活函数,它的导数为:

g ( z ) ′ = a ( 1 − a ) g(z)'=a(1-a) g(z)′=a(1−a)

则有:

∂ A 2 ∂ Z 2 = A 2 ( 1 − A 2 ) \frac{\partial A^{2}}{\partial Z^{2}}=A^{2}(1-A^{2}) ∂Z2∂A2=A2(1−A2)

将其带入 d Z 2 dZ^{2} dZ2中,得:

d Z 2 = A 2 − Y A 2 ( 1 − A 2 ) ⋅ A 2 ( 1 − A 2 ) = A 2 − Y dZ^{2}=\frac{A^{2}-Y}{A^{2}(1-A^{2})}\cdot A^{2}(1-A^{2})=A^{2}-Y dZ2=A2(1−A2)A2−Y⋅A2(1−A2)=A2−Y

发现 d Z 2 dZ^{2} dZ2的表达式是不是很简单呢?

J 对 W 2 J对W^{2} J对W2求偏导数:

d W 2 = 1 m d Z 2 ⋅ ∂ Z 2 ∂ W 2 = 1 m d Z 2 ⋅ A 1 T dW^{2}=\frac1m dZ^{2}\cdot\frac{\partial Z^{2}}{\partial W^{2}}=\frac1m dZ^{2}\cdot A^{1T} dW2=m1dZ2⋅∂W2∂Z2=m1dZ2⋅A1T

其中, A 1 T A^{1T} A1T表示 A 1 A^{1} A1的转置。

J 对 b 2 J对b^{2} J对b2 求偏导数:

d b 2 = 1 m n p . s u m ( d Z 2 , a x i s = 1 ) db^{2}=\frac1mnp.sum(dZ^{2},\ \ axis=1) db2=m1np.sum(dZ2, axis=1)

这里的np.sum()是Python Numpy中的求和函数,参数axis = 0表示矩阵行相加,axis = 1表示矩阵列相加。

J J J对 A 1 A^{1} A1求偏导数:

d A 1 = d Z 2 ⋅ ∂ Z 2 ∂ A 1 = W 2 T ⋅ d Z 2 dA^{1}=dZ^{2}\cdot\frac{\partial Z^{2}}{\partial A^{1}}=W^{2T}\cdot dZ^{2} dA1=dZ2⋅∂A1∂Z2=W2T⋅dZ2

J 对 Z 1 J对Z^{1} J对Z1求偏导数:

d Z 1 = d A 1 ⋅ ∂ A 1 ∂ Z 1 = d A 1 ∗ g 1 ′ ( Z 1 ) = W 2 T ⋅ d Z 2 ∗ g 1 ′ ( Z 1 ) dZ^{1}=dA^{1}\cdot\frac{\partial A^{1}}{\partial Z^{1}}=dA^{1}*g^{1'}(Z^{1})=W^{2T}\cdot dZ^{2}*g^{1'}(Z^{1}) dZ1=dA1⋅∂Z1∂A1=dA1∗g1′(Z1)=W2T⋅dZ2∗g1′(Z1)

其中, g 1 ′ ( Z 1 ) g^{1'}(Z^{1}) g1′(Z1)表示 A 1 A^{1} A1对 Z 1 Z^{1} Z1的导数。上式中的*号表示两个矩阵对应元素相乘, ⋅ \cdot ⋅表示矩阵相乘。

J J J对 W 1 W^{1} W1求偏导数:

d W 1 = d Z 1 ⋅ ∂ Z 1 ∂ W 1 = 1 m d Z 1 ⋅ A 0 T dW^{1}=dZ^{1}\cdot\frac{\partial Z^{1}}{\partial W^{1}}=\frac1mdZ^{1}\cdot A^{0T} dW1=dZ1⋅∂W1∂Z1=m1dZ1⋅A0T

J J J对 b 1 b^{1} b1求偏导数:

d b 1 = 1 m n p . s u m ( d Z 1 , a x i s = 1 ) db^{1}=\frac1mnp.sum(dZ^{1},\ \ axis=1) db1=m1np.sum(dZ1, axis=1)

好了,我们已经完整地推导了神经网络反向传播过程。

我把正向传播和反向传播涉及的公式全都整理出来,以供查阅:

计算完 W W W和 b b b的导数之后,利用上一篇介绍过的梯度下降算法,更新 W W W和 b b b:

W 1 = W 1 − η ⋅ d W 1 W^{1}=W^{1}-\eta\cdot dW^{1} W1=W1−η⋅dW1

b 1 = b 1 − η ⋅ d b 1 b^{1}=b^{1}-\eta\cdot db^{1} b1=b1−η⋅db1

W 2 = W 2 − η ⋅ d W 2 W^{2}=W^{2}-\eta\cdot dW^{2} W2=W2−η⋅dW2

b 2 = b 2 − η ⋅ d b 2 b^{2}=b^{2}-\eta\cdot db^{2} b2=b2−η⋅db2

其中, η \eta η是学习因子。

6.4 W和b的初始化

神经网络模型在开始训练时需要对各层权重系数 W W W和常数项 b b b进行初始化赋值。初始化赋值时, b b b一般全部初始化为0即可,但是 W W W不能全部初始化为0。接下来我们来分析一下原因。

还是上面的神经网络模型,如果 W 1 W^{1} W1和 W 2 W^{2} W2全部初始化为0,即:

W 1 = 0 0 0 0 0 0 0 0 0 0 0 0 W^{1}= \left \\begin{matrix} 0 \& 0 \& 0 \& 0\\\\ 0 \& 0 \& 0 \& 0\\\\ 0 \& 0 \& 0 \& 0 \\end{matrix} \\right W1= 000000000000

W 2 = 0 0 0 0 W^{2}= \left \\begin{matrix} 0 \& 0 \& 0 \& 0 \\end{matrix} \\right W2=0000

这样使得隐藏层四个神经元的输出都相同,即:

A 1 1 = A 2 1 = A 3 1 = A 4 1 A_1^{1}=A_2^{1}=A_3^{1}=A_4^{1} A11=A21=A31=A41

经过推导得到:

d Z 1 1 = d Z 2 1 = d Z 3 1 = d Z 4 1 dZ_1^{1}=dZ_2^{1}=dZ_3^{1}=dZ_4^{1} dZ11=dZ21=dZ31=dZ41

以及:

d W 1 1 = d W 2 1 = d W 3 1 = d W 4 1 dW_1^{1}=dW_2^{1}=dW_3^{1}=dW_4^{1} dW11=dW21=dW31=dW41

因此,隐藏层四个神经元对应的权重行向量 W 1 1 W_1^{1} W11、 W 2 1 W_2^{1} W21、 W 3 1 W_3^{1} W31、 W 4 1 W_4^{1} W41每次迭代更新都会得到完全相同的结果。也就是说,始终有:

W 1 1 = W 2 1 = W 3 1 = W 4 1 W_1^{1}=W_2^{1}=W_3^{1}=W_4^{1} W11=W21=W31=W41

这样隐藏层设置多个神经元就没有任何意义了。

所以,一般对 W W W进行随机初始化。相应的Python语句为:

复制代码
W1 = np.random.randn((4,3))*0.01
b1 = np.zero((4,1))
W2 = np.random.randn((1,4))*0.01
b2 = 0    

值得注意的是,W1和W2都习惯性地乘以0.01。究其原因,是因为如果使用Sigmoid或者tanh作为激活函数的话, W W W比较小,得到的 ∣ Z ∣ |Z| ∣Z∣也比较小(零点附近),而零点附近区域的梯度比较大,这样能大大提高梯度下降算法的更新速度,尽快找到全局最优解。如果 W W W较大,得到的 ∣ Z ∣ |Z| ∣Z∣也比较大,接近曲线平缓区域,梯度很小,更新速度慢,训练过程也会慢很多。当然,如果使用ReLU或者Leaky ReLU,则可以不乘以0.01。

6.5 总结

本文主要介绍了最简单的2层神经网络模型,详细推导其正向传播过程和反向传播过程,得到了各权重系数W和常数项b的导数表达式。我们也列举了常见的四种激活函数,分析各自的优缺点。最后,简单解释了参数初始化的方法和注意事项。

相关推荐
SLAM必须dunk38 分钟前
GMR(General Motion Retargeting)仓库详细解析
机器学习·机器人
钓了猫的鱼儿2 小时前
基于深度学习+AI的城市人行道障碍物目标检测与预警系统(Python源码+数据集+UI可视化界面+YOLOv11训练结果)
人工智能·深度学习·目标检测
HackTorjan7 小时前
2026年5月29日:全球首个通用人工智能操作系统正式发布,开启人机协同新纪元
人工智能
刘大猫.7 小时前
智造短剧新引擎:火山引擎上线「火山剧创 1.0」,制作效率提升 80%
人工智能·ai·chatgpt·机器人·大模型·火山引擎·短剧新引擎
红尘散仙7 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
雅菲奥朗7 小时前
企业级 AI 自动化|OpenClaw 龙虾实战与认证
运维·人工智能·自动化·openclaw
HIT_Weston8 小时前
99、【Agent】【OpenCode】task 工具提示词(Slash command)(一)
人工智能·agent·opencode
25 Hz8 小时前
Mind 爱好者时空表征刊 第24期 | 时间结构学习、空间对时间表征的补偿、事件内部的时间扭曲……
人工智能
心中有国也有家8 小时前
GE图引擎深度解析——CANN的计算图优化与执行引擎
人工智能·pytorch·python·学习·numpy
海兰8 小时前
【文字三国志:第一篇】天命重构,大语言模型(LLM)动态生成文言风格的叙事文本的文字游戏
人工智能·游戏·语言模型