混合精度训练,FP16加速训练,降低内存消耗

文章介绍了浮点数表示的三种形式,强调了FP16在深度学习中能减少显存占用和加速计算,但也带来了溢出错误、表示范围限制和舍入误差问题。为解决这些问题,文章提出了混合精度训练,包括权重备份、损失缩放和精度累加等技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 计算机中的浮点数表示,按照IEEE754可以分为三种,分别是半精度浮点数、单精度浮点数和双精度浮点数。三种格式的浮点数因占用的存储位数不同,能够表示的数据精度也不同。

    • 在这里插入图片描述

    • Signed bit用于控制浮点数的正负,0表示正数,1表示负数;

    • Exponent部分用于控制浮点数的大小,以2为底进行指数运算;

    • Significand部分用于控制浮点数的精度,存储浮点数的有效数字。

  • 默认深度学习模型训练过程中都是使用fp32

  • 使用fp16能带来什么好处:

    • 减少显存占用:现在模型越来越大,当你使用Bert这一类的预训练模型时,往往显存就被模型及模型计算占去大半,当想要使用更大的Batch Size的时候会显得捉襟见肘。由于FP16的内存占用只有FP32的一半,自然地就可以帮助训练过程节省一半的显存空间。

    • 加快训练和推断的计算:与普通的空间时间Trade-off的加速方法不同,FP16除了能节约内存,还能同时节省模型的训练时间。在大部分的测试中,基于FP16的加速方法能够给模型训练带来多一倍的加速体验。

    • 张量核心的普及:硬件的发展同样也推动着模型计算的加速,随着Nvidia张量核心(Tensor Core)的普及,16bit计算也一步步走向成熟,低精度计算也是未来深度学习的一个重要趋势。

    • x = F P 16 ( ( − 1 ) S i g n e d ∗ 2 E x p o n e n t − 15 ∗ ( 1 + S i g n i F i c a n d 2 10 ) ) x=FP16((-1)^{Signed}*2^{Exponent-15}*(1+\frac{SigniFicand}{2^{10}})) x=FP16((1)Signed2Exponent15(1+210SigniFicand))

    • x = F P 32 ( ( − 1 ) S ∗ 2 E − 127 ∗ 1. S F ) x=FP32((-1)^S*2^{E-127}*1.SF) x=FP32((1)S2E1271.SF)

    • x = F P 64 ( ( − 1 ) S ∗ 2 E − 1023 ∗ 1. S F ) x=FP64((-1)^S*2^{E-1023}*1.SF) x=FP64((1)S2E10231.SF)

    • FP16最大值为0 11110 1111111111,其计算方式为

      • ( − 1 ) 0 ∗ 2 30 − 15 ∗ 1.1111111111 = 1 ∗ 2 15 ∗ ( 1 + 2 − 1 + 2 − 2 + . . . + 2 − 10 ) = 65504 (-1)^0*2^{30-15}*1.1111111111\\ =1*2^{15}*(1+2^{-1}+2^{-2}+...+2^{-10})\\ =65504 (1)0230151.1111111111=1215(1+21+22+...+210)=65504
    • 如果 Exponent 位全部为0:

      • 如果 Significand位 全部为0,则表示数字 0
    • 如果 Exponent 位全部位1:

      • 如果 fraction 位 全部为0,则表示 ±inf

      • 如果 fraction 位 不为0,则表示 NAN

  • 使用fp16能带来什么问题:

    • 溢出错误

      • 半精度浮点数有两个字节存储。由于FP16的动态范围比FP32的动态范围要狭窄很多,因此在计算过程中很容易出现上溢出(Overflow )和下溢出(Underflow)的错误,溢出之后就会出现“Nan”的问题。在深度学习中,由于激活函数的的梯度往往要比权重梯度小,更易出现下溢出的情况。

      • 表示范围

        • 运算结果大于最大正数时称为正上溢,小于绝对值最大负数时称为负上溢,正上溢和负上溢统称上溢。数据一旦产生上溢,计算机必须中断运算操作,进行溢出处理

        • 当运算结果在0至最小正数之间时称为正下溢,在0至绝对值最小负数之间时称为负下溢,正下溢和负下溢统称下溢。 数据下溢时,浮点数值趋于零,计算机仅将其当作机器零处理

        • 在这里插入图片描述

    • 舍入误差

      • Rounding Error指示是当网络模型的反向梯度很小,一般FP32能够表示,但是转换到FP16会小于当前区间内的最小间隔,会导致数据溢出。如0.00006666666在FP32中能正常表示,转换到FP16后会表示成为0.000067,不满足FP16最小间隔的数会强制舍入。

      • 解决方案

        • 输入FP16的数据,部分运算继续使用FP16计算,得到FP16结果

        • 将部分运算转成 FP32类型进行计算,得到 FP32中间结果

        • 输出时将所有的FP32数据转换为FP16

  • 混合精度训练,指代的是单精度 float和半精度 float16 混合训练。为了想让深度学习训练可以使用FP16的好处,又要避免精度溢出和舍入误差。于是可以通过FP16和FP32的混合精度训练(Mixed-Precision),混合精度训练过程中可以引入权重备份(Weight Backup)、损失放大(Loss Scaling)、精度累加(Precision Accumulated)三种相关的技术。

  • 权重备份(Weight Backup)

    • 权重备份主要用于解决舍入误差的问题。其主要思路是把神经网络训练过程中产生的激活activations、梯度 gradients、中间变量等数据,在训练中都利用FP16来存储,同时复制一份FP32的权重参数weights,用于训练时候的更新。

    • 在计算过程中所产生的权重weights,激活activations,梯度gradients等均使用 FP16 来进行存储和计算,其中权重使用FP32额外进行备份。

    • 深度模型中,lr * gradent的参数值可能会非常小,利用FP16来进行相加的话,则很可能会出现舍入误差问题,导致更新无效。因此通过将权重weights拷贝成FP32格式,并且确保整个更新过程是在 fp32 格式下进行的。即:

      • w e i g h t 32 = w e i g h t 32 + l r ∗ g r a i d e n t 16 weight_{32}=weight_{32}+lr * graident_{16} weight32=weight32+lrgraident16
    • 权重用FP32格式备份一次,那岂不是使得内存占用反而更高了呢?是的,额外拷贝一份weight的确增加了训练时候内存的占用。 但是实际上,在训练过程中内存中分为动态内存和静态内容,其中动态内存是静态内存的3-4倍,主要是中间变量值和激活activations的值。而这里备份的权重增加的主要是静态内存。只要动态内存的值基本都是使用FP16来进行存储,则最终模型与整网使用FP32进行训练相比起来, 内存占用也基本能够减半

  • 损失缩放(Loss Scaling)

    • 如果仅仅使用FP32训练,模型收敛得比较好,但是如果用了混合精度训练,会存在网络模型无法收敛的情况。原因是梯度的值太小,使用FP16表示会造成了数据下溢出(Underflow)的问题,导致模型不收敛。于是需要引入损失缩放(Loss Scaling)技术。

    • 为了解决梯度过小数据下溢的问题,对前向计算出来的Loss值进行放大操作,也就是把FP32的参数乘以某一个因子系数后,把可能溢出的小数位数据往前移,平移到FP16能表示的数据范围内。根据链式求导法则,放大Loss后会作用在反向传播的每一层梯度,这样比在每一层梯度上进行放大更加高效

  • 精度累加(Precision Accumulated)

    • 在混合精度的模型训练过程中,使用FP16进行矩阵乘法运算,利用FP32来进行矩阵乘法中间的累加(accumulated),然后再将FP32的值转化为FP16进行存储。简单而言,就是利用FP16进行矩阵相乘,利用FP32来进行加法计算弥补丢失的精度。这样可以有效减少计算过程中的舍入误差,尽量减缓精度损失的问题

