前向传播/反向传播和计算图|多层感知机|动手学深度学习

199 阅读8分钟

1. 假设一些标量函数X\mathbf{X}的输入X\mathbf{X}n×mn \times m矩阵。ff相对于X\mathbf{X}的梯度维数是多少?

对于一个标量函数 f(X)f(\mathbf{X}),其中 X\mathbf{X} 是一个 n×mn \times m 矩阵,该函数相对于 X\mathbf{X} 的梯度是一个与 X\mathbf{X} 同样大小的矩阵。具体来说,梯度是一个 n×mn \times m 的矩阵,其元素是函数 ff 相对于 X\mathbf{X} 中每个元素的偏导数。

梯度的计算可以表示为:

fXRn×m\frac{\partial f}{\partial \mathbf{X}} \in \mathbb{R}^{n \times m}

这里,fX\frac{\partial f}{\partial \mathbf{X}} 表示 ff 相对于矩阵 X\mathbf{X} 的元素的偏导数组成的矩阵。对于矩阵 X\mathbf{X} 中的每个元素 XijX_{ij},梯度矩阵中的相应元素是 fXij\frac{\partial f}{\partial X_{ij}}

在实际应用中,例如在机器学习中的损失函数,这个梯度矩阵用于执行梯度下降或其他优化算法,以找到最小化或最大化标量函数 ff 的矩阵 X\mathbf{X} 的值。

2. 向本节中描述的模型的隐藏层添加偏置项(不需要在正则化项中包含偏置项)。

  1. 画出相应的计算图。
  2. 推导正向和反向传播方程。

backprop.drawio.png

3. 计算本节所描述的模型,用于训练和预测的内存占用。

在网页提供的上下文中,我们考虑的是一个单隐藏层的多层感知机(MLP),并且包含了L2正则化项。为了估算内存占用,我们需要考虑模型参数、前向传播和反向传播过程中的中间变量。

模型参数:

  1. 隐藏层权重 W(1)W^{(1)}: 其维度是 h×dh \times d,其中 hh 是隐藏层神经元的数量,dd 是输入特征的数量。
  2. 输出层权重 W(2)W^{(2)}: 其维度是 q×hq \times h,其中 qq 是输出层神经元的数量。

如果使用32位浮点数(即4字节每个参数),则模型参数的内存占用大约为: Memoryparams=4×(h×d+q×h)\text{Memory}_{\text{params}} = 4 \times (h \times d + q \times h)

前向传播的中间变量:

  1. 隐藏层激活 hh: 其维度是 h×nh \times n,其中 nn 是小批量中的样本数。
  2. 输出层变量 oo: 其维度是 q×nq \times n

中间变量的内存占用大约为: Memoryfw=4×(h×n+q×n)\text{Memory}_{\text{fw}} = 4 \times (h \times n + q \times n)

反向传播的中间变量和梯度:

  1. 输出层梯度: 维度同样是 q×nq \times n
  2. 隐藏层梯度: 维度是 h×nh \times n

梯度的内存占用大约为: Memorybw=4×(h×n+q×n)\text{Memory}_{\text{bw}} = 4 \times (h \times n + q \times n)

总内存占用:

将上述所有部分加起来,我们得到总的内存占用估算: Memorytotal=Memoryparams+Memoryfw+Memorybw\text{Memory}_{\text{total}} = \text{Memory}_{\text{params}} + \text{Memory}_{\text{fw}} + \text{Memory}_{\text{bw}} Memorytotal=4×(h×d+q×h+2×(h+q)×n)\text{Memory}_{\text{total}} = 4 \times (h \times d + q \times h + 2 \times (h + q) \times n)

默认参数示例:

假设我们有以下默认参数:

  • h=128h = 128 (隐藏层神经元数)
  • d=64d = 64 (输入特征数)
  • q=10q = 10 (输出层神经元数,例如对于10个类别的分类问题)
  • n=32n = 32 (小批量大小)

则总内存占用大约为: Memorytotal=4×(128×64+10×128+2×(128+10)×32)\text{Memory}_{\text{total}} = 4 \times (128 \times 64 + 10 \times 128 + 2 \times (128 + 10) \times 32) Memorytotal=4×(8192+1280+8320+640)\text{Memory}_{\text{total}} = 4 \times (8192 + 1280 + 8320 + 640) Memorytotal=4×10400\text{Memory}_{\text{total}} = 4 \times 10400 Memorytotal=41600 bytes\text{Memory}_{\text{total}} = 41600 \text{ bytes}

或者说大约为41.6 KB。

请注意,这个计算是一个简化的估算,实际的内存占用可能因深度学习框架的内部实现细节、数据类型的精度(如是否使用float16, float32, 或 float64)、以及是否有额外的内存优化技术等因素而有所不同。此外,正则化项 ss 的计算和存储也需要一定的内存,但在上面的估算中并未显著考虑,因为它通常远小于模型参数和中间变量的内存占用。

4. 假设想计算二阶导数。计算图发生了什么?预计计算需要多长时间?

在神经网络的训练过程中,正向传播(forward propagation)和反向传播(backward propagation)是两个核心步骤。正向传播是指输入数据通过网络,经过每一层的变换,最终得到输出结果的过程。反向传播则是指在得到损失函数后,通过计算损失函数对网络参数的梯度,然后更新参数以减少损失的过程。

正向传播中的二阶导数

