Deep Learning Systems: 全连接神经网络、优化器、初始化介绍

533 阅读1分钟

全连接神经网络

上一篇文章中我们介绍了自动微分的基本概念,现在可以介绍神经网络更通用的形式了。

一个LL层的带偏置项的全连接神经网络(也叫多层感知机),通过下面的迭代式定义:

zi+1=σi(WiTzi+bi),    i=1,,Lhθ(x)zL+1z1x\begin{align} & z_{i+1} = \sigma_i (W_i^T z_i + b_i), \ \ \ \ i = 1, \dots, L \\ & h_\theta(x) \equiv z_{L+1} \\ & z_1 \equiv x \end{align}

参数是θ={W1:L,b1:L}\theta = \{ W_{1:L}, b_{1:L}\}σi(x)\sigma_i(x)是一个非线性激活函数。

矩阵形式写法中广播的奥秘

我们思考一下上面式子中的矩阵形式

Zi+1=σi(ZiWi+1biT)Z_{i+1} = \sigma_i (Z_i W_i + 1b_i^T)

细心的话可以注意到,由于Zi+1Rm×nZ_{i+1} \in \mathbb R^{m \times n},为了使矩阵维度相匹配的话,那么1biTRm×n1b_i^T \in \mathbb R^{m \times n},但是实际上biTRm×nb_i^T \in \mathbb R ^{m \times n}

在实际操作中,我们可以通过广播(broadcast) 操作将biTb_i^T的维度扩充。

  • 对于一个n×1n \times 1的向量(或者更高维度的张量),broadcast操作将它看作一个n×pn \times p的矩阵,将原来的向量重复p次
  • 因此我们可以写成这种矩阵形式Zi+1=σi(ZiWi+1biT)Z_{i+1} = \sigma_i (Z_i W_i + 1b_i^T)
  • broadcast操作并不拷贝数据

全连接网络中关键问题

为了训练一个全连接神经网络(或者任何其它的深度神经网络),我们需要弄清楚如下几个特定的问题:

  • 我们应该怎么选择网络的宽度和深度?
  • 我们怎么优化我们的目标?(“SGD”是最简单的答案,但是这不是实践中最常用的方法)
  • 我们怎么初始化网络的权重参数?
  • 我们怎么可以确保网络在经历了多轮迭代优化后,还可以继续训练下去?

这些问题(仍然)没有明确的答案,对于深度学习来说,它们最终会针对特定问题,但我们将介绍一些基本原则。

优化器

梯度下降

我们考虑一个针对某一个函数ff的通用梯度下降参数更新策略,可以写成如下形式:

θt+1=θtαθf(θt)\theta _{t+1} = \theta_t - \alpha \nabla _\theta f(\theta _t)

其中α>0\alpha > 0(学习率), θf(θt)\nabla _\theta f(\theta_t)ff对参数θt\theta_t的梯度。

梯度下降方法在局部区域内是函数值下降最快的地方,但是从更大的时间跨度来看,其下降值可能在振荡。

梯度下降图解

对于θR2\theta \in \mathbb R ^2,考虑二次函数f(θ)=12θTpθ+qTθf(\theta) = \frac{1}{2} \theta^Tp\theta + q^T \thetaPP是正定的矩阵(所有特征值都是正数)

下面是采取不同学习率,不断迭代梯度下降的图示说明: Screenshot from 2024-06-04 21-18-51.png

牛顿法

一种能够把握更多全局信息的方法是”牛顿法“,通过黑塞矩阵(矩阵的二阶导)的逆来缩放梯度:

θt+1=θtα(θ2f(θt))1θf(θt)\theta_{t+1} = \theta_t - \alpha(\nabla_\theta^2 f(\theta_t))^{-1} \nabla_{\theta} f(\theta_t)

其中θ2f(θt)\nabla_\theta^2 f(\theta_t)就是黑塞矩阵,n×nn \times n的矩阵大小,矩阵元素是nn个参数的二阶导。

相当于使用二阶泰勒将函数近似为二次函数展开,然后求解最优解。

如果取α=1\alpha = 1,则是称为“整步牛顿法”否则称为“阻尼牛顿法”。

牛顿法图解

在这个问题中,如果取α=1\alpha = 1,那么只需要迭代一次就可以达到最优解。 image.png

