Neural Networks
A Neuron
神经元是一种通用计算单元,它接收n个输入并产生单个输出。不同神经元的输出之所以不同,在于它们的参数(也称为权重)。神经元最常用的选择之一是“ sigmoid”或“二元逻辑回归”单元。该单元接收一个n维输入向量x,并产生标量激活值(输出)a。这个神经元还与一个n维权重向量w和一个偏置标量b相关联。这个神经元的输出如下:
a=\frac{1}{1+exp \left(-\left(w^{T} x+b\right)\right)}也可以表示为:
a=\frac{1}{1+exp \left(-\left[w^{T} b\right] \cdot\left[\begin{array}{ll}x & 1\end{array}\right]\right)}可以用下图表示

图2:此图展示了在Sigmoid神经元中,输入向量x是如何先被缩放、求和、加上偏置单元,然后再传入压缩型Sigmoid函数的过程。
A Single Layer of Neurons
我们将上述想法扩展到多个神经元,考虑如图3所示的情况:输入x被作为输入提供给多个这样的神经元。
如果我们将不同神经元的权重称为w1 .....wm,将偏置称为b1....bm,那么可以说相应的激活值是a1....am
\begin{aligned} a_{1} & =\frac{1}{1+exp \left(w^{(1) T} x+b_{1}\right)} \\ \vdots & \\ a_{m} & =\frac{1}{1+exp \left(w^{(m) T} x+b_{m}\right)} \end{aligned}为了使符号简洁并对更复杂的网络有用,我们定义以下抽象概念:
\sigma(z)=\left[\begin{array}{c}\frac{1}{1+exp \left(z_{1}\right)} \\ \vdots \\ \frac{1}{1+exp \left(z_{m}\right)}\end{array}\right] \\
b=\left[\begin{array}{c}b_{1} \\ \vdots \\ b_{m}\end{array}\right] \in \mathbb{R}^{m} \\
W=\left[\begin{array}{ccc} - & w^{(1) T} & - \\ & ... & \\ - & w^{(m) T} & -\end{array}\right] \in \mathbb{R}^{m × n}我们现在可以将缩放和偏置的输出写成:
z=W x+b
sigmoid函数的激活值可写为:
\left[\begin{array}{c} a^{(1)} \\ \vdots \\ a^{(m)} \end{array}\right]=\sigma(z)=\sigma(W x+b)
feed-forward Compulation
到目前为止,我们已经了解了如何将输入向量x∈Rn输入到sigmoid单元层,以生成激活值a∈Rm。但这样做背后的直觉是什么呢?让我们以自然语言处理(NLP)中的命名实体识别(NER)问题为例来思考:
"Museums in Paris are amazing"
在这里,我们想判断中心词 “Paris” 是否为命名实体(命名实体通常指人名、地名、机构名等有特定指代的词,这里 “Paris” 是地名,属于命名实体)。要完成这个判断,模型需要利用 “中心词周围的词”(即 “词窗口”)的信息。这种判断属于非线性决策(原因在后文)。 这种非线性决策通常无法通过直接输入到Softmax函数中来捕捉,而是需要上文讨论的中间层进行评分(对输入向量x做 “非线性变换”,提取出 “词间交互” 的特征)。进一步,我们需要使用另一个矩阵U∈Rm×1,根据激活值为分类任务生成一个未归一化的分数,降维到1维:
s = U ^ { T } a = U ^ { T } f ( W x + b )其中f是激活函数
如果我们直接把输入向量x喂给 Softmax 函数做分类,本质上是用线性模型(如逻辑回归、线性 SVM)做判断。但线性模型的核心局限是:只能捕捉 “单个词的存在与否”,无法捕捉 “词与词之间的交互关系”。
“Museums 是第一个词” 这个信息是否重要,取决于第二个词是不是 “in”—— 只有当 “Museums” 和 “in” 同时出现在窗口的前两个位置时(即 “Museums in ...”),才更能暗示后面的 “Paris” 是地名(比如 “Museums in Paris” 表示 “巴黎的博物馆”,直接指向 “Paris” 的地名属性);如果第二个词不是 “in”(比如 “Museums near Paris” 或 “Museums Paris are...”),“Museums” 的作用就完全不同。
这种 “词与词的条件依赖关系”(A 词的意义需结合 B 词判断)属于非线性关系,而线性模型(直接喂x给 Softmax)只能计算 “每个词向量的加权和”,无法表达这种 “交互逻辑”—— 就像 “1+1=2” 和 “1×1=1” 的区别,线性模型只能做 “加法组合”,而 “交互关系” 需要 “乘法级别的非线性组合”。

