Adam与RMSProp优化器的区别以及训练显存消耗(以LLaMA-2 7B为例):中英双语

时间:2024-12-03 15:11:46

中文版

深入分析:Adam与RMSProp优化器的区别以及显存消耗

在深度学习中,优化器是训练神经网络时至关重要的组件。Adam(Adaptive Moment Estimation)和RMSProp是两种常用的优化算法,它们都试图通过自适应调整学习率来提高模型的训练效率和性能。今天,我们将深入探讨这两种优化器的区别,并结合数学公式详细分析它们的工作原理,最后分析在训练过程中它们的显存消耗。

1. Adam与RMSProp的基本概念

1.1 Adam优化器

Adam优化器结合了动量(Momentum)自适应学习率的思想,它在每个参数上维护两个变量:

  • 第一矩(momentum):对梯度的指数加权平均,用于减少振荡。
  • 第二矩(RMSProp的变体):对梯度的平方的指数加权平均,用于自适应调整学习率。

Adam的主要思想是通过对一阶和二阶矩的估计,来调整每个参数的更新步长,使得每个参数在训练过程中能够拥有自己的学习率。

1.1.1 Adam优化器的数学公式

Adam优化器的更新公式如下:

  1. 梯度计算
    g t = ∇ θ L ( θ t ) g_t = \nabla_\theta L(\theta_t) gt=θL(θt)
    其中 ( g t g_t gt ) 是在时间步 ( t t t ) 的梯度,( θ t \theta_t θt ) 是模型参数,( L ( θ t ) L(\theta_t) L(θt) ) 是损失函数。

  2. 一阶矩(动量)更新
    m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t mt=β1mt1+(1β1)gt
    其中 ( β 1 \beta_1 β1 ) 是一阶矩的衰减系数,通常取值接近1(如 0.9)。

  3. 二阶矩(RMSProp变体)更新
    v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 vt=β2vt1+(1β2)gt2
    其中 ( β 2 \beta_2 β2 ) 是二阶矩的衰减系数,通常取值接近1(如 0.999)。

  4. 偏置修正
    m ^ t = m t 1 − β 1 t , v ^ t = v t 1 − β 2 t \hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t} m^t=1β1tmt,v^t=1β2tvt
    这里的偏置修正是为了在训练初期纠正一阶矩和二阶矩的偏差。

  5. 参数更新
    θ t + 1 = θ t − α v ^ t + ϵ m ^ t \theta_{t+1} = \theta_t - \frac{\alpha}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t θt+1=θtv^t +ϵαm^t
    其中,( α \alpha α ) 是学习率,( ϵ \epsilon ϵ ) 是一个小常数,防止除零错误。

1.2 RMSProp优化器

RMSProp(Root Mean Square Propagation)优化器是一种自适应优化算法,它通过维护梯度平方的指数加权平均来调整每个参数的学习率。与传统的SGD优化器不同,RMSProp为每个参数分配了不同的学习率。Root Mean Square是均方根的意思。

1.2.1 RMSProp优化器的数学公式

RMSProp的更新公式如下:

  1. 梯度计算
    g t = ∇ θ L ( θ t ) g_t = \nabla_\theta L(\theta_t) gt=θL(θt)

  2. 梯度平方的指数加权平均
    v t = β v t − 1 + ( 1 − β ) g t 2 v_t = \beta v_{t-1} + (1 - \beta) g_t^2 vt=βvt1+(1β)gt2
    其中,( β \beta β ) 是衰减系数,通常取值接近1(如 0.9)。

  3. 参数更新
    θ t + 1 = θ t − α v t + ϵ g t \theta_{t+1} = \theta_t - \frac{\alpha}{\sqrt{v_t + \epsilon}} g_t θt+1=θtvt+ϵ αgt
    其中,( α \alpha α ) 是学习率,( ϵ \epsilon ϵ ) 是一个小常数,防止除零错误。

