前馈神经网络
神经网络
神经网络,或称为人工神经网络(Artificial Neural Networks, ANN),是一种模仿生物神经网络结构和功能的计算模型,用于估计或逼近那些无法用传统算法精确表示的复杂函数关系。广泛应用于语音识别、图像识别、NLP等。
神经网络中最基本的单元是神经元(neuron)。生物学结构如下图所示:
M-P神经元模型正是对这一结构进行了抽象,其中树突对应于输入部分,每个神经元收到其他神经元传递过来的输入信号,如下图:
假设一个神经元接收 d 个输入信号 x1,x2,⋯,xd ,记作向量 x 。这些信号通过带权重的连接传递给细胞体,细胞体先计算输入信号的加权和,然后通过激活函数处理产生神经元的输出,称为活性值 (activation)
a=g(wTx+b)
其中权重向量 x 又称为连接权(connection weight)。
下图给出了一个典型的神经元结构示例
将多个神经元按一定的层次结构连接起来,就得到了多层神经网络,也称为前馈神经网络 (Feedforward Neural Network, FNN) 或多层感知器 (Multi-Layer Perceptron, MLP)。有三部分组成,分别是输入层(input layer)、隐藏层(hide layer)以及输出层(output layer)。神经元向下游其他神经元的输出称为激活值 (activation value)。一个没有隐藏层且输出层只有一个单元的神经网络就相当于线性的Logistic模型。
深度学习是指使用多层神经网络的机器学习方法。一个深度学习模型通常包含多个隐藏层,能够学习数据的高级特征和抽象表示。深度学习在近年来取得了显著的进展,推动了人工智能领域的发展。
逻辑回归
给定的数据集
D={(x1,y1),(x2,y2),⋯,(xN,yN)}
包含 N 个样本,d 个特征。其中,第 i 个样本的特征向量为 xi=(xi1,xi2,⋯,xid)T 。目标变量 yi∈{0,1} 。
再来重温下逻辑回归:Given x, want y^=P(y=1∣x) 。是一个单层且只有一个输出的神经网络,输出层的激活值 a 即为模型的输出 y^=a
Model:
y^=a=σ(wTx+b)
Activation function:
σ(z)=1+e−z1
Loss function:
ℓ(a,y)=−yloga−(1−y)log(1−a)
Cost function:
J(w,b)=N1i=1∑Nℓ(ai,yi)
给定学习率 η,参数 w,b 的更新公式为
w←w−η∇wJ(w,b)b←b−η∇bJ(w,b)
对于单个样本,根据链式法则
∇wℓ(a,y)=∂a∂ℓσ′(z)∂w∂z
其中损失函数的梯度
∂a∂ℓ(a,y)=−ay+1−a1−y=a(1−a)a−y
激活函数的梯度
σ′(z)=σ(z)(1−σ(z))=a(1−a)
第三项
∂w∂z=x
最终得到一个简洁的式子
∇wℓ(a,y)=(a−y)x
同理
∂b∂ℓ(a,y)=a−y
上面计算图中,出于方便,约定损失函数 ℓ 对任意变量 θ 的梯度简记为 δθ,即 δθ=∂θ∂ℓ(a,y) 。
现在,我们计算整个数据集上的梯度
∂w∂J(w,b)=N1i=1∑N(ai−yi)xi∂b∂J(w,b)=N1i=1∑N(ai−yi)
其中
ai=y^i=σ(wTxi+b)
为了计算方便,约定特征向量 x=(1,x1,x2,⋯,xd)T,权重向量 w=(b,w1,w2,⋯,wd)T。
上述梯度计算的矩阵形式为
∇wJ(w)=N1X(a−y)wherea=σ(XTw)
其中
X=⎣⎢⎢⎢⎡1x11⋮x1d1x21⋮x2d⋯⋯⋱⋯1xN1⋮xNd⎦⎥⎥⎥⎤,w=⎣⎢⎢⎢⎡bw1⋮wd⎦⎥⎥⎥⎤,y=⎣⎢⎢⎢⎡y1y2⋮yN⎦⎥⎥⎥⎤
至此,我们便可以用梯度下降法训练模型。
全连接神经网络
全连接神经网络(Full Connection, FC)是一种最基本的神经网络结构,FC 的准则很简单:神经网络中除输入层之外的每个节点都和上一层的所有节点有连接。下图是一个单隐层的全连接神经网络,由于输入层不涉及计算,通常不计入层数,如下图中神经网络层数为 2。
实际上,1989年Robert Hecht-Nielsen证明了对于任何闭区间内的一个连续函数都可以用一个单隐含层的前馈神经网络来逼近,这就是通用近似定理。所以一个两层的神经网络就可以完成任意的维到维的映射。虽然一个单隐层网络能学习任何函数, 但并不意味着我们应该尝试使用单隐藏层网络来解决所有问题。 事实上,通过使用更深(而不是更广)的网络,我们可以更容易地逼近许多函数。
为方便计算,神经网络符号约定如下:
- 以方括号上标表示所在的层。神经网络的总层数记为 L,则第 l 层上标为 [l],输入层上标为 [0],输出层上标为 [L]。
- 以 d[l] 表示第 l 层神经元的个数。aj[l] 表示第 l 层第 j 个神经元的激活值,wj[l] 和 bj[l] 则分别表示其权重向量和偏移量。易知,wj[l] 是一个 d[l−1] 维向量。
- 函数 g(z) 表示神经元的激活函数。
记每一层激活值组成激活向量
a=[a1a2⋯]T
第 l 层的每一个神经元的激活值
aj[l]=g[l](zj[l])wherezj[l]=wj[l]⋅a[l−1]+bj[l]
激活向量的矩阵形式为
a[l]=g[l](z[l])wherez[l]=W[l]a[l−1]+b[l]
其中,权重组成 d[l]×d[l−1] 维矩阵
W[l]=⎣⎡∣w1[l]∣∣w2[l]∣⋯∣wd[l][l]∣⎦⎤T
这样,前馈神经网络可以通过逐层的信息传递,得到网络最后的输出。整个网络可以看作一个复合函数。将向量 x 作为第 1 层的输入 a[0],将第 L 层的输出 a[L]作为整个函数的输出。
x=a[0]→z[1]→a[1]→z[2]→⋯a[L−1]→z[L]→a[L]→=y^
最后,定义N 个样本的数据集组成的 d[l]×N 维激活值矩阵
A=⎣⎡∣a1∣∣a2∣⋯∣aN∣⎦⎤
计算第 l 层的激活值矩阵
A[l]=g[l](Z[l])whereZ[l]=W[l]A[l−1]+B[l]
其中, B[l]=[b[l],b[l],⋯,b[l]] 是列向量都相同的 d[l]×N 维偏移矩阵。
反向传播算法
给定的数据集
D={(x1,y1),(x2,y2),⋯,(xN,yN)}
包含 N 个样本,d 个特征。其中,第 i 个样本的特征向量为 xi=(xi1,xi2,⋯,xid)T 。
在深度神经网络中,损失函数通常是非凸的,所以只能求得数值解,而梯度下降法是最常用的方法。
给定学习率 η 和代价函数
J(W,b)=N1i=1∑Nℓ(y^i,yi)
第 l 层参数的梯度下降更新公式为
W←W−η∇WJb←b−η∇bJ
下图演示了单隐层神经网络是怎么计算梯度的
上面计算图中,出于方便,约定损失函数 ℓ 对任意变量 θ 的梯度简记为 δθ,即 δθ=∂θ∂ℓ(y^,y) 。
这便是深度学习的核心之一,反向传播算法。涉及前向传播和反向传播两个主要过程。
前向传播(Forward Propagation, FP)相当简单,数据从输入层流向输出层,依次计算出每层的激活值,最后计算损失。每一层有两部分组成
z[l]=W[l]a[l−1]+b[l]a[l]=g[l](z[l])
反向传播(Backward Propagation, BP),是一个应用链式法则的递归过程。我们从输出层开始,反向计算每一层的梯度。
第 l 层损失对权重的梯度较为复杂,我们从矩阵元素的角度出发,再推广到矩阵。
∂Wij[l]∂ℓ=∂zi[l]∂ℓ∂Wij[l]∂zi[l]=∂zi[l]∂ℓaj[l−1]
现在我们将这个标量结果重塑为矩阵形式:
∂W[l]∂ℓ=δ[l](a[l−1])T
其中,δ[l] 称为误差项(Error Term) ,用来简化链式法则的应用
δ[l]=∂z[l]∂ℓ
同理得到损失对偏置的梯度
∂b[l]∂ℓ=δ[l]
接下来推导反向传播误差项的递归计算公式,也是反向传播的关键步骤。我们从 z[l+1] 和 z[l] 的关系出发:
z[l+1]=W[l+1]al+b[l+1]=W[l+1]g[l](z[l])+b[l+1]
应用链式法则得到:
δ[l]=(W[l+1])Tδ[l+1]⊙g[l] ′(z[l])
其中 ⊙ 是矩阵的 Hadamard 积运算符,表示每个元素相乘。这个递归方程允许我们从输出层 δ[L] 开始,一路反向迭代计算 δ[L],δ[L−1],⋯,δ[1]。
对于输出层误差
δ[L]=∂a[L]∂ℓ⊙g[L] ′(z[L])
∂a[L]∂ℓ 取决于具体的损失函数。
最后,将梯度应用到 N 个样本的数据集,定义
A=⎣⎡∣a1∣∣a2∣⋯∣aN∣⎦⎤,Z=⎣⎡∣z1∣∣z2∣⋯∣zN∣⎦⎤
则权重梯度
∂W[l]∂J=N1i=1∑N∂W[l]∂ℓ(y^i,yi)
可写为
∂W[l]∂J=Δ[l](A[l−1])T
误差项矩阵
Δ[l]=∂Z[l]∂J=(W[l+1])TΔ[l+1]⊙g[l] ′(Z[l])
至此,我们便完成了反向传播算法的计算流程。
以下是 mini-batch 梯度下降算法的伪代码
mini-batch 符号约定如下
激活函数
我们知道神经网络模拟了人类神经元的工作机理,激活函数(Activation Function)是一种添加到人工神经网络中的函数,旨在帮助网络学习数据中的复杂模式。因为神经网络中每一层只是对输入做线性变换,所以如果没有激活函数,那么无论你构造的神经网络多么复杂,有多少层,最后的输出都是输入层的线性组合,纯粹的线性组合并不能够解决更为复杂的问题。所以,激活函数必须使用非线性函数。
下面我们介绍几个常用的激活函数:
Sigmoid 函数取值范围为 (0,1),是一个十分常见的激活函数
g(z)=1+exp(−z)1

