第三章:计算核心架构——SIMT与SIMD、脉动阵列、数据流架构
各位同学,今天我们来聊聊芯片里最核心的“算力引擎”——计算核心架构。说白了,就是芯片到底怎么把数学运算又快又好地干完。
我这些年调过不少模型,也踩过不少坑。一个很深的体会是:不理解计算核心的架构,你写的算子优化代码就是瞎蒙。你想想看,连硬件怎么干活都不知道,怎么可能写出高性能的代码?
这一章,我们重点看三种主流架构:SIMT与SIMD、脉动阵列(Systolic Array)、数据流架构(Dataflow)。它们各有各的脾气,也各有各的用武之地。
3.1 SIMT 与 SIMD:并行计算的“老大哥”与“新贵”
先说说SIMD。Single Instruction Multiple Data,单指令多数据流。这玩意儿其实很老了,x86的MMX、SSE、AVX,ARM的NEON,都是它。
它的核心思想很简单:一条指令,同时操作一堆数据。
比如你要给一个数组里每个数都加1。用普通CPU,你得一条条加。用SIMD,一条指令下去,8个、16个、甚至32个数同时加完。效率直接翻倍。
我在项目中遇到过一个问题:一个图像预处理算子,用纯C++写要跑3毫秒。后来改成NEON intrinsics,直接压到0.4毫秒。嗯,这就是SIMD的魅力。
关键点:SIMD要求数据在内存里是连续排列的,而且每个元素的大小必须一致。否则,你就要做“数据打包”和“解包”,那效率反而会下降。
再说SIMT。Single Instruction Multiple Threads,单指令多线程。这是GPU的看家本领。
你可能会问:SIMT和SIMD有啥区别?
我打个比方:
- SIMD:一个老师(指令)对着一群学生(数据)喊“全体起立”,所有学生必须同时起立。谁慢了都不行。
- SIMT:一个老师(指令)对着一群小组长(线程)喊“让你们组的人起立”,每个小组长可以灵活安排自己组里的人。有的组可能有人请假,那就不管他。
说白了,SIMT比SIMD更灵活。它允许每个线程有自己的寄存器、自己的执行路径(虽然效率会打折)。这就是为什么GPU能处理那些“分支多、数据不规则”的任务。
我的经验:在GPU上写算子时,尽量让同一个warp(32个线程)里的线程走同一个分支。如果分支太多,性能会断崖式下跌。我曾经因为一个if-else语句,让一个算子的吞吐量掉了40%。
3.2 脉动阵列(Systolic Array):矩阵乘法的“流水线工厂”
接下来是脉动阵列。这玩意儿在AI芯片里太重要了。Google的TPU、华为的昇腾,核心都是它。
脉动阵列长什么样?想象一个二维的网格,每个格子里是一个乘累加单元(MAC)。数据像血液一样,在网格里“脉动”流动。
我画个图帮你理解:
你看这个图:
- 红色箭头:激活值从左往右流。每个MAC单元拿到一个激活值。
- 绿色箭头:权重从上往下流。每个MAC单元拿到一个权重。
- 每个MAC:做一次乘累加,然后把结果往右或往下传。
这样做的好处是什么?数据复用率极高。同一个权重可以被多个激活值复用,同一个激活值也可以被多个权重复用。访存次数大大减少。
核心优势:脉动阵列特别适合矩阵乘法。对于两个NxN的矩阵,传统方法需要O(N³)次访存,脉动阵列只需要O(N²)次。在大规模矩阵运算时,这个优势是决定性的。
我记得有一次,我们在一个FPGA上实现一个卷积层。用普通的乘累加阵列,功耗飙到15W。后来改成脉动阵列,同样的计算量,功耗降到6W。这就是架构的力量。
3.3 数据流架构(Dataflow):让数据“自己找路”
最后说说数据流架构。这玩意儿和前面两种思路完全不同。
SIMT和SIMD是“指令驱动”的——指令告诉硬件做什么。脉动阵列是“结构驱动”的——硬件结构决定了数据怎么流动。
而数据流架构是“数据驱动”的——数据准备好了,计算就自动触发。
你想想看,这像什么?像一条流水线。上游的零件到了,下游的工人就开始干活。不用等什么指令,也不用管什么顺序。
数据流架构有几个特点:
- 无全局控制:没有中央控制器来调度指令。每个计算单元自己决定什么时候干活。
- 高并行度:只要数据依赖关系允许,所有能算的单元同时算。
- 低功耗:没有指令取指、译码的开销,也没有乱序执行的复杂逻辑。
我的建议:如果你的计算图是“稀疏”的——比如很多条件分支、动态形状——数据流架构往往比脉动阵列更合适。因为脉动阵列要求数据规整,而数据流架构不怕不规则。
举个例子。你在做图神经网络(GNN)的推理。每个节点的邻居数量不一样,计算图是动态的。用脉动阵列,你得做padding,浪费算力。用数据流架构,每个节点独立计算,效率反而更高。
3.4 三种架构的对比与选型
好了,三种架构都讲完了。我们来个总结对比:
| 特性 | SIMD/SIMT | 脉动阵列 | 数据流架构 |
|---|---|---|---|
| 控制方式 | 指令驱动 | 结构驱动 | 数据驱动 |
| 数据复用 | 低(需手动管理) | 高(硬件自动复用) | 中(取决于数据流图) |
| 灵活性 | 高(可编程性强) | 低(适合规整运算) | 中(适合动态图) |
| 典型场景 | 通用计算、图像处理 | 矩阵乘法、卷积 | 图神经网络、稀疏计算 |
| 功耗效率 | 中 | 高 | 高 |
| 代表芯片 | GPU、CPU | TPU、昇腾 | Wave Computing、SambaNova |
避坑指南:我曾经在一个项目里,试图用脉动阵列去跑一个稀疏矩阵乘法。结果呢?大部分MAC单元都在空转,利用率不到20%。后来换成数据流架构,利用率直接拉到70%以上。所以,选架构一定要看你的计算模式。别拿锤子看什么都像钉子。
最后说一句心里话:没有完美的架构,只有合适的架构。你在做芯片设计或者算子优化时,一定要先搞清楚你的 workload 是什么样子的。是规整的矩阵乘法?还是稀疏的动态图?是批量处理?还是流式处理?
搞清楚了这些,你才能选对架构,写出真正高效的代码。
嗯,这一章就到这里。下一章我们聊聊存储层次——那个让无数工程师掉头发的“内存墙”。
想要更多资料,联系可可