最大间隔目标函数
与大多数机器学习模型一样,神经网络也需要一个优化目标,即一种误差或优良度的度量标准,我们分别希望将其最小化或最大化。在这里,我们将讨论一种常用的误差指标,称为最大间隔目标。使用这一目标的核心思想是让 “正确的” 得分(s)比 “错误的” 得分(sc)高。
那么,我们的目标函数将是最大化(s-sc)或最小化(sc-s)。然而,我们对目标进行了修改,以确保仅当sc>s =>(sc-s)>0 时才计算误差。损失函数可以写为:
minimize J=max \left(s_{c}-s, 0\right)当s>sc 的时候,说明正确得分大于错误的,无需优化;sc>s时,说明还有优化空间。
然而,上述优化目标存在风险,因为它并未尝试建立安全边际。我们希望“真实”标记的数据点比“虚假”标记的数据点高出某个正边际Δ。换句话说,我们希望仅在(s-sc<Δ)时计算误差,而不仅仅是在s-sc<0时计算。因此,我们对优化目标进行了修改:
minimize J=max \left(\Delta+s_{c}-s, 0\right)在上述表述中,
s_{c}=U^{T} f(W x_{c}+b) \\ s=U^{T} f(W x+b)反向传播
由于我们通常使用梯度下降(或其变体,如随机梯度下降)来更新参数,因此通常需要更新方程中所需的任何参数的梯度信息:


\theta^{(t+1)}=\theta^{(t)}-\alpha \nabla_{\theta(t)} J接下来以图5为例,进行反向传播,下面是一些术语:
- xi 是神经网络的输入。
- s是神经网络的输出。
- 每一层(包括输入层和输出层)都有接收输入并产生输出的神经元。第k层的j-th神经元接收标量输入zjk,并产生标量激活输出ajk。
- 第1层指的是输入层,而非第一个隐藏层。对于输入层,xj=zj1=aj1.
- Wk是将第k层的输出映射到k+1层输入的传递矩阵。
- 我们将在zjk处计算的反向误差成为δj(k)
让我们开始:假设成本J=(1+sc-s)为正,并且我们想要对参数W14(1)进行更新(见图5和图6),我们必须认识到W14(1)仅对z1(2)和a1(2) 有贡献,(对z2(2),a2(2) 没有影响)。这一事实对于理解反向传播至关重要——反向传播的梯度仅受它们所贡献的值的影响。从最大间隔损失中我们可以看到:
\frac{\partial J}{\partial s}=-\frac{\partial J}{\partial s_{c}}=-1