在正向传播中,通常不会直接计算二阶导数。正向传播主要关注的是网络的输出,即对于给定的输入 xx,网络如何通过一系列参数 θ\theta 计算出输出 yy。这个过程可以表示为 y=f(x;θ)y = f(x; \theta),其中 ff 是网络的函数,θ\theta 是网络参数。

反向传播中的二阶导数

反向传播主要涉及一阶导数,即损失函数 LL 对网络参数 θ\theta 的偏导数。这些一阶导数用于参数的更新。然而,如果要计算二阶导数,即损失函数对参数的二阶偏导数,这通常涉及到Hessian矩阵的构建,它是一阶导数的梯度。

Hessian矩阵

Hessian矩阵 HH 是一个方阵,其元素 HijH_{ij} 是损失函数 LL 对参数 θi\theta_iθj\theta_j 的二阶偏导数,即 Hij=2LθiθjH_{ij} = \frac{\partial^2 L}{\partial \theta_i \partial \theta_j}

计算图的变化

在计算图中,为了计算二阶导数,需要对每个参数的一阶导数(即梯度)再次应用链式法则。这意味着对于每个参数,你需要构建一个新的计算图,该图计算该参数的梯度相对于其他所有参数的偏导数。这会导致计算图的复杂度显著增加。

计算时间

预计计算二阶导数所需的时间将远远超过一阶导数的计算。原因如下:

  1. 计算复杂度:二阶导数的计算涉及到更多的乘积和求导操作。
  2. 存储需求:Hessian矩阵的大小与参数的数量的平方成正比,对于大型网络,这可能导致巨大的存储需求。
  3. 计算图大小:每个参数都需要一个完整的计算图来计算其相对于其他所有参数的二阶导数,这会导致大量的重复计算。

优化算法

实际上,由于直接计算和使用完整的Hessian矩阵在计算上非常昂贵,许多优化算法采用近似方法来处理二阶导数,如牛顿法的变体或拟牛顿法(如L-BFGS)。这些方法通过近似Hessian矩阵或其逆矩阵来减少计算和存储需求。

结论

在实践中,计算二阶导数并不常见,特别是在深度学习中,因为其计算成本非常高。相反,研究者和工程师通常会使用基于一阶导数的优化算法,如梯度下降及其变体。如果你对特定的优化问题或算法有更具体的兴趣,可以提供更多的上下文,以便进行更详细的讨论。

5. 假设计算图对当前拥有的GPU来说太大了。

  1. 请试着把它划分到多个GPU上。
  2. 与小批量训练相比,有哪些优点和缺点?

当我们面临计算图太大以至于单个GPU无法容纳的情况时,我们可以考虑使用多个GPU来并行化训练过程。以下是如何将计算图划分到多个GPU上以及与小批量训练相比的优缺点:

将计算图划分到多个GPU上

  1. 数据并行(Data Parallelism):这是最常见的多GPU训练方法。在这种方法中,每个GPU都拥有模型的一个副本。输入数据被划分成多个批次,每个批次被送入一个GPU进行正向和反向传播。然后,梯度在所有GPU之间进行平均,并更新每个模型副本的参数。

  2. 模型并行(Model Parallelism):在模型并行中,模型的不同部分被放置在不同的GPU上。例如,如果一个模型有多个层,可以将一些层放在一个GPU上,其余层放在另一个GPU上。这种方法适用于模型太大而无法在单个GPU上完全容纳的情况。

  3. 混合并行(Hybrid Parallelism):结合了数据并行和模型并行的特点,适用于更复杂的场景,可以根据模型和数据的大小灵活地调整。

与小批量训练相比的优缺点

优点

  1. 加速训练:使用多个GPU可以显著加快训练速度,因为可以并行处理数据和模型的不同部分。

  2. 处理更大的模型:多GPU训练允许处理更大的模型,这些模型可能无法在单个GPU上完全容纳。

  3. 处理更大的数据集:可以处理更大的数据集,因为并行化可以更快地完成数据的加载和处理。

  4. 更好的扩展性:多GPU训练通常更容易扩展到更多的GPU,从而进一步提高训练速度。

缺点

  1. 通信开销:在数据并行训练中,不同GPU之间需要频繁地交换梯度信息,这可能导致通信开销增加,特别是在使用多个GPU时。

  2. 同步问题:在多GPU训练中,需要同步不同GPU上的梯度和参数更新,这可能导致训练过程变慢,尤其是在网络延迟较高的情况下。

  3. 复杂性增加:多GPU训练的实现比单GPU训练更复杂,需要更多的代码和设置。

  4. 内存限制:尽管使用了多个GPU,但如果模型太大,每个GPU上的内存可能仍然不足以容纳整个模型,这就需要模型并行或混合并行。

  5. 梯度消失/爆炸问题:在深度网络中,使用多个GPU可能会导致梯度消失或爆炸问题更加严重,因为梯度需要在多个GPU之间平均。

  6. 成本:多GPU训练需要更多的硬件资源,这可能导致更高的成本。

总的来说,多GPU训练可以显著提高训练速度和处理能力,但也需要考虑通信开销、同步问题和实现复杂性等潜在缺点。小批量训练是一种更简单、更灵活的方法,但在处理大型模型和数据集时可能会受到硬件资源的限制。选择哪种方法取决于具体的应用场景、模型大小、数据集大小以及可用的硬件资源。