再将FP32的值转化为FP16进行存储**。简单而言,就是利用FP16进行矩阵相乘,利用FP32来进行加法计算弥补丢失的精度。这样可以有效减少计算过程中的舍入误差,尽量减缓精度损失的问题

### FP8 深度学习混合精度训练实现与优化 #### 背景介绍 在深度学习领域,降低计算和存储成本一直是研究的重点之一。FP16已经广泛应用于混合精度训练中以提高效率并减少资源消耗[^2]。然而,随着硬件支持的进步和技术的发展,更进一步探索更低位宽的数据表示形式成为可能。其中,FP8作为一种新兴的低精度数据格式,在某些特定场景下展现出巨大潜力。 #### FP8 数据格式特点 相比传统的FP32以及较为常见的FP16, FP8具有更加紧凑的结构: - **指数范围缩小**:通常只有5比特用于表示指数部分; - **尾数长度减短**:一般仅有2到3比特分配给小数部分; - **特殊值编码简化**:如无穷大、NaN等特殊情况下的二进制模式更为简单。 这种设计使得FP8能够在有限的空间内完成基本运算操作的同时极大限度地节省带宽需求和功耗开销。 #### 实现方法概述 要成功实施基于FP8的混合精度训练方案,需解决以下几个核心挑战: ##### 1. 数值稳定性保障机制 由于FP8所能表达的有效动态范围非常有限,直接采用可能导致严重的溢出或下溢现象,进而影响最终收敛效果甚至使整个网络失效。为此,可借鉴现有针对FP16所提出的梯度缩放策略——即通过对损失函数乘上适当比例因子后再反向传播更新参数权重的方式来缓解上述风险;同时引入Loss scaling技术确保重要信息不会因为过早截断而丢失[^4]。 ##### 2. 精确度补偿措施 考虑到单纯依靠FP8难以满足所有层间交互所需的高分辨率要求,建议采取分阶段转换方式—即将前向传递过程尽可能多地迁移到较低精度环境执行(比如激活函数计算),而后向传播则视具体情况灵活调整至更高一点的标准直至完全恢复成全尺寸版本参与后续迭代优化流程。此外还可以尝试利用量化感知训练(Quantization-Aware Training,QAT)提前模拟目标平台特性从而更好地适配实际部署条件[^1]. ##### 3. 支持库与框架集成 目前主流AI芯片厂商已经开始重视起对于超低位宽度算术逻辑单元(ALU)的支持力度,并陆续推出配套软件工具链帮助开发者快速搭建实验原型验证想法可行性。例如NVIDIA TensorRT就提供了专门面向推理侧优化后的API接口可以直接调用内置好的FP8相关功能模块; PyTorch/XLA也在积极跟进这一趋势努力填补生态空白地带以便让更多研究人员受益于此项前沿成果[^3]. ```python import torch from apex import amp model = MyModel() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Enable mixed precision with custom op for fp8 support. opt_level = 'O2' amp.register_float_function(torch, 'sigmoid') model, optimizer = amp.initialize( model, optimizer, opt_level=opt_level, cast_model_type=torch.float8, # Hypothetical API extension supporting FP8 ) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羞儿

写作是兴趣,打赏看心情

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值