基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-08-02 02:31

Transformer训练加速:GPU融合与精度优化

MarkTechPost#NVIDIA#GPU优化#Transformer
Editor brief · 编辑速览

详解 NVIDIA Transformer Engine 的 FP8 低精度、融合内核配置、性能基准测试,附 PyTorch 完整代码。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

人工智能

本教程将探讨 NVIDIA Transformer Engine 如何通过融合 GPU 内核、BF16 计算以及针对硬件优化的 FP8 执行来加速 Transformer 工作负载。首先,我们会安装 Transformer Engine,并检测当前使用的 GPU 架构,以确定运行环境支持 TE 内核、FP8 Tensor Core,还是只能使用纯 PyTorch 回退路径。随后,我们将研究 te.Linear、te.LayerNorm、te.LayerNormLinear、te.LayerNormMLP 和 te.TransformerLayer 等核心融合组件,同时配置一种延迟缩放 FP8 recipe,用于管理张量缩放、amax 历史记录以及混合 E4M3/E5M2 格式。利用这些组件,我们将构建一个紧凑的 GPT 风格因果语言模型,使用确定性的合成序列进行训练,对比高精度与 FP8 执行,测量运行时间和 GPU 峰值显存,检查 FP8 元数据,并通过自回归生成验证训练后的模型。

import subprocess, sys, os
def pip_install(*pkgs):
   subprocess.run([sys.executable, "-m", "pip", "install", "-q",
                   "--no-build-isolation", *pkgs], check=False)
print(">> Installing transformer_engine[pytorch] (this can take a few minutes)...")
pip_install("transformer_engine[pytorch]")
import time, math, gc
import torch
import torch.nn as nn
import torch.nn.functional as F
assert torch.cuda.is_available(), "Enable a GPU runtime in Colab first!"
DEVICE = "cuda"
props = torch.cuda.get_device_properties(0)
CC = (props.major, props.minor)
GPU_NAME = props.name
print(f">> GPU: {GPU_NAME} | compute capability {CC[0]}.{CC[1]} | "
     f"{props.total_memory/1e9:.1f} GB")
TE_CAPABLE  = CC >= (8, 0)
FP8_CAPABLE = CC >= (8, 9)
te = None
if TE_CAPABLE:
   try:
       import transformer_engine.pytorch as te
       from transformer_engine.common import recipe
       print(">> Transformer Engine imported OK:",
             getattr(te, "__version__", "unknown version"))
   except Exception as e:
       print(f">> TE import failed ({e}); using pure-PyTorch fallback.")
       TE_CAPABLE = FP8_CAPABLE = False
else:
   print(">> GPU is pre-Ampere (e.g. T4): TE kernels unsupported -> fallback mode.")
if TE_CAPABLE and FP8_CAPABLE and te is not None:
   try:
       ok, reason = te.fp8.check_fp8_support()
       FP8_CAPABLE = bool(ok)
       if not ok:
           print(">> TE reports FP8 unsupported:", reason)
   except Exception:
       pass
print(f">> Mode: TE={'ON' if TE_CAPABLE else 'OFF'} | "
     f"FP8={'ON' if FP8_CAPABLE else 'OFF (will use BF16)'}")
torch.manual_seed(1234)
if TE_CAPABLE:
   H = 768
   x_demo = torch.randn(8, 32, H, device=DEVICE, dtype=torch.bfloat16)
   lin      = te.Linear(H, H, bias=True, params_dtype=torch.bfloat16).to(DEVICE)
   ln       = te.LayerNorm(H, params_dtype=torch.bfloat16).to(DEVICE)
   ln_lin   = te.LayerNormLinear(H, 3 * H, params_dtype=torch.bfloat16).to(DEVICE)
   ln_mlp   = te.LayerNormMLP(H, 4 * H, params_dtype=torch.bfloat16).to(DEVICE)
   with torch.no_grad():
       print("\n>> Module tour (shapes):")
       print("   te.Linear         ", tuple(lin(x_demo).shape))
       print("   te.LayerNorm      ", tuple(ln(x_demo).shape))
       print("   te.LayerNormLinear", tuple(ln_lin(x_demo).shape))
       print("   te.LayerNormMLP   ", tuple(ln_mlp(x_demo).shape))
   del lin, ln, ln_lin, ln_mlp, x_demo
   gc.collect(); torch.cuda.empty_cache()
