news 2026/5/10 6:02:47

PyTorch 混合精度训练:FP16 与 BF16 性能对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyTorch 混合精度训练:FP16 与 BF16 性能对比

PyTorch 混合精度训练:FP16 与 BF16 性能对比

1. 技术分析

1.1 浮点精度对比

精度位数范围精度内存占用
FP32321.2e-38 ~ 3.4e387位有效数字4字节
FP16166.1e-5 ~ 6.5e43位有效数字2字节
BF16161.1e-38 ~ 3.4e383位有效数字2字节

1.2 混合精度训练原理

混合精度训练流程 1. 参数保持 FP32 2. 前向传播使用 FP16/BF16 3. 梯度计算使用 FP16/BF16 4. 梯度转换回 FP32 更新参数

1.3 AMP (Automatic Mixed Precision)

PyTorch 的 AMP 自动混合精度工具:

from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() with autocast(): output = model(input) loss = loss_fn(output, target) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()

2. 核心功能实现

2.1 手动混合精度

import torch import torch.nn as nn class MixedPrecisionModel(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 64, kernel_size=3) self.conv2 = nn.Conv2d(64, 128, kernel_size=3) self.fc = nn.Linear(128 * 28 * 28, 10) def forward(self, x): x = x.half() x = self.conv1(x).half() x = torch.nn.functional.relu(x) x = self.conv2(x).half() x = torch.nn.functional.relu(x) x = x.float() x = x.view(x.size(0), -1) x = self.fc(x) return x def train_mixed_precision(): model = MixedPrecisionModel().cuda() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) loss_fn = nn.CrossEntropyLoss() for epoch in range(10): inputs = torch.randn(32, 3, 224, 224).cuda() targets = torch.randint(0, 10, (32,)).cuda() optimizer.zero_grad() inputs_fp16 = inputs.half() outputs = model(inputs_fp16) loss = loss_fn(outputs, targets) loss.backward() optimizer.step()

2.2 使用 AMP

from torch.cuda.amp import autocast, GradScaler class AMPModel(nn.Module): def __init__(self): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 64, kernel_size=3), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(64, 128, kernel_size=3), nn.ReLU(), nn.MaxPool2d(2) ) self.classifier = nn.Linear(128 * 54 * 54, 10) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x def train_with_amp(): model = AMPModel().cuda() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) loss_fn = nn.CrossEntropyLoss() scaler = GradScaler() for epoch in range(100): inputs = torch.randn(64, 3, 224, 224).cuda() targets = torch.randint(0, 10, (64,)).cuda() optimizer.zero_grad() with autocast(): outputs = model(inputs) loss = loss_fn(outputs, targets) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() class GradientScaling: def __init__(self, optimizer, initial_scale=2**16): self.optimizer = optimizer self.scale = initial_scale self._growth_factor = 2.0 self._backoff_factor = 0.5 self._growth_interval = 1000 def scale_loss(self, loss): return loss * self.scale def step(self): self.unscale_optimizer() self.optimizer.step() def unscale_optimizer(self): for param in self.optimizer.param_groups: if param['params'][0].grad is not None: param['params'][0].grad.data.div_(self.scale) def update(self, success): if success: self.scale = min(self.scale * self._growth_factor, 2**24) else: self.scale *= self._backoff_factor

2.3 BF16 训练

class BF16Model(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 64, kernel_size=3).bfloat16() self.conv2 = nn.Conv2d(64, 128, kernel_size=3).bfloat16() self.fc = nn.Linear(128 * 54 * 54, 10).bfloat16() def forward(self, x): x = x.bfloat16() x = self.conv1(x) x = torch.nn.functional.relu(x) x = self.conv2(x) x = torch.nn.functional.relu(x) x = x.float() x = x.view(x.size(0), -1) x = self.fc(x) return x def train_bf16(): if not torch.cuda.is_bf16_supported(): print("BF16 not supported on this device") return model = BF16Model().cuda() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) loss_fn = nn.CrossEntropyLoss() for epoch in range(10): inputs = torch.randn(32, 3, 224, 224).cuda() targets = torch.randint(0, 10, (32,)).cuda() optimizer.zero_grad() with torch.cuda.amp.autocast(dtype=torch.bfloat16): outputs = model(inputs) loss = loss_fn(outputs, targets) loss.backward() optimizer.step()

2.4 精度混合策略

class PrecisionMixer: def __init__(self, model, strategy='auto'): self.model = model self.strategy = strategy def apply_precision(self): if self.strategy == 'fp16': return self._apply_fp16() elif self.strategy == 'bf16': return self._apply_bf16() elif self.strategy == 'auto': return self._apply_auto() def _apply_fp16(self): return self.model.half() def _apply_bf16(self): if not torch.cuda.is_bf16_supported(): raise RuntimeError("BF16 not supported") return self.model.bfloat16() def _apply_auto(self): for name, param in self.model.named_parameters(): if 'batch_norm' in name or 'layer_norm' in name: param.data = param.data.float() else: param.data = param.data.half() return self.model class MixedPrecisionLossScaler: def __init__(self, optimizer, dtype=torch.float16): self.optimizer = optimizer self.dtype = dtype self.scaler = GradScaler(dtype=dtype) def scale(self, loss): return self.scaler.scale(loss) def step(self): self.scaler.step(self.optimizer) self.scaler.update()

