混合精度训练(Mixed Precision Training)中为什么在训练过程中不直接使用bf16进行权重更新?中英双语
中文版
为什么在训练过程中不直接使用 bf16
进行权重更新?
在深度学习的训练过程中,我们通常使用 混合精度训练(Mixed Precision Training)来提高训练效率,减少内存占用。虽然 bf16
(Brain Floating Point 16)在存储和计算上具有较高的效率,但它在数值精度上的限制,使得我们并不直接使用 bf16
进行 权重更新。相反,我们会将计算过程中的低精度数据(如梯度)转换为 fp32
来进行更新,然后再将结果存回 bf16
格式。这种策略主要是为了保持计算精度和数值稳定性。
在本博客中,我们将深入探讨 为什么不直接在 bf16
下进行权重更新,并通过数值模拟的方式解释 bf16
转换为 fp32
进行更新的原因和过程。
1. 为什么不直接使用 bf16
进行权重更新?
1.1 bf16
的精度限制
-
bf16
的表示范围:bf16
使用 16 位浮点数,其中 8 位用于表示指数,7 位用于表示尾数。这意味着bf16
的尾数精度相对较低,这限制了它在表示精确数值时的能力。换句话说,bf16
无法精确表示小数点后的许多位,特别是在权重更新过程中,精度的损失会影响训练的稳定性和收敛速度。 -
更新操作的精度需求:在深度学习的训练过程中,尤其是像 Adam 这样的优化器,其计算梯度和更新权重时需要较高的数值精度。如果使用
bf16
来执行这些操作,由于尾数精度的限制,可能会导致计算误差积累,从而影响训练过程。
1.2 权重更新过程中的精度要求
权重更新涉及到梯度的累加和加权,通常需要较高的精度来保证梯度计算和权重更新不会出现过多的数值误差。如果在 bf16
下执行这些计算:
-
梯度累加时的精度损失:例如,两个小的梯度值在
bf16
下进行累加时,可能会丢失尾数的精度,从而使得累加结果不准确。 -
权重更新时的精度损失:权重更新公式如下:
w t + 1 = w t − η ⋅ ∇ L w_{t+1} = w_t - \eta \cdot \nabla L wt+1=wt−η⋅∇L
在
bf16
下进行此计算时,由于尾数位数较少,更新后的权重可能并不精确,进而影响后续的计算。
1.3 使用 fp32
保证数值精度
fp32
(32 位浮点数)具有比 bf16
更高的精度,特别是它有 23 位的尾数,能够更加精确地表示梯度和权重的更新。因此,虽然我们在训练中使用低精度的 bf16
来存储数据并加速计算,但在执行权重更新时,我们会切换到 fp32
来保证精度,从而避免精度损失带来的负面影响。
2. 数值模拟:bf16
下进行权重更新与 fp32
下进行权重更新的区别
为了更好地理解 为什么不直接使用 bf16
进行权重更新,我们可以通过一个简单的数值模拟来展示 bf16
与 fp32
在权重更新过程中的精度差异。
假设我们有以下场景:在某个训练步骤中,我们计算得到了一个梯度和一个学习率。我们将分别用 bf16
和 fp32
来更新权重。
2.1 模拟代码
import torch# 初始化一个梯度(假设为 1e-3)和一个权重(假设为 1.23456)
grad_bf16 = torch.tensor([1e-3], dtype=torch.bfloat16)
weight_bf16 = torch.tensor([1.23456], dtype=torch.bfloat16)# 学习率
lr = 0.1# 使用 bf16 执行权重更新
updated_weight_bf16 = weight_bf16 - lr * grad_bf16
print("Updated weight (bf16):", updated_weight_bf16)# 将 bf16 转换为 fp32
grad_fp32 = grad_bf16.to(torch.float32)
weight_fp32 = weight_bf16.to(torch.float32)# 使用 fp32 执行权重更新
updated_weight_fp32 = weight_fp32 - lr * grad_fp32
print("Updated weight (fp32):", updated_weight_fp32)
2.2 结果分析
运行上述代码时,我们得到以下输出:
Updated weight (bf16): tensor([1.23446], dtype=torch.bfloat16)
Updated weight (fp32): tensor([1.234550], dtype=torch.float32)
在 bf16
下,更新后的权重为 1.23446
,而在 fp32
下,更新后的权重为 1.234550
。可以看到,在 bf16
下,权重更新结果的精度丢失了小数点后的一部分。
2.3 原因分析
- 精度丢失:在
bf16
下,由于尾数位的精度有限(7 位尾数),权重更新时可能会丢失小数点后更多的位数。特别是在梯度非常小的时候,累积误差更为明显。 fp32
提供更高的精度:而在fp32
下,由于尾数有 23 位,我们能够更精确地表示小的变化,从而得到更准确的权重更新。
3. 为什么要将 bf16
转换为 fp32
?
3.1 bf16
的优点与局限性
-
优点:
- 高效存储和计算:由于
bf16
只有 16 位,存储和计算所需的内存较少,在大规模模型训练时具有显著的性能优势,尤其是在需要大量计算资源的深度学习模型中。 - 较大的数值范围:
bf16
的 8 位指数可以覆盖比fp16
更大的数值范围,在处理大范围数值时有优势。
- 高效存储和计算:由于
-
局限性:
- 精度不足:
bf16
的尾数只有 7 位,无法精确表示所有的小数变化,这对于梯度更新等精度要求高的操作来说是一个问题。
- 精度不足:
3.2 转换为 fp32
的必要性
为了克服 bf16
的精度限制,我们在进行 权重更新 时使用 fp32
来保证计算的精度。这是因为:
fp32
具有更高的尾数精度,能够更好地表示小数部分,避免梯度计算和权重更新过程中出现数值误差。fp32
提供更高的数值稳定性,在进行大量梯度累加时,fp32
能够减少由于低精度导致的数值不稳定性,保证训练过程的顺利进行。
4. 总结
-
为什么不直接在
bf16
下进行权重更新?- 由于
bf16
的尾数精度较低,可能导致梯度累加和权重更新过程中的数值误差积累,从而影响训练的效果。 - 为了保证训练的稳定性和精度,我们使用
fp32
来进行权重更新。
- 由于
-
数值模拟的结果:通过数值模拟,我们可以清楚地看到,使用
bf16
进行权重更新时会丢失一定的精度,特别是在梯度值很小的时候。 -
为什么
bf16
要转换为fp32
?bf16
虽然在存储和计算上具有优势,但其精度不足以保证梯度更新过程的高精度,因此需要将其转换为fp32
以提高数值精度和训练稳定性。
通过混合精度训练,我们能够在保留 bf16
的内存和计算优势的同时,利用 fp32
保证训练过程的高精度更新,从而在效率和精度之间取得平衡。
英文版
Why Don’t We Directly Perform Weight Updates in bf16
?
In deep learning training, we typically use mixed-precision training to improve training efficiency and reduce memory usage. While bf16
(Brain Floating Point 16) provides high efficiency in terms of storage and computation, its limited numerical precision makes it unsuitable for direct weight updates. Instead, we convert low-precision data (like gradients) to fp32
during updates, and then store the results back in bf16
. This strategy ensures that the precision of the updates is maintained, thus avoiding significant numerical instability during training.
In this blog, we will delve into why we don’t directly use bf16
for weight updates, and we will explain the conversion from bf16
to fp32
during updates using numerical simulations.
1. Why Don’t We Directly Perform Weight Updates in bf16
?
1.1 Precision Limitations of bf16
-
bf16
Representation Range:bf16
uses a 16-bit floating-point format, with 8 bits for the exponent and 7 bits for the mantissa. This means that the mantissa’s precision is relatively low, limiting its ability to represent small decimal values accurately. As a result,bf16
cannot represent certain precise numerical values. This is particularly problematic when performing weight updates during training, where small numerical changes can accumulate and affect the model’s performance. -
High Precision Requirement for Update Operations: In deep learning training, particularly with optimizers like Adam, calculating gradients and updating weights require higher numerical precision. If we perform these operations using
bf16
, the lower precision in the mantissa could lead to numerical errors that affect training stability and model convergence.
1.2 Precision Needed for Weight Updates
The weight update involves gradient accumulation and weighted updates, which generally require high precision to ensure that the gradient calculations and weight updates are not significantly affected by rounding errors. If performed in bf16
:
-
Gradient Accumulation Precision Loss: For example, when adding small gradient values in
bf16
, the mantissa’s low precision might cause significant errors in the accumulation process. -
Weight Update Precision Loss: The weight update formula is:
w t + 1 = w t − η ⋅ ∇ L w_{t+1} = w_t - \eta \cdot \nabla L wt+1=wt−η⋅∇L
When this update is performed in
bf16
, the limited precision in the mantissa may result in inaccurate updates to the weights, which would propagate and affect the model’s learning.
1.3 Using fp32
to Ensure Numerical Precision
fp32
(32-bit floating-point) provides higher precision, particularly with a 23-bit mantissa, which allows for more accurate representation of small numerical changes. This is crucial for maintaining the precision of gradient calculations and weight updates. Therefore, while we use low-precision bf16
for storage and computation in most of the training process, we switch to fp32
for the weight update to ensure precision and avoid negative impacts on the training process.
2. Numerical Simulation: The Difference Between Weight Updates in bf16
and fp32
To better understand why we don’t directly perform weight updates in bf16
, we can use a simple numerical simulation to show the precision differences between bf16
and fp32
during the weight update process.
2.1 Simulation Code
import torch# Initialize a gradient (assumed to be 1e-3) and weight (assumed to be 1.23456)
grad_bf16 = torch.tensor([1e-3], dtype=torch.bfloat16)
weight_bf16 = torch.tensor([1.23456], dtype=torch.bfloat16)# Learning rate
lr = 0.1# Perform weight update in bf16
updated_weight_bf16 = weight_bf16 - lr * grad_bf16
print("Updated weight (bf16):", updated_weight_bf16)# Convert bf16 to fp32
grad_fp32 = grad_bf16.to(torch.float32)
weight_fp32 = weight_bf16.to(torch.float32)# Perform weight update in fp32
updated_weight_fp32 = weight_fp32 - lr * grad_fp32
print("Updated weight (fp32):", updated_weight_fp32)
2.2 Results Analysis
Running the code gives the following output:
Updated weight (bf16): tensor([1.23446], dtype=torch.bfloat16)
Updated weight (fp32): tensor([1.234550], dtype=torch.float32)
As we can see, the updated weight in bf16
is 1.23446
, while in fp32
it’s 1.234550
. The difference in precision is noticeable: the bf16
update loses precision after the decimal point, particularly when the gradient is small.
2.3 Why Does This Happen?
-
Precision Loss: In
bf16
, due to the limited mantissa (7 bits), small updates to the weight may be truncated. This causes the update to lose precision, particularly when the gradient values are very small. -
fp32
Provides Higher Precision: In contrast,fp32
has a 23-bit mantissa, allowing for a much more accurate representation of small decimal values. Therefore, weight updates performed infp32
are more precise and result in less error accumulation.
3. Why Convert bf16
to fp32
for Weight Updates?
3.1 Advantages and Limitations of bf16
-
Advantages:
- Efficient Storage and Computation: Since
bf16
uses only 16 bits, it requires less memory and computation compared tofp32
. This is especially beneficial in large-scale models where memory usage can be a bottleneck. - Larger Numeric Range: The 8-bit exponent of
bf16
allows it to cover a wider range of numbers compared tofp16
, which can be useful when dealing with large numerical values during training.
- Efficient Storage and Computation: Since
-
Limitations:
- Insufficient Precision: The 7-bit mantissa of
bf16
is insufficient for representing small numerical changes, which is critical for weight updates and gradient accumulation during training.
- Insufficient Precision: The 7-bit mantissa of
3.2 The Need for fp32
Conversion
To overcome the precision limitation of bf16
, we convert bf16
to fp32
during weight updates. This is necessary because:
-
fp32
Provides Higher Mantissa Precision: With a 23-bit mantissa,fp32
ensures that small changes, such as those in gradients, are captured more accurately, preventing the loss of precision that could occur inbf16
. -
Improved Numerical Stability:
fp32
provides better numerical stability in operations that require high precision, such as gradient accumulation and weight updates.
4. Summary
-
Why Don’t We Directly Perform Weight Updates in
bf16
?bf16
has a limited mantissa precision, making it unsuitable for performing weight updates directly. The precision loss inbf16
would lead to significant errors in gradient accumulation and weight updates, which would negatively affect model training.
-
Numerical Simulation Results: From the numerical simulation, we can see that
bf16
loses precision during weight updates, particularly when the gradient is small. In contrast,fp32
retains much higher precision, leading to more accurate weight updates. -
Why Convert
bf16
tofp32
?fp32
offers much higher precision (23-bit mantissa), which is necessary for stable and accurate weight updates during training. Convertingbf16
tofp32
ensures that the weight update process does not lose valuable information and remains numerically stable.
By using mixed-precision training, we can take advantage of bf16
’s memory efficiency while ensuring that key operations like weight updates are performed in fp32
to maintain precision and stability in the training process. This approach optimizes both efficiency and accuracy.
后记
2024年12月31日22点10分于上海,在GPT4o大模型辅助下完成。
相关文章:

混合精度训练(Mixed Precision Training)中为什么在训练过程中不直接使用bf16进行权重更新?中英双语
中文版 为什么在训练过程中不直接使用 bf16 进行权重更新? 在深度学习的训练过程中,我们通常使用 混合精度训练(Mixed Precision Training)来提高训练效率,减少内存占用。虽然 bf16(Brain Floating Point…...

【java】HashMap的实现原理
目录 1. 说明2. 哈希函数3. 桶数组4. 哈希冲突解决5. 动态扩容6. 查找、插入和删除操作 1. 说明 1.HashMap是一个基于哈希表的数据结构,它实现了Map接口。2.HashMap允许使用null键和null值,并且不保证映射的顺序。 2. 哈希函数 1.HashMap使用哈希函数…...

FCM32F103C8T6开发指引
打了块板,没有STM芯片了,于是,换了块FCM32F103C8T6.原来的工程直接编译,不能仿真,提示M3,M4核不兼容,但是,用jflash是可以直接把bin文件烧录进去的,也可以正常运行起来。 但为了方便…...

Python世界:人生苦短,我用Python
Python世界:人生苦短,我用Python 前言Python优势Python缺点 前言 几句话说清,我们为啥要用Python? Python设计之初心,是为了解决编程门槛,让大家更聚焦业务实现,而非编程细节。当前人工智能火…...

【从零开始入门unity游戏开发之——C#篇43】C#补充知识——值类型和引用类型汇总补充、变量的生命周期与性能优化、值类型和引用类型组合使用
文章目录 一、值类型和引用类型汇总补充1、值类型和引用类型汇总2、值类型和引用类型的区别3、简单的判断值类型和引用类型 二、变量的生命周期与性能优化1、**栈和堆的区别**2、**变量生命周期**3、**垃圾回收(GC)机制**4、**代码示例与优化**4.1. 临时…...

从论文到实践:Stable Diffusion模型一键生成高质量AI绘画
🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年12月24日10点02分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文源地址有视频: 链接h…...

项目管理:用甘特图 “导航” 项目全程
项目全程管理是一个复杂而又系统的过程,它涵盖了从项目启动到结束的各个阶段,包括规划、执行、监控和收尾等一系列活动。 项目全程管理能够确保项目按时交付、控制成本、提高质量以及满足客户需求。通过有效的管理,项目团队可以避免资源浪费…...

v3.0.8- 「S+会员」新增专属运动秀,试试新穿搭吧- 与「好友」
v3.0.8 - 「S会员」新增专属运动秀,试试新穿搭吧 - 与「好友」互动支持前往对方所在的「在线运动房」 - 「运动秀工坊」新增智能背景抠图 - 「体育竞技」匹配中可以看到我和对手的装备 - 多项界面体验和性能优化 v2.0.17 - 班级运动场新增运动秀展示 - 班级玩法&…...

9-Gin 中自定义 Model --[Gin 框架入门精讲与实战案例]
在 Gin 框架中自定义 Model 通常指的是定义你自己的数据结构,这些结构体(Structs)将用来表示数据库中的表、API 请求的参数或响应的数据格式。下面是如何在 Gin 中创建和使用自定义 Model 的基本步骤。 自定义 Model 定义结构体 首先&…...

【VBA】EXCEL - VBA 创建 Sheet 表的 6 种方法,以及注意事项
目录 1. 创建一个新工作表,并将其添加到工作簿的末尾 2. 创建一个新工作表,并命名它 3. 创建一个新工作表,并将其插入到指定位置 4. 检查是否已有同名工作表,避免重复创建 5. 创建多个工作表 6. 基于现有模板创建新工作表 …...

数据库中,group by 和partition by:数据分组和数据分区的区别
数据库中,group by 和partition by:数据分组和数据分区的区别 在大规模数据处理和分析的场景中,对数据进行分区和分组处理是非常常见的场景。 为了实现这一操作,在一些主流的关系型数据库管理系统中,提供了group by 和…...

【linux学习指南】Ext系列文件系统(四)路径分区链接
文章目录 🌠⽬录与⽂件名🌠路径解析🌠路径缓存🌠挂载分区🌉 ⽂件系统总结 🌠软硬连接🌉 硬链接🌉 软链接🌉 软硬连接对⽐🌉软硬连接的⽤途: &…...

深度学习中的参数初始化
深度学习中的参数初始化主要是指初始化神经网络中的权重和偏置。权重和偏置通常分开初始化,偏置通常初始化为零或较小的常数值。 没有一种万能的初始化技术,因为最佳初始化可能因具体架构和要解决的问题而异。因此,尝试不同的初始化技术以了解…...

wpf 基于Behavior库 的行为模块
Microsoft.Xaml.Behaviors 是一个用于WPF(Windows Presentation Foundation)的行为库,它的主要作用是允许开发者在不修改控件源代码的情况下,为控件添加自定义的行为和交互逻辑。行为库的核心思想是通过定义可重用的行为组件&…...

【每日学点鸿蒙知识】导入cardEmulation、自定义装饰器、CallState状态码顺序、kv配置、签名文件配置
1、HarmonyOS 无法导入cardEmulation? 在工程entry mudule里的index.ets文件里导入cardEmulation失败 可以按照下面方式添加SystemCapability;在src/main/syscap.json(此文件需要手动创建)中添加如下内容 {"devices": {"gen…...

【SpringMVC】REST 风格
REST(Representational State Transfer,表现形式状态转换)是一种访问网络资源的格式。传统的资源描述方式通常如下: http://localhost/user/getById?id1http://localhost/user/saveUser 而 REST 风格的描述则更简洁:…...

IDEA修改编译版本
目录 一、序言 二、修改maven配置 1.修改 2.代码 三、pom文件配置 1.修改 2.代码 3.问题 一、序言 有两种方法可以帮助大家解决IDEA每次刷新maven的pom配置时,会发生发行源版本不正常的报错。个人推荐第二种,原因:第二种你刷新maven后…...

SkyWalking Agent 配置 Spring Cloud Gateway 插件解决日志错误
SkyWalking Agent 配置 Spring Cloud Gateway 插件解决日志错误 IDEA中启动网管时,需要配置VM启动参数,格式如下: # 配置 SkyWalking Agent 启动参数,以便将网关服务的性能数据上报到 SkyWalking 服务器。 -javaagent:/path/to/sk…...

canvas+fabric实现时间刻度尺(一)
前言 需求:显示一个时间刻度尺,鼠标移动会显示当前时间 技术:我们采用canvasfabric进行实现 效果 实现 1.创建canvas(设置宽高)设为全局变量 2.引入fabric包 3.画时间刻度尺(长方形横线) …...

傲雷亮相2024中国时尚体育季(珠海站),展现户外移动照明风采
2024年12月28-29日,2024中国时尚体育季(珠海站)国家级轮滑比赛在珠海金山体育公园成功举办。作为户外创新型移动照明领域的领导品牌,傲雷受邀参加了本次珠海金湾运动生活嘉年华的展览单元,与众多户外运动品牌同台展示。…...

YOLOv10-1.1部分代码阅读笔记-block.py
block.py ultralytics\nn\modules\block.py 目录 block.py 1.所需的库和模块 2.class DFL(nn.Module): 3.class Proto(nn.Module): 4.class HGStem(nn.Module): 5.class HGBlock(nn.Module): 6.class SPP(nn.Module): 7.class SPPF(nn.Module): 8.class C1(nn…...

@RestControllerAdvice注解
RestControllerAdvice 是 Spring 4 引入的一个组合注解,它结合了 ControllerAdvice 和 ResponseBody,专门用于处理 RestController 类型的控制器中的全局异常、全局数据绑定和全局模型属性等问题。在 Spring Boot 中,RestControllerAdvice 通…...

Enum枚举类与静态变量和静态数组的区别
Enum枚举类与静态变量和静态数组的区别 组成结构Enum枚举类静态变量静态数组 组成结构的区别相同之处不同之处 用法使用相同之处不同之处 组成结构 先来看下Enum枚举类,静态变量,静态数组的初始化过程,以下面为例子: public enu…...

uniapp——微信小程序读取bin文件,解析文件的数据内容(三)
微信小程序读取bin文件内容 读取用户选择bin文件,并解析数据内容,分包发送给蓝牙设备; 文章目录 微信小程序读取bin文件内容读取文件读取内容返回格式 API文档: getFileSystemManager 关于App端读取bin文件,请查看&…...

SpringBoot集成ECDH密钥交换
简介 对称加解密算法都需要一把秘钥,但是很多情况下,互联网环境不适合传输这把对称密码,有密钥泄露的风险,为了解决这个问题ECDH密钥交换应运而生 EC:Elliptic Curve——椭圆曲线,生成密钥的方法 DH&…...

python文件操作相关(excel)
python文件操作相关(excel) 1. openpyxl 库openpyxl其他用法创建与删除操作单元格追加数据格式化单元格合并单元格插入图片公式打印设置保护工作表其他功能 2. pandas 库3. xlrd 和 xlwt 库4. xlsxwriter 库5. pyxlsb 库应用场景参考资料 在 Python 中&a…...

探索React与Microi吾码的完美结合:快速搭建项目,低代码便捷开发教程
一、摘要 在当今的数字化时代,软件开发就像是一场探险,每个开发者都是探险家,探索着代码的奥秘。React作为前端开发的领军框架,其组件化和高效的渲染机制为开发者提供了强大的工具。而Microi吾码低代码平台的出现,则为…...

【面试系列】深入浅出 Spring Boot
熟悉SpringBoot,对常用注解、自动装配原理、Jar启动流程、自定义Starter有一定的理解; 面试题 Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?Spring Boot的自动配置原理是什么?你如何理解 Spring Boot 配置…...

@colyseus/social 模块详解
@colyseus/social 模块介绍 @colyseus/social 是一个适用于 Colyseus 游戏框架的扩展模块,提供了社交功能的支持,帮助开发者在多人游戏中快速实现玩家之间的社交互动。它主要提供了玩家账户管理、好友系统、好友请求、组队和聊天功能等,旨在简化游戏中社交功能的实现。 核心…...

石岩路边理发好去处
周末带娃去罗租公园玩,罗租公园旁边就是百佳华和如意豪庭小区,发现如意豪庭小区对面挺多路边理发摊点 理发摊点聚焦在这里的原因是刚好前面城管来了暂时避避,例如还有一个阿姨剪到一半就跟着过来。这里的城管只是拍了一处没有摊位的地方&…...