fp8_recipe = None
if FP8_CAPABLE:
   fp8_recipe = recipe.DelayedScaling(
       fp8_format=recipe.Format.HYBRID,
       amax_history_len=16,
       amax_compute_algo="max",
   )
   print("\n>> FP8 recipe:", fp8_recipe)

我们安装 NVIDIA Transformer Engine,并初始化 GPU 加速执行所需的 PyTorch 环境。通过检查当前 GPU、计算能力和显存容量,我们可以判断融合 TE 内核与 FP8 Tensor Core 是否可用。我们还会验证核心融合模块,并配置延迟缩放 FP8 recipe,同时为不受支持的硬件保留自动切换至 PyTorch 的回退机制。

VOCAB, D_MODEL, N_HEADS, N_LAYERS, FFN, SEQ = 96, 768, 12, 4, 3072, 256
class MiniGPT_TE(nn.Module):
   """Causal LM where every block is a single fused te.TransformerLayer."""
   def __init__(self):
       super().__init__()
       self.emb = nn.Embedding(VOCAB, D_MODEL)
       self.pos = nn.Embedding(SEQ, D_MODEL)
       self.blocks = nn.ModuleList([
           te.TransformerLayer(
               hidden_size=D_MODEL,
               ffn_hidden_size=FFN,
               num_attention_heads=N_HEADS,
               self_attn_mask_type="causal",
               layer_number=i + 1,
               params_dtype=torch.bfloat16,
               hidden_dropout=0.0,
               attention_dropout=0.0,
           )
           for i in range(N_LAYERS)
       ])
       self.ln_f = nn.LayerNorm(D_MODEL)
       self.head = nn.Linear(D_MODEL, VOCAB, bias=False)
   def forward(self, idx):
       B, T = idx.shape
       h = self.emb(idx) + self.pos(torch.arange(T, device=idx.device))
       h = h.to(torch.bfloat16)
       for blk in self.blocks:
           h = blk(h)
       h = self.ln_f(h.float())
       return self.head(h)
class Block_PT(nn.Module):
   """Plain-PyTorch transformer block, mirrors te.TransformerLayer."""
   def __init__(self):
       super().__init__()
       self.ln1 = nn.LayerNorm(D_MODEL)
       self.attn = nn.MultiheadAttention(D_MODEL, N_HEADS, batch_first=True)
       self.ln2 = nn.LayerNorm(D_MODEL)
       self.mlp = nn.Sequential(nn.Linear(D_MODEL, FFN), nn.GELU(),
                                nn.Linear(FFN, D_MODEL))
   def forward(self, x, mask):
       a, _ = self.attn(self.ln1(x), self.ln1(x), self.ln1(x),
                        attn_mask=mask, need_weights=False)
       x = x + a
       return x + self.mlp(self.ln2(x))
class MiniGPT_PT(nn.Module):
   def __init__(self):
       super().__init__()
       self.emb = nn.Embedding(VOCAB, D_MODEL)
       self.pos = nn.Embedding(SEQ, D_MODEL)
       self.blocks = nn.ModuleList([Block_PT() for _ in range(N_LAYERS)])
       self.ln_f = nn.LayerNorm(D_MODEL)
       self.head = nn.Linear(D_MODEL, VOCAB, bias=False)
   def forward(self, idx):
       B, T = idx.shape
       mask = torch.triu(torch.full((T, T), float("-inf"),
                                    device=idx.device), diagonal=1)
       h = self.emb(idx) + self.pos(torch.arange(T, device=idx.device))
       for blk in self.blocks:
           h = blk(h, mask)
       return self.head(self.ln_f(h))
model = (MiniGPT_TE() if TE_CAPABLE else MiniGPT_PT()).to(DEVICE)
n_params = sum(p.numel() for p in model.parameters())
print(f"\n>> Model: {'TE fused' if TE_CAPABLE else 'pure PyTorch'} | "
     f"{n_params/1e6:.1f}M params | {N_LAYERS} layers x {D_MODEL}d")