让我们以图6为例,更好地讨论反向传播的“误差共享/分布”解释。假设我们要更新W14(1):
- 我们从反向传播a1(3)的1的误差信号开始。
- 然后,我们将这个误差乘以神经元的局部梯度,该神经元z1(3)将映射到a1(3)。在这种情况下,这个梯度恰好是1,因此误差仍然是1。现在,这被称为δ1(3)。
- 此时,I的误差信号已达到z1(3)。我们现在需要分配误差信号,使误差的“公平份额”到达a1(2)。
- 计算a1(2)处的误差=W1(2)×δ1(3),所以a1(2)=W1(2)
- 正如我们在步骤2中所做的那样,我们需要将误差传递到将z1(2)映射到a1(2)的神经元。我们通过将a1(2)处的误差信号乘以该神经元的局部梯度(恰好为f'(z1(2)))来实现这一点。
- 得到隐藏层z1(2)处的误差δ1(2) = f'(z1(2))× W1(2)
- 最后,我们需要通过简单地将“公平份额”的误差乘以它负责转发的输入(即a4(2)),将其分配给W14(1)。
- 因此,损失相对于W14(1)的梯度经计算为a4(1)f'(z1(2)) W1(2)
请注意,我们使用这种方法得到的结果与之前使用显式微分得到的结果完全相同。因此,我们可以通过微分的链式法则,或者通过误差共享和分布式流方法来计算网络中参数的误差梯度——这两种方法实际上做的是完全相同的事情,但从不同角度去理解它们可能会有所帮助。
Generalized steps to propagateδ(k) to δ(k-1) :
- 已知 k 层第 i 个神经元的误差 δi⁽ᵏ⁾
- 我们通过将 δi⁽ᵏ⁾乘以路径权重Wi,j(k-1),将此误差反向传播至aj(k-1)。
- 因此,在aj(k-1)处收到的误差为δi⁽ᵏ⁾Wi,j(k-1)
- 然而,如图8所示,aj(k-1)可能已被转发到下一层的多个节点。它也应该承担从第k层节点反向传播的错误的责任,使用完全相同的机制。
- 因此,在aj(k-1)处收到的误差为δi⁽ᵏ⁾Wi,j(k-1)+δm⁽ᵏ⁾Wm,j(k-1)
- 事实上,我们可以将其概括为Σiδi⁽ᵏ⁾ Wi,j(k-1)
- 既然我们在aj(k-1)处得到了正确的误差,我们就通过与局部梯度f'(zj(k-1))相乘,将其传递到k-1层的神经元j。
- 因此,到达zj(k-1)的误差(称为 δ(k-1))是
f'\left(z_{j}^{(k-1)}\right) \sum_{i} \delta_{i}^{(k)} W_{i j}^{(k-1)}Neural Networks: Tips and Tricks
Gradient check
在上一节中,我们详细讨论了如何通过基于微积分(解析)的方法计算神经网络模型中参数的误差梯度/更新。现在我们介绍一种数值逼近这些梯度的技术——尽管这种方法计算效率太低,无法直接用于训练网络,但它可以非常精确地估计任何参数的导数;因此,它可以作为检验我们解析导数正确性的有用工具。给定一个具有参数向量θ和损失函数J的模型,围绕θi的数值梯度可通过中心差分公式简单给出:
f'(\theta) \approx \frac{J\left(\theta^{(i+)}\right)-J\left(\theta^{(i-)}\right)}{2 \epsilon}其中,ϵ是一个小数(通常在1e-5左右)。术语J(θ(i+))只是当我们将参数θ'sith元素扰动+ 6时,在给定输入的前向传播中计算出的误差。类似地,术语J(θ(i-))是当我们将参数θ'sith元素扰动-ϵ时,在相同输入的前向传播中计算出的误差。因此,通过两次前向传播,我们可以逼近模型中任何给定参数元素的梯度。我们注意到,数值梯度的这种定义非常自然地源于导数的定义,在标量情况下,
f'(x) \approx \frac{f(x+\epsilon)-f(x)}{\epsilon}当然,这里存在一个细微的差别——上面的定义仅在正方向上对x进行扰动来计算梯度。虽然以这种方式定义数值梯度是完全可行的,但在实际应用中,使用中心差分公式往往更为精确和稳定,该公式会在两个方向上对参数进行扰动。其直观思路是,要更好地近似某点附近的导数/斜率,我们需要考察函数f's在该点左右两侧的行为。通过泰勒定理也可以证明,中心差分公式的误差与ϵ2成比例,这一误差相当小,而导数定义则更容易产生误差。
现在,你可能会问一个很自然的问题:如果这种方法如此精确,那我们为什么不使用它来计算所有的网络梯度,而是采用反向传播呢?简单来说,正如前面所暗示的,答案在于效率——要知道,每次我们想计算某个元素的梯度时,都需要进行两次前向传播,这在计算上会非常昂贵。此外,许多大规模神经网络可能包含数百万个参数,而每个参数计算两次传播显然不是最优的。而且,由于在诸如随机梯度下降(SGD)之类的优化技术中,我们必须在数千次迭代中每次迭代计算一次梯度,显然这种方法很快就会变得难以处理。正是这种低效性,使得我们只使用梯度检查来验证解析梯度的正确性,而解析梯度的计算要快得多。
正则化
与许多机器学习模型一样,神经网络极易发生过拟合现象,即模型在训练数据集上能取得近乎完美的性能,但却失去了对未见过的数据的泛化能力。解决过拟合(这一问题也被称为“高方差问题”)的一种常用技术是引入L2正则化惩罚项。其思路是,我们只需在损失函数J后附加一个额外项,这样总代价的计算方式就变为:
J_{R}=J+\lambda \sum_{i=1}^{L}\left\| W^{(i)}\right\| _{F}在上述公式中,||W(i)|| 是矩阵W(i)(网络中的第i个权重矩阵)的弗罗贝尼乌斯范数,λ是控制正则化项相对于原始成本函数权重的超参数。由于我们试图最小化JR,正则化的本质作用是在对原始成本函数进行优化时,对过大的权重进行惩罚。由于弗罗贝尼乌斯范数具有二次性质(它计算矩阵元素的平方和),L2正则化有效地降低了模型的灵活性,从而减少了过拟合现象。施加这样的约束也可以解释为贝叶斯先验信念,即最优权重接近零——接近的程度取决于λ的值。选择合适的λ值至关重要,且必须通过超参数调优来确定。λ值过高会导致大多数权重被设置得过于接近0,模型无法从训练数据中学习到任何有意义的信息,往往在训练集、验证集和测试集上都获得较差的准确率。λ值过低,则我们会再次陷入过拟合的境地。需要注意的是,偏置项不会被正则化,也不会对上述成本项产生影响.
确实存在其他类型的正则化方法有时会被使用,例如L1正则化,它对参数元素的绝对值(而非平方值)求和——不过,这种方法在实际应用中不太常见,因为它会导致参数权重的稀疏性。在下一节中,我们将讨论 dropout 方法,它通过在前向传播中随机丢弃(即设为零)神经元,有效地起到了另一种形式的正则化作用。
dropout
Dropout是一种强大的正则化技术,由Srivastava等人在《Dropout:一种防止神经网络过拟合的简单方法》中首次提出。其理念简单却有效——在训练过程中,我们会在每次前向/反向传播时以一定概率(1-p)随机“丢弃”一部分神经元(或者说,每个神经元有概率p保持激活状态)。而在测试时,我们会使用完整的网络来进行预测。这样做的结果是,网络通常能从数据中学习到更有意义的信息,更不容易过拟合,并且在手头的任务上整体表现通常更优。这种技术之所以如此有效的一个直观解释是,Dropout本质上是同时训练指数级数量的更小网络,并对它们的预测结果进行平均。
在实际应用中,我们引入 dropout 的方式是:对于每一层神经元的输出 h,我们以概率 p 保留每个神经元,否则将其设为 0。然后,在反向传播过程中,我们只通过前向传播中被保留的神经元传递梯度。最后,在测试阶段,我们使用网络中所有的神经元进行前向传播计算。然而,一个关键的细节是,为了使 dropout 有效发挥作用,测试期间神经元的预期输出应该与训练期间大致相同——否则输出的幅度可能会有很大差异,网络的行为也将不再明确。因此,我们通常必须在测试期间将每个神经元的输出除以某个值——读者需要自行思考这个值应该是多少,才能使训练和测试期间的预期输出相等。
激活函数
到目前为止,我们已经讨论了包含 sigmoidal 神经元以引入非线性的神经网络;然而,在许多应用中,可以使用其他激活函数设计出更好的网络。这里列出了一些常见的选择及其函数和梯度定义,它们可以替代上面讨论的 sigmoidal 函数。
Sigmoid:这是我们讨论过的默认选择;激活函数σ由下式给出:
\sigma(z)=\frac{1}{1+exp (-z)}
\\ where \sigma(z) \in(0,1)
sigma(z)的梯度为:
\sigma'(z)=\frac{-exp (-z)}{1+exp (-z)}=\sigma(z)(1-\sigma(z))
数据预处理
均值减法
给定一组输入数据X,通常的做法是通过从X中减去X的特征均值向量来对数据进行零中心化处理。一个重要的点是,在实际操作中,均值仅根据训练集计算,并且这个均值会从训练集、验证集和测试集中减去。
归一化
另一种常用的技术(尽管可能不如均值减法常用)是将每个输入特征维度缩放至具有相似的数值范围。这很有用,因为输入特征通常以不同的“单位”衡量,但我们通常希望在初始阶段将所有特征视为同等重要。实现这一点的方法是简单地将特征除以其在训练集上计算出的各自标准差。
Whitening
与均值减法+归一化相比,白化的使用并不那么普遍,它本质上是将数据转换为具有单位协方差矩阵——也就是说,特征变得不相关且方差为1。这通常是通过首先对数据进行均值减法来完成的,得到X'。然后,我们可以对X'进行奇异值分解(SVD),得到矩阵u、S、V。接着,我们计算U X',将X'投影到由u的列所定义的基中。最后,我们将结果的每个维度除以S中相应的奇异值,以对数据进行适当缩放(如果奇异值为零,我们可以改用一个小数来除)。
参数初始化
要让神经网络实现卓越性能,一个关键步骤是对参数进行合理的初始化。一种不错的初始策略是将权重初始化为围绕0呈正态分布的小随机数——实际上,这种方法通常能取得令人满意的效果。不过,在《Understanding the difficulty of training deep feedforward neural networks》(2010年)中,泽维尔等人研究了不同的权重和偏置初始化方案对训练动态的影响。实证结果表明,对于sigmoid和tanh激活单元而言,当矩阵的权重满足下面条件的时候,能实现更快的收敛速度和更低的错误率。
W \sim U\left[-\sqrt{\frac{6}{n^{(l)}+n^{(l+1)}}}, \sqrt{\frac{6}{n^{(l)}+n^{(l+1)}}}\right]其中,n(l)是 W 的输入单元数量,n(l+1)是 W 的输出单元数量。在这种参数初始化方案中,偏置单元被初始化为 0。这种方法试图维持各层间的激活方差以及反向传播的梯度方差。如果没有这种初始化,梯度方差(可作为信息的代表)通常会随着跨层反向传播而减小。
Learning Strategies
训练期间模型参数更新的速率/幅度可以通过学习率来控制。在下面的简单梯度下降公式中,学习率是:
\theta^{new }=\theta^{old }-\alpha \nabla_{\theta } J_{t}(\theta )你可能会认为,为了实现快速的收敛速度,我们应该将α设置为更大的值——然而,更大的收敛速度并不能保证更快的收敛。事实上,当学习率非常大时,我们可能会发现损失函数实际上会发散,因为参数更新会导致模型越过凸极小值点,如图15所示。在非凸模型中(我们处理的大多数模型都是如此),大学习率的结果是不可预测的,但损失函数发散的可能性非常高。

避免损失发散的简单解决方案是使用非常小的学习率,这样我们就能仔细地搜索参数空间——当然,如果学习率太小,我们可能无法在合理的时间内收敛,或者可能陷入局部最小值。因此,与其他任何超参数一样,学习率必须进行有效的调整。
由于训练是深度学习系统中成本最高的阶段,一些研究试图改进这种设置学习率的简单方法。例如,罗南·科洛贝尔(Ronan Collobert)将权重Wi,j的学习率按神经元输入扇入的平方根的倒数进行缩放n(l)
还有其他几种已被证明有效的技术——其中一种是退火,即在经过若干次迭代后,以某种方式降低学习率——这种方法确保我们从较高的学习率开始,快速接近最小值;当我们离最小值越来越近时,就开始降低学习率,以便能在更精细的范围内找到最优解。执行退火的一种常见方法是,每学习n次迭代后,将学习率α降低x倍。指数衰减也很常见,在这种方法中,迭代t时的学习率α由α(t)=α0e-kt 给出,其中α0是初始学习率,k是超参数。另一种方法是让学习率随时间降低,如下所示:
\alpha(t)=\frac{\alpha_{0} \tau}{max (t, \tau)}在上述方案中,α0是一个可调节参数,代表初始学习率。T也是一个可调节参数,代表学习率开始降低的时间。在实际应用中,人们发现这种方法的效果相当不错。在下一节中,我们将讨论另一种自适应梯度下降方法,该方法不需要手动设置学习率。
Momentum Updates(动量更新)
借鉴物理中 “动量” 的概念 —— 物体运动时会因动量保持原有运动趋势,同时受外力(梯度)影响调整方向。在参数更新中,“动量” 表现为 “历史更新方向的累积”,让参数更新不仅依赖 “当前梯度”,还依赖 “过去更新的速度”,从而:
- 沿梯度长期一致的方向(如损失函数的陡峭下降方向)加速更新;
- 沿梯度频繁变化的方向(如震荡方向)减缓更新,避免来回波动。
Snippet 2.2
# Computes a standard momentum update
#
# on parameters x
v = mu*v - alpha*grad_x #mu * v:保持历史运动趋势 alpha * grad_x:响应当前梯度
x += v # 参数 x 的更新幅度和方向由速度 v 直接决定
若mu=0.9,则当前速度的 90% 来自上一次的速度(历史动量),仅 10% 来自当前梯度的调整,确保运动方向的连续性。
Adaptive Optimization Methods
AdaGrad是标准随机梯度下降(SGD)的一种实现,其关键区别在于:每个参数的学习率可以不同。每个参数的学习率取决于该参数的梯度更新历史,具体来说,更新历史较少的参数会使用更大的学习率进行更快的更新。换句话说,过去更新不多的参数现在更可能拥有更高的学习率。形式上:
\theta_{t, i}=\theta_{t-1, i}-\frac{\alpha}{\sqrt{\sum_{\tau=1}^{t} g_{\tau, i}^{2}}} g_{t, i} \\where g_{t, i}=\frac{\partial}{\partial \theta_{i}^{t}} J_{t}(\theta)在这种技术中,我们发现如果梯度历史的均方根极低,那么学习率就会非常高。这种技术的一个简单实现如下:
# Assume the gradient dx and parameter vector x
cache += dx**2
x += - learning_rate * dx / np.sqrt(cache + 1e-8)
其他常见的自适应方法有RMSProp和Adam,其更新规则如下):
# Update rule for RMS prop
cache = decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)
# Update rule for Adam
m = beta1*m + (1-beta1)*dx
v = beta2*v + (1-beta2)*(dx**2)
x += - learning_rate * m / (np.sqrt(v) + eps)
RMSProp是AdaGrad的一种变体,它利用了平方梯度的移动平均值——特别是,与AdaGrad不同,它的更新不会单调变小。Adam更新规则反过来又是RMSProp的一种变体,但增加了类似动量的更新。关于这些方法行为的更详细分析,我们建议读者参考这些方法各自的来源。
Comments NOTHING