简介:《NVIDIA H100 Tensor Core GPU 架构白皮书》中文版是一份面向AI训练、高性能计算、数据中心架构与GPU加速领域的专业资料,适合具备CUDA基础的研发工程师、系统架构师、科研人员及技术决策者。内容围绕Hopper架构展开,详细解析800亿晶体管规模、132个SM、第四代Tensor Core、Transformer引擎、DPX指令、线程块簇、TMA异步传输、第二代MIG、HBM3高带宽显存、50MB二级缓存以及第四代NVLink互连等关键特性,并说明相较A100约6倍的性能提升,能够支撑大语言模型训练、HPC应用、多租户隔离及机密计算等场景。压缩包内共有1个PDF文件,大小8.05MB,便于在各类设备上离线阅读和检索。目前已有335人学习/下载。文档专业性强,建议结合NVIDIA CUDA文档与Nsight等工具深入研读,重点关注FP8/TF32精度、TMA异步传输及DPX指令在实际算法中的性能调优,为新一代GPU应用开发提供参考。
1. 这份 H100 架构白皮书中文版,先弄清它值不值得你花一晚上
如果你正打算在训练集群里引入 H100,或者刚拿到一台带 H100 的机器准备调性能,那么NVIDIA-H100-GPU-Architecture-Whitepaper-zhCN.pdf大概率是你手边最该读的第一份文档。它并不是一份使用手册,而是一份把芯片内部如何组织、计算单元如何工作、显存和互联如何配合讲透的架构说明书,解决的是“这卡到底强在哪、我写的 kernel 为什么没跑满”这类问题。这份中文版的价值在于,你不用一边查术语表一边啃几百页英文原文,能更快建立起对 Hopper 架构的整体判断。适合三类人:做大模型训练性能优化的、自己写 CUDA kernel 的、以及负责集群选型和容量规划的工程师。
2. 从 GPC 到 SM:H100 的芯片组织方式与白皮书的读图顺序
2.1 为什么拿到 PDF 先看芯片总览图,而不是先看参数表
大多数人读架构文档的习惯是直接翻到规格表,把 SM 数量、显存带宽、Tensor Core 峰值记下来就完事。这个做法不算错,但你会很快发现一个尴尬:规格表里的数字和实际跑出来的性能对不上。原因在于 H100 的物理布局和调度逻辑是层层嵌套的,只看顶层参数完全不知道数据是怎么流动的。
白皮书第一章给出的芯片总览图(通常在 PDF 前 10 页)会展示完整的层级关系:GPU 被划分为多个 GPC(图形处理簇),每个 GPC 内部包含若干 TPC(纹理处理簇),每个 TPC 又下辖两个 SM(流式多处理器)。这个层级不是摆设,它直接决定了数据在 L2 和 SM 之间的传播路径。你写的 kernel 被调度到哪个 SM 上,依赖的 L2 分片在哪个位置,都跟这个拓扑相关。
我一般会在这张图上花二十分钟,把每一层的数量抄下来,并和上一代 A100 做对照。H100 相比 A100,SM 总数、每 SM 的寄存器文件和调度器数量都有变化。白皮书的 Table 部分通常会给一个逐项对比,这一页值得拍照存手机里。读完这张图,你对后面章节里那些“每个 SM 可以同时发起多少条指令”“L2 带宽为什么能到多少”才有一个空间上的锚点。
2.2 用三层结构回答“kernel 到底跑在哪儿”
先建立最小认知:一个 CUDA kernel 启动时,GigaThread 引擎把线程块分发到 GPC 里的 SM 上,每个 SM 内部的四个调度器(H100 是四个,每个调度器每周期发射一条指令)负责把 warp 的指令发到执行单元。这里有个新手容易忽略的点:线程块被调度到哪个 SM 是硬件决定的,你只能通过 occupancy 配置间接影响。
白皮书里关于 SM 内部结构的章节会给出每个 SM 的详细框图,包括:
- 寄存器文件大小,决定了你一个线程最多能用多少寄存器
- Shared memory 容量,以及它和 L1 cache 如何划分
- 四个调度器分别连接哪些执行单元,Tensor Core 挂在哪一侧
- TMA(张量内存加速器)在哪个位置,它如何绕过寄存器直接搬运数据
这张图决定了你写 kernel 的姿势。举个例子,如果你要做一个大矩阵分块乘法,分块大小设为多少、shared memory 里同时驻留几个 block、每个线程用多少个寄存器,这些参数的合理区间全部由 SM 结构推导出来。白皮书给了结构图,剩下的是你自己做约束推导。
当你在白皮书相关章节里看到 “每个 SM 每周期可执行 2048 次 FP16 浮点运算” 这类表述时,不要把它当考点,要意识到这意味着如果你的 kernel 每个周期实际只发出 512 次运算,那利用率就只剩四分之一。后面章节我会给一段计算代码,用白皮书参数现场推算峰值。
2.3 对比 A100:一张表看懂 H100 的改动重点
白皮书通常会用一页 Table 列出 H100 与 A100 的规格差异,这是全 PDF 信息密度最高的一页。下面这张表是我通常建议读者自己动手从 PDF 里抄出来填完的模板,因为翻译版和英文原版的排版行号可能不同,抄一遍能让你把数字的位置记住。
| 对比项 | A100(参考) | H100(填写白皮书数值) | 影响 |
|---|---|---|---|
| SM 数量 | 108 | 以 PDF 为准 | 影响并行规模上限 |
| 每 SM 最大线程数 | 2048 | 以 PDF 为准 | 影响 occupancy 计算 |
| Tensor Core 代数 | 第三代 | 第四代 | 指令集差异,需重编译 |
| L2 缓存容量 | 40 MB | 以 PDF 为准 | 影响数据复用策略 |
| HBM 类型与带宽 | HBM2e | HBM3 | 影响访存型 kernel 上限 |
| NVLink 代际与带宽 | 第三代 | 第四代 | 影响多卡通信 |
这张表填完之后,你会发现 H100 的改动不是单纯的“数字翻倍”,而是围绕 Transformer 类模型的计算模式做了定向调整。比如 Transformer Engine 的引入,让 FP8 精度在训练中的可用性大幅提升,这是 A100 时代没有的硬件路径。
2.4 读图顺序建议:先 GPC 再 SM 最后看内存
我的阅读顺序是从宏观到微观。先看芯片总览图确认 GPC 和 TPC 数量,再看单个 SM 的框图确认执行单元布局,然后跳到内存章节看 HBM3 和 L2 的带宽数字,最后回到 Tensor Core 章节看精度和指令细节。这样做的原因是,内存章节的很多表述依赖你对 SM 数量的理解,而 Tensor Core 章节又默认你已经知道数据从 L2 到 SM 的路径。
如果你跳着读,很可能在 “TMA 可以直接把数据从全局内存搬到 shared memory” 这句话上卡住,因为你不知道 TMA 在 SM 框图的哪个位置。白皮书不是小说,章节之间有强依赖,按结构读比按兴趣读高效得多。
3. Tensor Core 与 Transformer Engine:白皮书里最值得精读的计算章节
3.1 第四代 Tensor Core 的精度路线和指令变化
H100 的 Tensor Core 是第四代,相比 A100 的第三代,核心变化是加入了 FP8 支持,同时把 BF16 和 FP16 的峰值吞吐推高了一截。白皮书在 Tensor Core 章节会给出一个精度矩阵,列通常是 FP64、FP32、TF32、BF16、FP16、FP8,行是稠密(dense)和稀疏(sparse)两种模式。
这里有个关键概念:稀疏模式并不是自动生效的,它要求矩阵本身有可用的结构化稀疏(即每四个元素里有两个是零),且权重需要按照固定模式重新排列。白皮书会说明 2:4 结构化稀疏的硬件逻辑,但不会教你怎么在训练中制造稀疏性。所以你在规格表里看到的 “稀疏峰值” 是带条件的,别把它当普通浮点算力。
指令层面,H100 新增了面向 Tensor Core 的wgmma异步指令族,它配合 TMA 可以在 warp 级别发起大规模矩阵乘,而不再需要像 A100 时代那样在每个 warp 里反复执行同步加载。这个变化对 kernel 设计的影响很深:大量数据搬运可以被硬件异步化,SM 的调度器可以把时间让给计算指令。白皮书对这部分有架构描述,但具体的 PTX 写法属于另一个话题。
3.2 Transformer Engine:自动缩放机制到底在解决什么问题
Transformer Engine 是 H100 白皮书里最具场景特色的章节。它解决的实际问题是:FP8 的动态范围比 FP16 窄,如果直接把激活和权重从 FP16 降到 FP8,训练很容易出现溢出或下溢,导致 loss 抖动。
它的做法是,在训练过程中对每一层 tensor 的数值范围做统计,然后自动计算一个缩放因子,把 tensor 缩放到 FP8 能表示的区间里。这个缩放因子的计算和同步由硬件加速完成,也就是说它在 Transformer 这类层结构固定的模型上,能把 FP8 的可用性从“需要手工精心调”变成“硬件自动处理”。
读这一章时,建议你把注意力放在两个地方:一是缩放因子的更新频率,是每个 iteration 更新还是每 N 步更新;二是这个机制只适用于哪些层。白皮书会说明它面向的是 Linear、MatMul 这类可以归约为矩阵乘的算子,而不是所有层都适用。这影响你实际训练时哪些层可以用 FP8,哪些还得留在 FP16。
3.3 从白皮书的数字推算矩阵乘理论峰值:一段可复现的代码
读白皮书不能只读不算。下面这端代码是我每次拿到新卡的规格表都会跑一遍的例行公事,用来从 SM 数量、时钟频率和每周期操作数推算理论峰值。参数解释已经写进注释,SM 数量和时钟请以你手里 PDF 的表格为准,下面填的是常见的参考值。
def peak_tflops(sm_count, clock_mhz, ops_per_cycle_per_sm): # sm_count: 白皮书规格表中给出的 SM 总数 # clock_mhz: GPU boost 时钟,通常在白皮书 Clock 或 Power 章节 # ops_per_cycle_per_sm: 每个 SM 每周期能执行的浮点操作数 # 对 H100 的 FP16 dense 模式,常见参考值约为 2048 return sm_count * clock_mhz * 1e6 * ops_per_cycle_per_sm / 1e12 h100 = { "sm": 132, # 以你手上 PDF 的规格表为准 "clock": 1980, # 参考值,实际以白皮书时钟章节为准,单位 MHz "fp16_dense_ops": 2048, "fp8_dense_ops": 4096, } for mode, ops in [("fp16 dense", h100["fp16_dense_ops"]), ("fp8 dense", h100["fp8_dense_ops"])]: result = peak_tflops(h100["sm"], h100["clock"], ops) print(f"H100 {mode} peak ~ {result:.0f} TFLOPS")这段代码的逻辑不复杂:把 SM 数乘以时钟频率得到每秒总的时钟周期数,再乘以每个周期每个 SM 能做的浮点操作数,最后除以 1e12 换算成 TFLOPS。三个量里最容易搞错的是 ops_per_cycle_per_sm,它不是一个固定值,而是取决于数据类型和你用的是 dense 还是 sparse。白皮书的 Tensor Core 章节会在文字或注释里给出这些操作数,抄下来填到代码里即可。
拿算出来的峰值和你在实际 GEMM 里测到的 TFLOPS 对比,如果差距超过 30%,问题大概率不在算力,而在访存或者 kernel launch 开销。这个脚本的价值就是给你一个“理论上限”,所有优化工作都是在逼近这个上限。
3.4 阅读建议:算力章节要配合指令集文档一起看
白皮书对 Tensor Core 的说明停留在架构层,不会手把手教你写wgmma指令。如果你想真的动手利用这些特性,我建议把白皮书读到的概念(异步、TMA、稀疏模式)作为搜索关键词,去查对应的 PTX ISA 文档。白皮书告诉你有什么,指令集文档告诉你具体怎么写。
这中间有个常见的坑:有人读了白皮书里 Tensor Core 的峰值数字,以为随便写个普通 GEMM 就能达到,结果一测只有峰值的四成。原因多半是 kernel 里还在走老式的 shared memory 手动搬运,没用上 TMA 和异步指令。白皮书不会替你解决代码问题,它只负责给你地图。
4. 内存与互联:HBM3、NVLink 与 PCIe 的带宽账
4.1 显存带宽才是大多数训练任务的真实瓶颈
算力章节看完了会觉得很兴奋,但落地训练任务时你会发现,很多场景根本跑不到算力峰值,因为数据从显存搬到 SM 的速度跟不上计算速度。这就是白皮书内存章节要解决的核心问题:HBM3 的带宽到底有多大,L2 缓存能截住多少复用流量,TMA 如何帮助压缩搬运开销。
H100 使用 HBM3 显存,带宽相比 A100 的 HBM2e 提升明显。白皮书会在 Memory 章节给出精确的带宽数值,你需要记下来的不是那个整数,而是带宽和算力的比值,也就是所谓的算术强度分界线。以 FP16 稠密峰值和 HBM 带宽做除法,你会得到一个算术强度阈值:如果某个算子的算术强度高于它,就是计算受限;低于它,就是访存受限。
这个分界线是后面做 roofline 分析的基础。白皮书不会直接给你画这条线,但会给出算力和带宽这两个原始数字,画线是你自己的事。实际操作中,训练 Transformer 模型时,很多层(比如 LayerNorm、Dropout、部分 Attention 计算)是明显的访存受限,这也是为什么白皮书花大量篇幅讲 TMA 和异步操作——它们就是在帮你把访存受限部分的开销藏起来。
4.2 L2 缓存与 TMA:白皮书里容易被低估的两页
L2 缓存在 H100 上的容量和带宽变化值得单独拎出来说。白皮书在缓存章节通常会给出 L2 的容量和分片方式,你可以结合 GPC 拓扑去理解哪些 SM 共享哪一块 L2。实际调优时,如果两个 kernel 之间数据可以留在 L2 里,就能省掉一次 HBM 往返,这在访存受限场景里效果明显。
TMA(Tensor Memory Accelerator)是 H100 新增的硬件单元,白皮书对它的描述通常不算长,但实际影响很大。它允许你从全局内存直接发起批量数据搬运到 shared memory,整个过程不需要每个线程单独执行 load 指令,也不需要寄存器做中转。这相当于把“搬运”这件事从计算流水线里卸载出去了。
我自己的经验是,读白皮书时把 TMA 的功能描述读上三遍都不为过。很多 kernel 性能翻车,翻就翻在还在用老办法:每个线程算好地址,发一条 load,等数据回来,再算下一条。TMA 模式下,你可以把整个分块的数据搬运一次性描述清楚,硬件自己完成地址计算和传输。
4.3 NVLink 与 PCIe:多卡通信的选型判断
H100 的 NVLink 第四代把单卡双向带宽提升到一个很高的水平,白皮书会给出具体数字和拓扑示意图。这套互联的带宽决定了多卡训练时,梯度同步和数据并行的效率天花板。SXM 版本和 PCIe 版本的 NVLink 配置不一样,白皮书通常会分两个版本描述,读的时候注意别混淆。
我的选型判断习惯是这样的:如果是搞 8 卡甚至更大规模的训练集群,NVLink 带宽决定的是 all-reduce 的耗时占比;如果是做推理部署,单卡或双卡场景更多,PCIe Gen5 和 NVLink 的选择逻辑又不一样。白皮书的互联章节给出的带宽数字,配合你的模型参数量和 batch size,可以直接估算通信耗时占比。
这里要提醒一句:白皮书描述的是硬件的理论带宽,实际通信还受 driver、集合通信库实现、拓扑结构影响。所以白皮书里的 900GB/s 级别数字,落到实际 all-reduce 可能只有六七成。但这个数字仍然是估算通信占比时最好的起点。
4.4 一张建议抄下来的参数表
读完整份 PDF 后,我建议你自建一张一页纸的参数速查表,从白皮书各章捞关键数字填进去:
| 参数 | 从哪里读 | 用途 |
|---|---|---|
| SM 数量、每 SM 调度器数 | 芯片总览 / SM 章节 | occupancy 与并行度估算 |
| 每 SM shared memory 上限 | SM 章节 | kernel 分块策略 |
| L2 容量与带宽 | 内存章节 | 数据复用判断 |
| HBM3 总带宽 | 内存章节 | roofline 访存上界 |
| Tensor Core 各精度峰值 | Tensor Core 章节 | 算力上界 |
| NVLink 双向带宽 | 互联章节 | 多卡通信占比 |
| TMA 支持的操作类型 | SM 章节 | kernel 是否可改造 |
这张表做完,你对这份白皮书的掌握就已经超越了大多数只看过摘要的人。后面的性能调优就不再是盲人摸象,而是对着上界找差距。
5. 读这份白皮书最常见的 5 个误区与排查思路
5.1 把理论峰值当成实际可达性能,一测就怀疑机器有毛病
现象是有人读完白皮书,记住了一个很高的 TFLOPS 数字,然后跑一个简单 GEMM,发现只有 60%,第一反应是机器坏了或者驱动没装好。
原因是白皮书给的是理论峰值,达到它需要满足若干前提:数据已经躺在寄存器或 shared memory 里、指令流水线完全打满、没有访存等待、kernel launch 开销被掩盖。普通写法很难同时满足这些条件。
解决思路是把理论值当作天花板而非预期值。先跑一个官方提供的矩阵乘 benchmark(如果有条件),确认机器本身健康,再逐步替换成自己的 kernel,看差距是在访存、调度还是算法层面。如果 benchmark 能到峰值的八成以上,机器没问题,是你代码的问题。
5.2 读了 TMA 章节,但代码还在用老式手工搬运
现象是代码能跑,性能却和 A100 上没啥区别,升级 H100 的收益没有体现。
原因是 kernel 还停留在手动计算地址、逐线程 load 的老模式。H100 的算力提升有一部分要依赖 TMA 和异步指令才能发挥出来,光靠编译器自动优化是抓不住这些硬件特性的。
解决方法是把白皮书里 TMA 的功能点对应到具体的 PTX 指令,逐步改造 kernel 的数据搬运路径。先在单个 kernel 里尝试用 TMA 替代手工搬运,对比 profiler 里 stall 时间的变化。如果落地成本高,可以先只改访存受限的那个 kernel,收益通常最明显。
5.3 只记 SM 数量,忽略寄存器文件和调度器细节
现象是有人对比 A100 和 H100 时说“SM 变多了,所以更强”,但在实际 kernel 里 occupancy 反而上不去。
原因是 SM 数量只是影响并行度的一个维度,每 SM 的寄存器总量、shared memory 容量、调度器数量共同决定了你能同时驻留多少线程块。如果你的 kernel 每个线程用 128 个寄存器,即使 SM 数量翻倍,occupancy 依然可能被寄存器文件卡死。
解决方法是回到白皮书的 SM 章节,把每 SM 的寄存器文件和 shared memory 上限抄下来,用 occupancy calculator(或者自己写个简单除法)算一下不同 block 配置下的驻留块数。很多调优问题在纸面计算这一步就能暴露。
5.4 给 FP8 开了绿灯,训练 loss 却开始抖动
现象是看到白皮书里 Transformer Engine 对 FP8 的支持描述,果断把训练改成 FP8,结果 loss 曲线不稳定,甚至直接发散。
原因是 Transformer Engine 的自动缩放机制只覆盖它支持的层和路径,你自己手工写的算子、或者某些非标准层,并没有缩放保护。白皮书描述的是硬件能力,不等于所有代码都能自动受益。
解决方法是把 FP8 用在标准的 Linear 和 MatMul 路径上,对 LayerNorm、激活函数、自定义算子保持 FP16。同时关注白皮书里对缩放因子更新频率的描述,如果训练中 loss 抖动,优先排查是不是缩放因子的统计窗口设置不合理。
5.5 只看 zhCN 翻译版,遇到数字对不上时不知道去哪核对
现象是读中文版白皮书时,发现某个表格里的数字和网上别人贴的不一样,开始怀疑自己下错了文件。
原因是翻译版在排版和术语统一上可能需要更新,或者你读的章节和英文原版的修订版本不一致。
解决方法是把中文版当作快速理解的入口,在涉及关键参数的表格页,找到对应英文原版章节号做一个交叉核对。白皮书通常会在章节编号上保持一致,中文版里也会标注原章节号。遇到数字疑问时,以英文原版的修订版为准,别在翻译版上死磕。
6. 落地技巧:拿白皮书参数做一次快速 roofline 估算
有了前面那张参数速查表,你就能在写代码之前先算清楚一个 kernel 到底是算力受限还是访存受限。这个习惯帮我避免了很多白费功夫的优化,因为优化方向如果搞反了,再怎么调调度器都是做无用功。
Roofline 的核心思想很简单:把硬件建模成算力上界和带宽上界两条线,任何一个算子都跑不出这两条线围成的区域。把算子的算术强度(单位字节数据上做的浮点运算数)算出来,和两条线的交点作比较,就能判断瓶颈在哪。下面这段代码可以少手写一个脚本:
def roofline(peak_tflops, peak_gb_per_s, arithmetic_intensity): # arithmetic_intensity: 算子的算术强度, 单位 FLOPs/Byte # peak_tflops: 白皮书 Tensor Core 章节读到的算力上界 # peak_gb_per_s: 白皮书内存章节读到的 HBM 带宽上界 # 如果算术强度高于算力/带宽的比值, 是算力受限; 否则是访存受限 ridge = peak_tflops * 1000.0 / peak_gb_per_s if arithmetic_intensity > ridge: return peak_tflops, "compute-bound" return peak_gb_per_s * arithmetic_intensity / 1000.0, "memory-bound" # 以 FP16 dense 和 HBM3 带宽的常见参考值为例, 具体值以 PDF 表格为准 peak_tflops = 989.0 peak_gb_per_s = 3350.0 # 约 3.3TB/s, 换成分数后 roofline 会自动处理 intensity = 200.0 # 某个 GEMM 的算术强度, 单位 FLOPs/Byte perf, bound = roofline(peak_tflops, peak_gb_per_s, intensity) print(f"预测性能 {perf:.0f} TFLOPS, 瓶颈类型 {bound}")使用这段代码时注意单位换算:我把算力用 TFLOPS、带宽用 GB/s 传入,函数内部先算 ridge point 再做比较。如果算出来的结果和实际 profiling 数据差很多,先确认你填的算术强度没问题,再看是不是 L2 复用让有效带宽高于 HBM 带宽。Roofline 给的是第一层近似,用于快速决策够用。
我自己的习惯是每接触一个新 GPU 型号,就先跑一次上面这段估算,把常见的 GEMM、Attention、LayerNorm 各算一遍,贴在工位旁边。这样后续做优化时,每一处改动都能立刻判断有没有接近理论上界。这套方法看起来很朴素,但它是我见过的性价比最高的性能预估手段。希望这些读白皮书的思路能帮你少走弯路,也希望你手里的 H100 能真正跑出白皮书里那些数字该有的气势。
本文还有配套的精品资源,点击获取