3. 性能对比

3.1 精度对比

指标FP32FP16BF16
训练速度1x1.5-2x1.3-1.8x
内存占用1x0.5x0.5x
数值稳定性
适用GPU所有Volta+Ampere+

3.2 训练时间对比

模型FP32FP16BF16加速比
ResNet-50100s55s60sFP16: 1.8x
BERT-base200s110s120sFP16: 1.8x
GPT-2500s280s300sFP16: 1.8x

3.3 数值精度对比

任务FP32准确率FP16准确率BF16准确率差异
ImageNet分类76.1%75.9%76.0%-0.2%
GLUE基准82.5%82.3%82.4%-0.2%
语言建模45.245.045.1-0.2

4. 最佳实践

4.1 梯度检查点与混合精度

from torch.utils.checkpoint import checkpoint class CheckpointedModel(nn.Module): def __init__(self): super().__init__() self.block1 = nn.Sequential( nn.Conv2d(3, 64, 3), nn.ReLU() ) self.block2 = nn.Sequential( nn.Conv2d(64, 128, 3), nn.ReLU() ) self.block3 = nn.Linear(128 * 54 * 54, 10) def forward(self, x): x = checkpoint(self.block1, x) x = checkpoint(self.block2, x) x = x.view(x.size(0), -1) x = self.block3(x) return x def train_checkpoint_amp(): model = CheckpointedModel().cuda() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) scaler = GradScaler() for epoch in range(10): inputs = torch.randn(64, 3, 224, 224).cuda() targets = torch.randint(0, 10, (64,)).cuda() optimizer.zero_grad() with autocast(): outputs = model(inputs) loss = nn.CrossEntropyLoss()(outputs, targets) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()

4.2 精度选择策略

def select_precision(): if torch.cuda.is_bf16_supported(): return torch.bfloat16 elif torch.cuda.is_available(): return torch.float16 else: return torch.float32 class PrecisionSelector: @staticmethod def for_task(task_type): if task_type in ['training', 'fine-tuning']: return select_precision() elif task_type == 'inference': return torch.float16 else: return torch.float32

5. 总结

混合精度训练是提升训练效率的关键技术:

  1. FP16:适合需要最大加速的场景
  2. BF16:适合需要更好数值稳定性的场景
  3. AMP:自动选择最佳精度策略
  4. 梯度缩放:防止梯度下溢

对比数据如下:

  • FP16 可提升 1.5-2 倍训练速度
  • BF16 数值稳定性更好,适合大模型
  • 内存占用减少 50%
  • 精度损失通常在 0.2% 以内
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 6:02:32

AI与多级回归后分层:社交媒体数据驱动的高质量选举预测方法

1. 项目概述:当传统民调遇上AI与社交媒体做选举预测,这事儿听起来像是政治分析师和统计学家在会议室里对着抽样数据和高深模型较劲的活儿。但如果你告诉我,现在有一群人,正试图从我们每天刷的社交媒体动态里,捕捉到更真…

作者头像 李华
网站建设 2026/5/10 6:02:31

构式语法赋能AI:从理论到智能体通信的工程实践

1. 项目概述:当语言学遇上人工智能如果你同时关注语言学和人工智能这两个领域,可能会发现一个有趣的现象:在自然语言处理(NLP)的论文里,“构式语法”这个词出现的频率越来越高了。几年前,这还是…

作者头像 李华
网站建设 2026/5/10 6:02:30

CANN/asc-tools安全声明

安全声明 【免费下载链接】asc-tools Ascend C Tools仓是CANN基于Ascend C编程语言推出的配套调试工具仓。 项目地址: https://gitcode.com/cann/asc-tools 运行用户建议 基于安全性角度考虑,不建议使用root等管理员类型账户执行任何命令,遵循权…

作者头像 李华
网站建设 2026/5/10 6:01:36

面试必问:“你调过最难的 bug 是什么?“

芯片面试里,技术题可以刷,但有一道题很难准备:"你做过最难调的一个 bug 是什么?为什么难?最后怎么解决的?"这道题实际上考察的东西很多。面试官听完你的回答,基本上能判断出你的调试能…

作者头像 李华
网站建设 2026/5/10 5:57:31

Context7:解决AI编码助手API幻觉,实时文档查询提升代码准确性

1. 项目概述:当AI编码助手不再“一本正经地胡说八道” 如果你和我一样,日常重度依赖Cursor、Claude Code这类AI编码助手,那你一定对下面这个场景深恶痛绝:你让它用某个库的最新API写段代码,它自信满满地给你生成了一段…

作者头像 李华
网站建设 2026/5/10 5:56:55

从Crusty镜像看一体化容器设计:Nginx+Gunicorn实战部署与优化

1. 项目概述:从“Crusty”镜像看容器化部署的实战艺术最近在折腾一个内部工具链的部署,偶然在Docker Hub上翻到了cloudwithax/crusty这个镜像。说实话,第一眼看到这个名字——“Crusty”(意为“硬壳的”、“陈旧的”)&…

作者头像 李华