我们使用融合的 te.TransformerLayer block 定义了一个紧凑的因果语言模型,以便通过 Transformer Engine 执行。同时,我们还实现了一个等价的纯 PyTorch Transformer 架构,其中包含多头注意力、Layer Normalization、残差连接和前馈网络。程序会根据 GPU 的支持情况动态选择合适的模型,并输出最终的参数量和架构维度。

def make_batch(bsz=16):
   phase  = torch.randint(0, VOCAB, (bsz, 1))
   stride = torch.randint(1, 7, (bsz, 1))
   steps  = torch.arange(SEQ + 1).unsqueeze(0)
   seq = (phase + stride * steps) % VOCAB
   return seq[:, :-1].to(DEVICE), seq[:, 1:].to(DEVICE)
opt = torch.optim.AdamW(model.parameters(), lr=3e-4)
def run_step(x, y, use_fp8):
   if TE_CAPABLE and use_fp8:
       with te.fp8_autocast(enabled=True, fp8_recipe=fp8_recipe):
           logits = model(x)
   else:
       logits = model(x)
   loss = F.cross_entropy(logits.float().reshape(-1, VOCAB), y.reshape(-1))
   opt.zero_grad(set_to_none=True)
   loss.backward()
   opt.step()
   return loss.item()
print(f"\n>> Training 60 steps ({'FP8' if FP8_CAPABLE else 'BF16/FP32'})...")
t0 = time.time()
for step in range(1, 61):
   x, y = make_batch()
   loss = run_step(x, y, use_fp8=FP8_CAPABLE)
   if step % 10 == 0:
       print(f"   step {step:3d} | loss {loss:.4f} | "
             f"{(time.time()-t0)/step*1000:.0f} ms/step")
print(f">> Final loss: {loss:.4f} (random guess would be ~{math.log(VOCAB):.2f})")

我们创建具有确定性算术规律的序列,让模型能够学习整个词表中可预测的 token 转移。接着配置 AdamW 优化器,并实现一个训练步骤:当硬件支持 FP8 执行时,使用 te.fp8_autocast 包裹前向传播。我们对模型进行多轮迭代训练,监控 loss 和每一步的延迟,并将最终 loss 与随机猜测的基线进行比较。

def bench(use_fp8, iters=30, warmup=10):
   x, y = make_batch(bsz=32)
   for _ in range(warmup):
       run_step(x, y, use_fp8)
   torch.cuda.synchronize()
   torch.cuda.reset_peak_memory_stats()
   t = time.time()
   for _ in range(iters):
       run_step(x, y, use_fp8)
   torch.cuda.synchronize()
   ms = (time.time() - t) / iters * 1000
   mem = torch.cuda.max_memory_allocated() / 1e9
   return ms, mem
print("\n>> Benchmark (batch 32, seq 256, fwd+bwd+optim):")
ms_hi, mem_hi = bench(use_fp8=False)
print(f"   {'BF16' if TE_CAPABLE else 'FP32'}: {ms_hi:7.1f} ms/step | "
     f"peak mem {mem_hi:.2f} GB")
if FP8_CAPABLE:
   ms_f8, mem_f8 = bench(use_fp8=True)
   print(f"   FP8 : {ms_f8:7.1f} ms/step | peak mem {mem_f8:.2f} GB")
   print(f"   Speedup: {ms_hi/ms_f8:.2f}x  "
         f"(gains grow with model size — try D_MODEL=2048, N_LAYERS=12)")
else:
   print("   FP8 benchmark skipped — needs an sm_89+ GPU (L4/H100/Ada/Blackwell).")
if FP8_CAPABLE:
   blk = model.blocks[0]
   for name, m in blk.named_modules():
       meta = getattr(m, "fp8_meta", None)
       if meta and "scaling_fwd" in meta:
           s = meta["scaling_fwd"]
           print(f"\n>> FP8 state of block-0 submodule '{name}':")
           print("   scale       :", s.scale.flatten()[:4].tolist())
           print("   amax_history:", s.amax_history[0, :4].tolist())
           break