tanh 函数取值范围为 (−1,1),函数的表达式如下:
g(z)=1+exp(−2z)1−exp(−2z)

tanh 的输出间隔为 1,并且整个函数以 0 为中心,比 sigmoid 函数更好。
ReLU (Rectified Linear Unit) 激活函数提供了一个很简单的非线性变换。在目前的深度神经网络中被广泛使用。
g(z)=max(0,z)

Sigmoid 函数和 tanh 函数都有一个缺点,就是如果 z 非常大或非常小,那么函数的梯度就可能很小,从而减慢学习速度。ReLU 函数只存在线性关系,收敛速度更快,是目前许多从业者训练神经网络中最常见的选择。
然而,当输入为负时,ReLU 梯度为0。这个神经元及之后的神经元梯度永远为0,不再对任何数据有所响应,导致相应参数永远不会被更新。称为 Dead ReLU 问题。
Leaky ReLU 函数是ReLU 的一个变体,当输入为负值时,他有一个很平缓的斜率,函数不在为0。
g(z)=max(γ,z)

其中,γ 是一个很小的数,如0.1,0.01等。
从理论上讲,Leaky ReLU 具有 ReLU 的所有优点,而且一定程度上缓解了 dead ReLU 问题,但在实际操作中,尚未完全证明 Leaky ReLU 总是比 ReLU 更好。
梯度消失和梯度爆炸
梯度消失和梯度爆炸问题都发生在反向传播过程中,反向传播通过链式法则将输出层的损失误差一层一层的向前传播,以计算每一层参数的梯度。对于深度网络,计算每一层的梯度公式大致如下:
∂W[l]∂ℓ=δ[l](a[l−1])T
其中
δ[l]=(W[l+1])Tδ[l+1]⊙g[l] ′(z[l])
实际上是一连串的乘法,主要包含后面所有层的权重矩阵 WL,WL−1,⋯,Wl+1 和各层激活函数的导数 g[L] ′(z[L]),g[L−1] ′(z[L−1]),⋯,g[l] ′(z[l]) 。
- 梯度消失(Vanishing Gradient):如果使用了 Sigmoid 或者 Tanh 激活函数,从导函数图像中了解到梯度值都小于1,在反向传播过程中,梯度值随着层数的回溯而指数级的减小,以至于传播到早期层时,梯度变得几乎为0,因此这些权重几乎得不到更新。同时,如果权重初始值本身也非常小,也会加剧连乘的缩小效应。
- 梯度爆炸(Exploding Gradient):主要原因是权重初值过大,或者训练过程中变得很大,那么连乘会导致指数级增长,导致损失值剧烈震荡,难以收敛。
ReLU 激活函数在正区间的导数为1,一定程度上改善了梯度消失问题。同时也要使用更智能的初始化方法,防止初始权重过大或过小。
初始化
在训练神经网络时,权重通常是随机初始化的,而不可能全部设为零。若所有权重初始值均为零,在前向计算时,所有的隐藏层神经元的激活值都相同。在反向传播时,所有权重的更新也都相同,导致神经网络无法学习不同的特征。一种最简单的随机初始化方法是从一个固定均值和方差的分布中采样来生成参数的初始值。同时,如果权重的初始值过大或过小,则可能会导致梯度消失或梯度爆炸。
Xavier 初始化
Wij∼N(0,m+n2)
或者
Wij∼U(−m+n6,m+n6)
其中 m 代表该层神经元的输入数量,n 代表该层神经元的输出数量。能够有效地避免梯度消失和梯度爆炸问题,适用于sigmoid/tanh。然而,它不适用于 ReLU 激活函数,因为 ReLU 会导致激活值的非对称性。
He 初始化
Wij∼N(0,m(1+γ2)2)
或者
Wij∼U(−m(1+γ2)6,m(1+γ2)6)
更适合 ReLU/Leaky ReLU 变换的性质。其中 γ 是 Leaky ReLU 在负值时的斜率。
批量归一化
深度神经网络的训练十分复杂,因为在训练过程中随着前一层网络参数的变化,下一层网络的输入分布也会发生变化。进行归一化可以使得数据具有相似的分布范围,提高模型的求解速度和泛化能力。另外,归一化还可以减少梯度消失或梯度爆炸等问题,使参数初始化不敏感,在训练深度神经网络时比较常用。
批量归一化(Batch Normalization) 发生在计算激活函数之前
Z[l]=W[l]A[l−1]+B[l]Z~[l]=BN(Z[l];β[l],γ[l])A[l]=g[l](Z~[l])
具体的算法如下图所示:
新的均值和方差由两个显式参数 γ 和 β 控制。
正则化
L1/L2正则化
正则化(Regularization)是机器学习中防止模型过拟合的一种技术。通过在损失函数中加入一个惩罚项(penalty term),限制模型参数的大小,从而提高模型的泛化能力。L1 正则化和 L2 正则化是两种常见的正则化方法,分别适用于不同的场景。
J~=J+2λl=1∑L∥W[l]∥F2
其中 ∥W∥F2=ij∑(wij)2 表示Frobenius范数。
带正则化项的梯度下降更新公式:
W[l]←W[l]−η∂W[l]∂J−ηλW[l]
在神经网络中,参数包括每一层神经元的权重(weight)和偏置(bias),我们通常只对权重做惩罚而不对偏置做正则惩罚,也不会导致太大的方差。另外,正则化偏置参数可能会导致明显的欠拟合。
正则化参数 λ 通过缩小特征权重来控制模型复杂度,值越大,相应的 W 越小,从而 z=Wa+b 也会相应变小。假设使用 Sigmoid 或 tanh 函数,则会接近0附近的线性部分,从而降低模型的复杂度。选择合适的正则化参数可以在防止过拟合和避免欠拟合之间取得平衡。
Dropout
当训练一个深度神经网络时,我们可以随机丢弃一部分神经元(同时丢弃其对应的连接边)来控制模型的复杂度,这种方法称为Dropout。Dropout为神经网络中的每个节点设置一个固定的概率 p 来判定要不要保留。
dropout(x)={x/p0with probability potherwise
为保持期望不变,在训练时,激活神经元的值为原来的 1/p 倍。
E[x]=0⋅(1−p)+p⋅px=x
一般来讲,对于隐藏层的神经元,其保留率 p=0.5 时效果最好,这对大部分的网络和任务都比较有效。训练的网络都是由这些随机生成的更小网络计算得到的,打破了神经元之间的依赖性,强迫网络学习更鲁棒的神经元连接。对于输入层的神经元,其保留率通常设为更接近1的数,使得输入变化不会太大。对输入层神经元进行丢弃时,相当于给数据增加噪声,以此来提高网络的鲁棒性。
Early Stopping
提前停止(Early Stopping)对于深度神经网络来说是一种简单有效的正则化方
法。由于深度神经网络的拟合能力非常强,因此比较容易在训练集上过拟合。使用梯度下降法进行优化时,我们可以使用一个和训练集独立的样本集合,称为验证集(Validation Set),并用验证集上的错误来代替期望错误。当验证集上的错误不再下降,就停止迭代。
数据增强
深度神经网络一般都需要大量的训练数据才能获得比较理想的效果。在数据量有限的情况下,可以通过数据增强(Data Augmentation)来增加数据量,提高模型鲁棒性,避免过拟合。目前,数据增强还主要应用在图像数据上,在文本等其他类型的数据上还没有太好的方法。
图像数据的增强主要是通过算法对图像进行转变,引入噪声等方法来增加数据的多样性。增强的方法主要有几种:
- 旋转(Rotation):将图像按顺时针或逆时针方向随机旋转一定角度;
- 翻转(Flip):将图像沿水平或垂直方向随机翻转一定角度;
- 缩放(Zoom In/Out):将图像放大或缩小一定比例;
- 平移(Shift):将图像沿水平或垂直方法平移一定步长;
- 加噪声(Noise):加入随机噪声;