4. 硬件架构与INT8计算单元:CPU INT8指令集(AVX-512 VNNI)、GPU Tensor Core INT8、NPU/TPU专用加速器

各位同学,咱们今天聊点硬核的。INT8计算,说白了就是让硬件用更少的力气干更多的活。但不同硬件干活的姿势,那可差太多了。

我这些年调优下来,最大的感触就是:不了解硬件,就别谈优化。你写的代码再漂亮,硬件不买账,一切都是白搭。今天咱们就把CPU、GPU、NPU这三家怎么玩INT8,掰开揉碎了讲清楚。

核心观点:INT8加速的本质,是用更低的精度换取更高的吞吐。但不同硬件架构的“交易方式”完全不同——CPU靠指令集,GPU靠专用核心,NPU/TPU靠全定制设计。

4.1 CPU INT8指令集:AVX-512 VNNI

先说说CPU。很多人觉得CPU做INT8推理太慢,不如GPU。嗯,这话对了一半。如果你还在用老旧的SSE指令集,那确实慢。但如果你有支持AVX-512 VNNI的处理器,情况就完全不同了。

AVX-512 VNNI是Intel在Cascade Lake时代引入的。它最牛的地方在于——一条指令就能完成8个INT8乘加操作。你想想看,以前你得拆成好几条指令,现在一条搞定,吞吐直接翻倍。

我的经验:我在部署一个BERT模型时,从AVX2切换到AVX-512 VNNI,推理延迟直接降了40%。但要注意,AVX-512频率会降,你得在吞吐和单核性能之间找平衡。

来看个实际例子。假设我们要做两个INT8向量的点积:

// 传统方式(AVX2)
__m256i a = _mm256_loadu_si256((__m256i*)ptr_a);
__m256i b = _mm256_loadu_si256((__m256i*)ptr_b);
__m256i prod = _mm256_maddubs_epi16(a, b);  // 先乘再加,但只到16位
// 还得额外累加...

// AVX-512 VNNI方式
__m512i a = _mm512_loadu_si512((__m512i*)ptr_a);
__m512i b = _mm512_loadu_si512((__m512i*)ptr_b);
__m512i sum = _mm512_dpbusd_epi32(zero, a, b);  // 一条指令搞定!

看到了吗?VNNI把乘加和累加合并了。这不仅仅是代码变短,关键是减少了指令发射压力和寄存器压力。

注意:AVX-512 VNNI需要硬件支持。不是所有标着“支持AVX-512”的CPU都支持VNNI。我吃过这个亏——代码写好了,跑在至强金牌上没问题,换到至强银牌上直接非法指令异常。

另外,CPU上做INT8还有个好处:内存带宽利用率高。因为INT8数据量是FP32的1/4,同样的内存带宽能喂给计算单元更多数据。这对带宽敏感型模型(比如推荐系统)特别友好。

4.2 GPU Tensor Core INT8

接下来聊聊GPU。NVIDIA从Volta架构开始引入Tensor Core,专门做混合精度计算。到了Turing,Tensor Core开始原生支持INT8。

Tensor Core的设计思路和CPU完全不同。CPU是通用计算单元,靠指令集扩展来加速。而Tensor Core是专用硬件,它只做一件事——矩阵乘加。

一个Tensor Core每个时钟周期能做一个4×4矩阵乘加。在A100上,每个SM有4个Tensor Core,一共108个SM。你算算,这吞吐量有多恐怖?

GPU架构 Tensor Core版本 INT8 TOPS 关键特性
Turing (T4) 第2代 65 首次支持INT8
Ampere (A100) 第3代 624 支持稀疏化,性能翻倍
Hopper (H100) 第4代 1979 Transformer引擎,FP8/INT8混合

用Tensor Core做INT8推理,我建议你直接用cuBLAS或cuDNN。别自己手写CUDA——除非你真的很闲。这些库已经针对Tensor Core做了深度优化,包括数据布局、warp调度、共享内存管理等等。

避坑指南:我曾经手写过一个INT8矩阵乘,自以为优化得很好了。结果一测,只有cuBLAS的60%性能。后来发现是数据对齐问题——Tensor Core要求数据按特定格式排列,我忽略了。

GPU上做INT8还有个关键点:量化校准。你喂给Tensor Core的数据必须是真正的INT8,而不是FP32转过去的。这涉及到calibration数据集的选择、量化参数的计算。我一般用1000张左右的图片做校准,效果比较稳定。

4.3 NPU/TPU专用加速器

最后说说专用加速器。NPU和TPU是真正的“专才”——从设计之初就是为了神经网络推理而生。

Google的TPU v1,2015年就出来了。它有一个巨大的脉动阵列(Systolic Array),128×128的MAC单元。每个周期能做16384个乘加操作。这规模,CPU和GPU看了都得喊大哥。

NPU这边,各家方案五花八门。华为的昇腾、寒武纪的思元、地平线的征程……但核心思路都一样:把计算和数据移动做到极致。

专用加速器有几个共同特点:

  • 大尺寸脉动阵列:矩阵乘是核心操作,用脉动阵列做最合适
  • 片上存储层次:多级SRAM,减少DRAM访问
  • 数据流优化:权重固定、输入流式、输出累加
  • 专用指令集:一条指令完成整个layer的计算

我调过一款NPU,它的INT8算力标称是32TOPS。但实际跑模型时,只能跑到18TOPS。为什么?因为数据搬运成了瓶颈。模型太大,权重放不进片上SRAM,频繁从DDR搬数据,计算单元一直在空等。

我的建议:用NPU/TPU时,一定要关注“计算效率”而不是“峰值算力”。峰值算力是理论值,实际能跑多少,取决于你的模型结构和数据流设计。

TPU还有一个杀手锏——Bfloat16。虽然它不是INT8,但它的动态范围和INT8差不多,而且不需要量化。TPU v2开始支持BF16,很多模型直接跑BF16,精度和FP32几乎一样,速度却快得多。

4.4 三种架构的对比与选择

说了这么多,咱们来总结一下。三种架构各有千秋,选哪个取决于你的场景:

维度 CPU (AVX-512 VNNI) GPU (Tensor Core) NPU/TPU
灵活性 最高 中等 最低
INT8吞吐 中等 高 最高
延迟 低 中等 低
功耗 高 中等 低
开发难度 中等 低(用库) 高
适用场景 小模型、低延迟 大模型、高吞吐 特定模型、量产

我个人习惯是:原型阶段用GPU,部署阶段看场景。如果模型小、延迟要求高,用CPU;如果模型大、吞吐要求高,用GPU;如果量很大、功耗敏感,考虑NPU。

下面这张图展示了三种架构在INT8计算时的核心差异:

INT8计算单元架构对比 CPU (AVX-512 VNNI) 通用计算核心 VNNI指令单元 L1/L2缓存 内存控制器 特点:指令级并行,共享缓存 GPU (Tensor Core) SM (流式多处理器) Tensor Core (4×4) 共享内存 HBM/显存 特点:大规模并行,专用矩阵单元 NPU/TPU 脉动阵列 (128×128) 片上SRAM 数据流控制器 DDR/HBM 特点:全定制,数据流驱动

从这张图能看出来,CPU是“小而精”,每个核心都能独立工作;GPU是“多而专”,大量SM配合Tensor Core;NPU/TPU则是“大而全”,整个芯片为一个目标服务。

好了,这一章的内容就到这里。记住一句话:没有最好的硬件,只有最合适的硬件。下一章咱们聊聊量化方法,看看怎么把FP32模型变成INT8,同时保证精度不掉。

可可精品资料库