我们分别在高精度和 FP8 执行模式下,对前向传播、反向传播以及优化器更新进行基准测试。通过测量平均训练步骤延迟和 GPU 已分配显存峰值,量化低精度计算对性能与显存占用的影响。我们还会检查 Transformer Engine 维护的缩放因子和 amax 历史记录,以了解延迟缩放如何帮助稳定 FP8 张量。

@torch.no_grad()
def generate(prompt_len=8, gen_len=24):
   x, _ = make_batch(bsz=1)
   ctx = x[:, :prompt_len]
   for _ in range(gen_len):
       inp = ctx[:, -SEQ:]
       if TE_CAPABLE and FP8_CAPABLE:
           with te.fp8_autocast(enabled=True, fp8_recipe=fp8_recipe):
               logits = model(inp)
       else:
           logits = model(inp)
       nxt = logits[:, -1].argmax(-1, keepdim=True)
       ctx = torch.cat([ctx, nxt], dim=1)
   return ctx[0].tolist()
seq = generate()
print("\n>> Greedy generation (should continue the arithmetic pattern):")
print("   prompt+gen:", seq)
diffs = [(b - a) % VOCAB for a, b in zip(seq, seq[1:])]
print("   step diffs:", diffs, "<- constant stride = model learned the rule")
print("\n>> Done! Things to try next:")
print("   * Scale up: D_MODEL=2048, N_LAYERS=12 -> FP8 speedup becomes dramatic")
print("   * recipe.Format.E4M3 vs HYBRID; amax_history_len=1024")
print("   * te.LayerNormMLP / te.LayerNormLinear in your own architectures")
print("   * fp8_model_init() to store weights themselves in FP8 for inference")

我们实现了贪心自回归生成:反复将最新的上下文输入训练后的因果语言模型。通过比较连续生成的 token,我们可以验证模型是否保持了合成训练数据中的固定算术步长。最后,我们列出了一些实际可行的扩展方向,包括增大模型维度、采用其他 FP8 格式、使用更长的 amax 历史记录、引入融合模块,以及初始化 FP8 权重。

总而言之,我们展示了如何将 NVIDIA Transformer Engine 集成到端到端的 Transformer 训练工作流中,同时保持对不同 Colab GPU 环境的兼容性。我们使用融合 Transformer 模块减少内核启动开销和显存流量;在硬件支持时,通过延迟缩放应用 FP8 autocasting;并借助自动 PyTorch 回退机制保留 BF16 或 FP32 执行路径。通过训练同一个迷你因果语言模型并进行基准测试,我们观察了硬件能力、数值格式、融合执行方式以及模型规模如何影响训练速度和显存消耗。我们还检查了支持稳定 FP8 计算的内部缩放因子与 amax 历史记录,从而更清楚地理解 Transformer Engine 如何管理低精度运算。

欢迎查看完整代码。也欢迎在 Twitter 上关注我们,别忘了加入我们拥有超过 15 万名成员的机器学习 SubReddit,并订阅 Newsletter。等等!你使用 Telegram 吗?现在也可以加入我们的 Telegram。

希望与我们合作,推广你的 GitHub Repo、Hugging Face Page、产品发布或 Webinar 等内容?欢迎联系我们。

Sana Hassan 是 MarkTechPost 的咨询实习生,也是 IIT Madras 的双学位学生。他热衷于运用技术和 AI 解决现实世界中的挑战。凭借对解决实际问题的浓厚兴趣,他为 AI 与现实生活解决方案的交汇领域带来了全新的视角。

Original source

本文由 AI 翻译整理,来源 MarkTechPost,原文版权归原作者所有。

阅读原文
上一篇
Agent系统架构选择:单体 vs 多体
下一篇
Python + FastAPI 构建生产级 AI Agent 完整指南

资讯速览

MarkTechPost · 2026-08-02 02:31

AI 评分 8.0 / 10

相关标签

#NVIDIA#GPU优化#Transformer

继续阅读

  • Agent 权限蔓延:如何在增量需求中悄悄发生
  • Agent系统架构选择:单体 vs 多体
  • Python + FastAPI 构建生产级 AI Agent 完整指南
  • 用 AI Agent 构建多租户 SaaS:架构与成本控制
  • AI Agent 金融操作必须人工审批:架构模式