但是这个方法在深度学习中没有太大的实际意义,主要有下面一些原因:

  1. 局部最优性:牛顿法通常只能找到局部最优解,而不是全局最优解。在非凸优化问题中,可能存在多个局部最优解,牛顿法可能会陷入这些局部最优解中的一个,而无法找到全局最优解。
  2. Hessian矩阵的正定性:牛顿法要求目标函数在迭代点附近是二次可微的,并且其Hessian矩阵(即二阶导数矩阵)是正定的,这样才能保证当前迭代点是一个局部最小点。在非凸问题中,Hessian矩阵可能不是正定的,或者在某些区域是不定的,这使得牛顿法无法保证收敛到局部最小点。
  3. 计算复杂性:牛顿法需要计算和存储目标函数的Hessian矩阵,这在高维问题中可能导致计算复杂性和存储需求非常高。对于大规模的非凸优化问题,这种计算和存储成本可能是不可接受的。
  4. 数值稳定性:在非凸问题中,Hessian矩阵可能存在病态情况,导致牛顿法的迭代过程不稳定,甚至可能发散。
  5. 收敛速度:牛顿法的收敛速度依赖于初始点的选择和目标函数的性质。在非凸问题中,由于可能存在多个局部最小值,牛顿法的收敛速度可能会很慢,或者在某些情况下根本不收敛。

动量(momentum)

有没有一种折中的方案,使得可以像梯度下降方法一样计算简单,然后又能够像牛顿法那样能更具有全局性呢?

答案就是使用动量来更新参数,动量考虑了先前梯度的移动平均值:

ut+1=βut+(1β)θf(θt)θt+1=θtαut+1\begin{align} & u_{t+1} = \beta u_t + (1 - \beta ) \nabla_\theta f(\theta _t) \\ & \theta_{t+1} = \theta_t - \alpha u_{t+1} \end{align}

其中α\alpha还是前面提到的学习率参数,β\beta是动量的参数。

  • 通常将动量写成这两种形式ut+1=βut+θf(θt)u_{t+1} = \beta u_t + \nabla_\theta f(\theta _t) 或者 ut+1=βut+αθf(θt)u_{t+1} = \beta u_t + \alpha \nabla_\theta f(\theta _t),但是用上面那种写法更能体现出uu是对梯度的放缩尺度的感觉

带动量的梯度下降法图解

image.png

从图中可以看到,带动量的梯度下降方法比单纯的梯度下降方法更平滑,但是还是存在振荡和函数值不下降的情况。

尽管如此,在实践中训练深度网络时经常有用。

无偏动量

动量utu_t (如果初始化为零,这是常见的),在初始迭代中会比在后面的迭代中小。

为了消除这种“偏差”使得更新在所有迭代中具有相同的预期幅度,我们可以使用下面的方式:

θt+1=θtαut+1/(1βt+1)\theta_{t+1} = \theta_t - \alpha u_{t+1} / (1- \beta ^{t+1})

无偏动量和上述带动量的优化对比图如下: image.png

Nesterov 动量

Nesterov 动量概念中的一个有用技巧,可以计算“下一个”点的动量来进行参数更新:

ut+1=βut+(1β)θf(θt)θt+1=θtαut+1ut+1=βut+(1β)θf(θtαut)θt+1=θtαut+1\begin{array}{l} u_{t+1}=\beta u_{t}+(1-\beta) \nabla_{\theta} f\left(\theta_{t}\right) \\ \theta_{t+1}=\theta_{t}-\alpha u_{t+1} \end{array} \Longrightarrow \begin{array}{l} u_{t+1}=\beta u_{t}+(1-\beta) \nabla_{\theta} f\left(\theta_{t}-\alpha u_{t}\right) \\ \theta_{t+1}=\theta_{t}-\alpha u_{t+1} \end{array}

image.png 这种方式对凸优化来说是件 “好事”,对深度网络也有帮助。

Adam

对于不同的参数,梯度的大小可能会有很大的不同,尤其是在不同的深度网络层、不同的层类型等情况下。

深度网络的不同层、不同层类型等,所谓的自适应梯度方法试图在迭代过程中估计这一比例 然后相应地重新调整梯度更新的规模

深度学习中最广泛使用的自适应梯度方法是Adam算法、它结合了动量和自适应规模估计

ut+1=β1ut+(1β1)θf(θt)vt+1=β2vt+(1β2)(θf(θt))2θt+1=θtαut+1/(vt+11/2+ϵ)\begin{array}{l} u_{t+1}=\beta_{1} u_{t}+\left(1-\beta_{1}\right) \nabla_{\theta} f\left(\theta_{t}\right) \\ v_{t+1}=\beta_{2} v_{t}+\left(1-\beta_{2}\right)\left(\nabla_{\theta} f\left(\theta_{t}\right)\right)^{2} \\ \theta_{t+1}=\theta_{t}-\alpha u_{t+1} /\left(v_{t+1}^{1 / 2}+\epsilon\right) \end{array}