1.3 Adam与RMSProp的区别

  1. 动量项的差异

    • Adam:不仅使用了梯度的一阶矩(动量),还使用了梯度平方的二阶矩(类似RMSProp)。这种方法使得Adam能够更加全面地调整每个参数的学习率,特别是在稀疏梯度情况下,效果更为显著。
    • RMSProp:只使用梯度平方的加权平均,不包含一阶矩。因此,RMSProp只依赖于梯度的变化,而没有考虑动量的积累。
  2. 更新规则的差异

    • Adam:对梯度的更新使用了偏置修正,并且同时考虑一阶和二阶矩的动态变化。
    • RMSProp:仅对梯度平方的历史进行更新,并且没有偏置修正。
  3. 适用场景

    • Adam:通常适用于所有场景,特别是当网络复杂且梯度稀疏时,Adam通常能够提供更好的性能。
    • RMSProp:在处理循环神经网络(RNN)等任务时,RMSProp由于自适应学习率的特性,也能表现良好,但在面对稀疏梯度和非凸优化问题时,Adam更具优势。

2. 显存消耗分析:Adam与RMSProp

Adam和RMSProp在训练过程中都会增加额外的内存开销,主要体现在它们需要存储梯度的历史信息和其他优化器状态变量。下面分析这两种优化器在显存消耗方面的不同:

2.1 Adam的显存消耗
  • Adam需要为每个参数维护一阶矩和二阶矩,因此其内存消耗是标准SGD的3倍
    • 模型参数(例如:LLaMA-2 7B有70亿参数):假设使用float32,每个参数占4字节,模型参数所需的内存为28 GB。
    • 梯度:与模型参数大小相同,需要28 GB。
    • 优化器状态:Adam需要两个状态变量(动量和二阶矩),所以优化器状态占用的内存为56 GB(28 GB × 2)。

因此,总显存需求为:

总显存需求 = 28   GB ( 模型 ) + 28   GB ( 梯度 ) + 56   GB ( 优化器 ) = 112   GB \text{总显存需求} = 28 \, \text{GB} (\text{模型}) + 28 \, \text{GB} (\text{梯度}) + 56 \, \text{GB} (\text{优化器}) = 112 \, \text{GB} 总显存需求=28GB(模型)+28GB(梯度)+56GB(优化器)=112GB

下面的python代码测试7B大模型本身的参数量:以float32计算。进位采用1024,计算得出:7B大模型的参数量为26.08 GB;当进位采用1000时,计算得出28.00 GB。为什么尝试1000,是因为在其他博文中看到28GB这个数字,自己测试一下,发现他们是在以1000为进位的时候测试得出的。参考文章:https://cuiyuhao.com/posts/c87c0f5d/

# 定义参数
num_parameters = 7 * 10**9  # 70 亿个参数
bytes_per_param = 4  # 每个参数占用 4 字节(32 位浮动数)

# 计算显存需求(单位:字节)
memory_in_bytes = num_parameters * bytes_per_param

# 将字节转换为 GB
memory_in_GB = memory_in_bytes / (1024 ** 3)  # 转换为 GB, 可调为1000

print(f"模型需要的显存为: {memory_in_GB:.2f} GB")

以bf16为例,由于它是float32的一半,所以它的参数量为 26.08GB / 2 = 13.04GB (以1024为进位),当以1000进位的时候,28GB / 2 = 14GB

2.2 RMSProp的显存消耗

RMSProp优化器只需要维护梯度平方的加权平均,因此内存消耗比Adam少。与SGD一样,RMSProp仅需要存储梯度的平方(即一个变量):

  • 模型参数:28 GB
  • 梯度:28 GB
  • 优化器状态:RMSProp仅需要一个状态变量(梯度平方),占用28 GB

因此,总显存需求为:

总显存需求 = 28   GB ( 模型 ) + 28   GB ( 梯度 ) + 28   GB ( 优化器 ) = 84   GB \text{总显存需求} = 28 \, \text{GB} (\text{模型}) + 28 \, \text{GB} (\text{梯度}) + 28 \, \text{GB} (\text{优化器}) = 84 \, \text{GB} 总显存需求=