Adma是否是 “好 ”的优化器在深度学习领域争论不休,但它在实践中似乎经常运行得很好。 image.png

随机变量

前面的例子都考虑了参数的批量更新,但最重要的优化选择是使用随机变量。最重要的优化选择是使用随机变量。

回忆我们机器学习的优化问题:

minimizeθ1mi=1m(hθ(x(i)),y(i))\underset{\theta}{minimize} \frac{1}{m} \sum _{i=1}^m \ell (h_\theta (x^{(i)}),y^{(i)})

即对损失的经验期望最小化.

我们只需计算一个例子子集(称为minibatch)的损失梯度,就能得到梯度的噪声估计值(但无偏)。

随机梯度下降

这样,我们就又回到了 SGD 算法,重复进行批次B{1,,m}B \subset \{ 1, \dots ,m\}的运算。

θt+1=θtαBiBθ(h(x(i)),y(i))\theta_{t+1} = \theta_t - \frac{\alpha}{B} \sum _{i \in B} \nabla_\theta \ell (h(x^{(i)}), y^{(i)})

与其采取几个昂贵、无噪音的步骤,我们不如采取许多便宜、又噪音的步骤,这样每台计算机的性能就会大大提高 image.png

最重要的收获

  • 迄今为止,您所看到的所有优化方法实际上只是以随机形式使用。
  • 从简单的(凸、二次)优化问题中,你能获得的关于这些优化方法的有效直觉是有限的。对这些优化方法的有效直觉是有限的。
  • 您需要不断尝试,才能理解/直观地了解这些方法对不同类型深度网络的实际影响。

初始化

初始化权重

回忆我们使用随机梯度下降方法迭代优化参数的公式:

Wi:=WiαWi(hθ(X),y)W_i :=W_i - \alpha \nabla_{W_i} \ell(h_\theta(X),y)

但是我们应该怎样选择什么样的值来初始化WiW_ibib_i呢?(直接使用0来初始化?)

我们来看当时手动推导反向传播算法的前向传播和反向传播的过程(不带偏置项):

Zi+1=σi(ZiWi)Gi=(Gi+1  σi(ZiWi))WiT\begin{array}{l} Z_{i+1} = \sigma _i (Z_iW_i) \\ G_i = (G_{i+1} \ \circ \ \sigma_i' (Z_iW_i))W_i^T \end{array}

如果Wi=0W_i = 0,那么Gj=0G_j = 0,对于jiWi(hθ(X),y)=0j \leq i \Longrightarrow \nabla_{W_i} \ell(h_\theta(X),y) = 0,因此取Wi=0W_i=0,会使得梯度消失从而更新不了参数。

不同初始化对训练的影响

我们简单的把权重随机初始化为一个正态分布WiN(0,σ2I)W_i \sim N(0, \sigma^2 I)

选择不同的方差σ2\sigma ^2将会影响下面两个部分:

  1. 前向激活函数输出ZiZ_i的范数
  2. 梯度的范数

下面是对方差取不同值使用MNIST数据集,隐藏层神经元100个,激活函数为relu总共50层的神经网络进行训练,对比上述两个范数的区别。 image.png

权重更新的并不大

  • 你可能会认为,无论初始化如何,网络参数都会收敛到某个相似的点区域。
  • 事实并非如此......权重往往更接近其初始化值,而不是经过优化后的 “最终”点。
  • 最终结论:初始化对于神经网络训练很重要。

是什么导致了这种影响

考虑独立随机变量xN(0,1)x \sim N(0,1)wN(0,1n)w \sim N(0, \frac{1}{n}),那么有

E[xiwi]=E[xi]E[wi]=0,Var[xiwi]=Var[xi]Var[wi]=1nE[x_iw_i] = E[x_i]E[w_i] = 0, Var[x_iw_i] = Var[x_i]Var[w_i]= \frac{1}{n}

E[wTx]=0,Var[wTx]=1E[w^Tx] = 0, Var[w^Tx]=1wTxN(0,1)w^Tx \rightarrow N(0,1)有中心极限定理可得)

因此,如果我们使用一个线性激活函数并且有ziN(0,I),WiN(0,1nI)z_i \sim N(0, I), W_i \sim N(0, \frac{1}{n}I),那么有zi+1=WiTN(0,I)z_{i+1} = W_i^T \sim N(0, I)

如果我们使用ReLU非线性激活函数,假设有ziz_i一半的分量将会被置0,因此为了保证Wi+1W_{i+1}WiW_i有同样的方差,需要将WiW_i方差乘2,也就是WiN(0,2nI)W_i \sim N(0, \frac{2}{n}I)(这也是kaiming normal initialization)