ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LPU芯片架构解析:确定性执行与片上SRAM加速大模型推理

2026/9/18 19:27:35 拓冰建站 浏览量
LPU芯片架构解析:确定性执行与片上SRAM加速大模型推理 1. LPU 芯片到底解决什么问题先把概念钉死第一次在群里看到 LPU 这个词不少人的第一反应是又来个新缩写第二反应是跟 NPU 有什么区别。这两个反应都很真实因为 LPU 的芯片架构确实不是凭空冒出来的品类它是被一类非常具体的负载逼出来的设计。LPU 全称 Language Processing Unit直译是语言处理单元它服务的核心场景就是大语言模型的推理——注意是推理不是训练。这个限定词很关键因为 LPU 芯片架构里几乎每一个看起来反常识的设计决策都能从只做推理这四个字里推导出来。我先说它能干什么。在大模型推理里用户能感知到的指标其实就两个第一个字多久出来首 token 延迟以及后面的字吐得多快生成吞吐通常按 tokens/s 计。传统 GPU 在这两件事上都不差但有一个绕不过去的结构性开销GPU 是通用并行处理器它的设计目标是什么活都能干所以它必须带一套复杂的硬件调度器用来在运行时动态决定哪个 warp、哪个 block 该上哪个 SM。这套机制在训练时是优点——负载再乱也能压满算力但在推理时尤其是 batch size 很小、访存模式高度规律的推理场景里调度本身就成了纯开销。LPU 芯片架构的思路正好相反既然推理的计算图是固定的、访存模式是可预测的那为什么不在编译期就把所有事情排好让硬件在运行期只管照单执行这就是确定性执行deterministic execution的由来也是理解 LPU 的第一把钥匙。它适合谁来了解三类人一是做推理服务部署、被延迟和成本两头夹的工程同学二是做芯片/体系结构方向、想搞清楚专用推理架构这条路能走多远的人三是模型侧的研究者因为 LPU 对模型结构的敏感性会反过来影响你怎么定义算子。1.1 LPU 这个名字容易让人误解的地方Language Processing Unit这个名字天然会让人以为它只能跑文本。实际上它跑的是张量运算图像、语音、多模态的模型一样能跑只是它的架构调优重心放在了自回归解码这条路径上——因为这条路径对内存带宽和延迟最敏感。另一个误解是把它等同于更快的 NPU。NPU 这个筐太大了手机上的 NPU、车机的 NPU、数据中心的推理加速卡都叫 NPU它们的共同点只是不是 CPU 也不是 GPU但内部架构千差万别。要说差异LPU 这类架构最鲜明的标签是两点一是片上存储优先二是编译期确定调度。这两点结合在一起才构成一个完整的架构选择单独拿一条出来说都不成立。提示判断一款推理芯片是不是这一类架构最简单的办法是看它需不需要一张编译器友好的模型图。如果它强烈依赖特定编译器做静态切分和内存规划且对动态 shape 支持有限那它大概率走的是确定性路线。1.2 与 GPU、TPU、NPU 的分界线在哪里我把几条线拉平了对比这样更容易看清定位差异维度GPU通用加速TPU 类脉动阵列LPU 类确定性推理调度方式运行时硬件调度运行时编译期混合编译期静态编排主存HBM几百 GB 级HBM片上 SRAM 为主访存特征不可预测靠缓存兜部分可预测全可预测动态 shape支持好一般支持有限需重编译强项训练、混合负载大矩阵乘低延迟单路解码这张表不用背理解逻辑就行GPU 用灵活性换通用性TPU 类用脉动阵列换矩阵乘效率LPU 类用确定性换极低的调度抖动。三者不是谁替代谁是在不同的约束条件下各自找最优解。2. 确定性执行LPU 架构的第一性原理要讲清楚确定性执行得先承认一件事GPU 上的推理之所以慢很多时候不是算力不够而是算力没被喂饱。我做过一个粗略的压测在一张主流加速卡上跑一个 7B 模型的 batch1 解码SM 利用率长期在个位数到二十几个百分点之间徘徊。原因很简单解码阶段每个 token 的计算量非常小就是一次矩阵向量乘但需要把整个权重矩阵从显存里搬一遍计算单元大部分时间在等数据。这就是典型的访存受限memory-bound。在这种负载下硬件调度器的存在反而添乱。它要看依赖、要仲裁、要切换上下文每个动作都是延迟。而 LPU 芯片架构的处理方式是把这些决策全部前移到编译期。谁来执行、什么时候执行、数据从哪个 bank 读、结果写到哪个地址编译出来的指令流里全写死了硬件运行期只需要一个非常轻的执行单元去按序跑。少了一层动态决策就少了一层抖动延迟的方差也就压下来了。2.1 传统 GPU 的调度开销究竟花在哪拆开看动态调度的开销主要在三块。第一块是指令发射与仲裁SM 里的 warp scheduler 每个周期都要从若干 warp 里挑一个能发射的这个挑选本身要消耗周期和面积。第二块是访存一致性维护因为 L1/L2/HBM 存在多级缓存缓存命中与否不可预测硬件必须处理各种 miss 和回填。第三块是同步与栅栏kernel 之间、block 之间的同步点越多流水线停顿越频繁。这三块开销在训练时是必要的因为训练的计算图虽然也有结构但梯度累积、通信重叠、动态 loss scaling 这些都让负载变得不那么规整。可推理不同——推理的计算图基本是静态的尤其是 decode 阶段每步的计算模式完全一样只是输入 token 换了。这种高度重复且可预测的负载恰恰是静态编排的最佳土壤。2.2 静态编排是怎么把调度器删掉的静态编排的本质是把原本属于硬件运行期的决策转移给编译器的图调度阶段。我用一段伪代码来说明这个思路重点看它把什么写死了# 编译期为一个 decode step 生成静态指令序列 for each layer in model.layers: # 权重地址在编译期就确定运行时不变 schedule(MXM_LOAD, addrweight_addr[layer], bankbank_id[layer]) schedule(MXM_MATMUL, srcactivation_buf, dstpartial_buf) schedule(VXM_ADD, srcpartial_buf, dstaccum_buf) schedule(VXM_GELU, srcaccum_buf, dstactivation_buf) # 通信动作同样被排进时间槽和计算严格对齐 schedule(C2C_SEND, srcactivation_buf, linklink_id[layer], slott1)这段东西看着朴素但信息量很大每一层的权重地址、用哪个 SRAM bank、通信动作放在哪个时间槽全都是编译期常量。硬件运行时不需要做任何地址计算和仲裁直接取指令执行就行。这就是为什么这类架构的指令发射单元可以做得极其简单——它不需要聪明它只需要准。注意静态编排的代价是灵活性。一旦运行时的形状和编译期假定的不一致比如 batch size 变了、序列长度超出预留 buffer就得重新编译或者走退化路径。这是这类架构最容易被低估的限制。3. 不用 HBM 的底气片上 SRAM 存储层级设计存储层级是 LPU 芯片架构里最容易被拿来讨论的部分。公开资料里给出的量级是单芯片 200MB 级别的片上 SRAM片上带宽达到几十 TB/s 量级。对比之下一张主流训练卡上的 HBM 也就几 TB/s 的带宽容量却有几干到上百 GB。这个反差很有意思容量小了三个数量级带宽却高了一个数量级。为什么会这样设计答案还是回到推理负载上。解码阶段的访存特征是这样的计算量小但要反复读权重。假设模型权重是 W 字节batch1 时生成一个 token 需要把 W 全读一遍。如果 W 放在 HBM 上耗时就是 W/带宽_HBM如果放在片上 SRAM耗时就是 W/带宽_SRAM。带宽差一个数量级单 token 延迟就差一个数量级。这就是把权重要往片上放的直接动机。3.1 带宽账几十 TB/s 是怎么来的我按公开量级做一次估算看看这个带宽是否说得通。假设单芯片有 200MB 级 SRAM分布在几百个 bank 上每个 bank 按位宽 512 bit64 字节设计。如果时钟在 1GHz 左右单个 bank 的吞吐是 64 字节 × 1e9 64 GB/s。要凑到几十 TB/sbank 数量要在几百到上千这个量级——这跟几百个计算 tile、每个 tile 带独立 SRAM的公开描述是对得上的。用这个估算反推一个 token 的片上读取时间假设某个模型分片到单芯片的权重是 200MB片上带宽按 80TB/s 算读取耗时约 200e6 / 80e12 2.5 微秒。也就是说只要数据都在片上读一遍权重的代价是微秒级的。而同样的 200MB 如果放在带宽 3TB/s 的 HBM 上读一遍要 66 微秒差了二十多倍。这个差距在单 token 延迟上是致命的因为你每生成一个 token 都要付一次这个成本。3.2 容量装不下大模型那怎么办数学很残酷一个 70B 参数的模型哪怕用 8 bit 量化权重也要 70GB。单芯片 200MB装不下差 350 倍。所以这类架构必须靠多芯片权重切分来解决。公开演示中跑 70B 模型用的是几百张卡的量级这个数量级和上面的估算基本吻合。切分带来两个后果必须提前想清楚。第一是通信变成了关键路径。每个 token 的每一层都要在芯片间交换激活值或者部分和通信延迟直接叠加到 token 延迟上。第二是成本的量级变化。几百张卡的硬件成本、功耗、机架空间跟一张卡不是一个量级。所以看待这类方案时不能只看 tokens/s 这一个数字要算每百万 token 的综合成本这里面包含了卡数、功耗、以及运维复杂度。提示估算任何片上存储优先架构的可行性先做两步算权重总量除以单芯片容量得到最少卡数再算这几十上百张卡的通信拓扑能不能把延迟压住。这两步过不了后面都是空谈。4. 计算单元与片上数据通路拆解讲完存储再看计算。公开资料里这类芯片把计算资源分成两类单元一类负责矩阵运算一类负责向量和逐元素运算。这个划分不是随意定的它对应的是 Transformer 里的两类操作。矩阵乘QKV 投影、FFN 的两层线性交给矩阵单元这是计算量大头LayerNorm、激活函数、残差相加、softmax 的一部分交给向量单元这些操作计算量小但频次高、依赖链长。为什么要把它们分开而不是用一个通用单元全包还是那个逻辑推理的计算图是静态的那就可以针对每类操作的访存特征定制单元。矩阵单元追求的是高吞吐、宽数据通路向量单元追求的是低延迟、灵活的分支处理能力。分开设计之后两类操作可以流水线并行矩阵单元在算第 N 层的时候向量单元已经在处理第 N-1 层的归一化了。4.1 矩阵单元与向量单元的分工逻辑拆得更细一点。矩阵单元通常采用脉动阵列或者张量核的结构数据从一侧流入、从另一侧流出中间不落寄存器这样能最大化数据复用。一次矩阵乘里每个权重被复用多次复用的次数等于 batch 相关的维度。注意这里有个陷阱batch1 时权重的复用次数极低脉动阵列的效率其实发挥不出来。这就是为什么这类架构在宣传时更强调单路低延迟而不是大 batch 的吞吐。向量单元的活更杂。以一次完整的 Transformer block 为例它要处理的操作序列大致是残差相加、LayerNorm、旋转位置编码RoPE的三角函数计算、注意力分数的缩放、softmax 里的指数和归一化、以及 MLP 里的激活函数比如 SwiGLU 里的 SiLU。这些操作有个共同点都是逐元素的没有矩阵间的那种规整复用。让矩阵单元去干这些活属于浪费让向量单元去干正好各得其所。4.2 一个 token 在片上走过的完整路径把路径串起来看一个 token 的解码过程大概是这样走的输入 token 的 embedding 从片外读入或者在片上表里查进入激活 buffer进入第 1 层向量单元做 LayerNorm矩阵单元做 QKV 投影注意力计算QK^T 是矩阵乘softmax 走向量单元再和 V 相乘又回到矩阵单元输出投影、残差相加向量单元接管FFN 的两层线性走矩阵单元中间的激活走向量单元每一层的部分结果通过片间链路广播到下游芯片全部层跑完最后的 logits 做采样得到下一个 token这条路径上每一步的耗时都是确定的因为数据在哪个 bank、走哪条链路、经过几个周期编译期就定好了。我第一次看到这个描述时觉得挺震撼——它把推理这件事从运行时的资源争夺变成了编译期的排班表。5. 片间互联几百张卡怎么拼成一台机器多芯片切分之后互联就成了整个系统的命脉。公开资料里这类架构的片间链路是点对点C2C的芯片按网格或者环形拓扑连起来数据在芯片之间以确定性的方式传递。为什么强调确定性因为如果互联是动态路由的那就又回到 GPU 那套问题上了——拥塞不可预测延迟波动大。这里的核心机制是广播式的层间流水。因为权重是切分到各芯片上的每一层的计算在芯片间是串行的芯片 A 算完第 1 层结果传给芯片 B 算第 2 层以此类推。如果层数和芯片数是 N 对 N 的映射那整个流水线的深度就是 N每生成一个 token 要走完 N 段流水。为了让流水线不停顿互联的带宽和延迟必须和计算严格匹配。5.1 C2C 拓扑与确定性广播链路的量级上公开描述里每条链路的带宽在几十 Gbps 到百 Gbps 之间每颗芯片带若干条链路双向合计在几百 GB/s 的量级。这个数字听起来不算惊人但关键在于延迟可控。点对点直连的好处是跳数固定没有交换机带来的排队抖动。数据从芯片 A 到芯片 B经过的时间是链路延迟 × 跳数是个常数。这套机制对编译器的要求极高。编译器必须知道每一层放在哪颗芯片上、每颗芯片的哪条链路在哪个时间槽可用然后把通信指令和计算指令交叉排进同一条时间线。排得好的时候通信被完全隐藏在计算背后排得不好链路空转、计算单元挨饿。5.2 通信开销的量化与边界我试着算一笔账看看这套体系的天花板在哪。假设一个 70B 模型切成 350 份每份 200MB分布在 350 颗芯片上。每生成一个 token激活值要在芯片间传递 350 次。假设每次传递的激活数据量是 hidden_size × 2 字节对于一个 8192 维的 hidden一次约 16KB。350 次传递加上链路开销如果每跳 1 微秒光通信就是 350 微秒。反过来看计算时间每颗芯片每个 token 要读 200MB 权重按 80TB/s 算是 2.5 微秒。所以在这个极端切分下通信开销远大于计算开销流水线是通信主导的。这解释了一个工程常识切分粒度不是越细越好切得太细通信吃掉所有收益。实际部署里会想办法在一颗芯片上多放几层减少切分段数。切分段数单芯片权重单芯片计算耗时通信跳数通信总耗时估算352GB25 微秒3535 微秒701GB12.5 微秒7070 微秒350200MB2.5 微秒350350 微秒这张表是示意性的估算真实值还受链路带宽和并行度影响但趋势很清楚切分带来的不是线性加速通信成本会吃掉大部分收益。这也是为什么这类架构的优势主要体现在延迟而不是吞吐上。注意评估多芯片推理方案时别只看单卡的算力规格一定要看互联的拓扑和每跳延迟。芯片间通信才是决定实际 tokens/s 的那个变量。6. 编译器才是真正的护城河聊到这儿必须说一个观点这类架构的硬件设计只占一半另一半全在编译器上。道理很简单——硬件把决策权交给了编译期那编译器就得承担起原本硬件的全部调度工作而且要做到接近最优。这不是一个简单任务它本质上是把一个图调度问题、一个内存分配问题、一个通信排程问题三个 NP 难问题揉在一起解。6.1 静态调度编译流程拆解一个典型的流程会经过这么几步。第一步是图解析与算子融合把模型的计算图读进来做一些标准融合比如把 LayerNorm 和后面的线性层合并减少一次数据搬运。第二步是权重的内存布局规划把每个权重块分配到具体的 SRAM bank目标是让后续的读取尽量并行、少冲突。第三步是指令调度把计算指令、访存指令、通信指令排进时间槽避免数据冒险和资源冲突。第四步是代码生成与校验输出硬件能直接执行的指令流。整个过程的关键约束是时间槽的排他性一个 bank 在同一周期只能服务一个读取请求一条链路在同一时间只能传一份数据。所以调度器要做的其实是资源约束下的时间最优排程这跟工厂排产是一个道理——不同的机器、不同的工序怎么排能让总工期最短。# 调度器的核心约束示意伪代码 def schedule(op, resources): for t in range(MAX_CYCLES): if all(r.free_at(t, op.duration) for r in resources[op.type]): for r in resources[op.type]: r.occupy(t, op.duration) op.start_cycle t return True raise ScheduleError(no feasible slot, likely resource conflict)这段伪代码简化了很多但它点出了核心调度器在找一个所有依赖资源都空闲的时间槽。找不到就报错这时候往往要回退去调整切分方案或者内存布局。实际生产环境里这个循环可能要跑几十分钟甚至更久。6.2 图切分与算子映射的取舍图切分是另一个大坑。模型不是随便切在哪儿都行的切的边界最好落在通信量小的地方。Transformer 里通信量最大的地方是注意力和 FFN 的连接处激活维度高通信量小的地方是比如 FFN 内部的第一层和第二层之间。有经验的编译器会把切分点往通信量小的位置挪哪怕两层计算量不太均衡也能靠流水线掩盖掉一部分不均衡。算子映射也一样。不是所有算子都能直接映射到硬件单元上像动态 shape 的 gather、条件分支、稀疏操作这些在静态架构上就很别扭。所以实际部署时很多团队会先做一个算子体检看模型里有哪些算子在目标架构上会被退化执行再决定要不要改模型。6.3 为什么它对模型结构这么敏感这里有个现象值得说说同一个模型改了实现细节比如把 LayerNorm 换成 RMSNorm或者把位置编码从绝对改成旋转编译后的性能可能差出一大截。原因在于编译器对每一种算子组合都有不同的调度模板模板里预设了数据怎么流动、buffer 怎么复用。结构一变模板可能就失效了需要重新生成调度甚至会出现某些结构根本无法高效映射的情况。这个特性反过来会影响模型设计。如果你打算把模型部署到这类架构上最省事的做法是尽量用标准算子别为了几个点的指标去用冷门结构。我见过有人为了一个小改动导致整块编译时间翻倍最后得不偿失。7. 实测表现与瓶颈分析公开演示里的数字很亮眼单路生成速度能到几百 tokens/s 的量级首 token 延迟压到几百毫秒以内。但理解这些数字时要注意看上下文是 batch1 还是 batch8上下文多长模型多大这些条件变了数字会剧烈变化。7.1 首 token 延迟与吞吐的取舍关系首 token 延迟和吞吐是一对矛盾。首 token 延迟主要受 prefll 阶段影响——要把整个 prompt 过一遍计算量跟 prompt 长度成正比。这一阶段是计算受限的矩阵单元能跑满所以延迟相对可控。而生成阶段的吞吐受访存限制每生成一个 token 都要读一遍权重这个成本是固定的跟你前面算得多快没关系。所以你会看到一个现象这类架构在首 token 延迟上有优势因为编译器把 prefll 的调度排得很紧但在大批量吞吐上不一定比 GPU 强因为 GPU 可以用大 batch 摊薄访存成本。这不是缺陷是设计取向——它瞄准的是交互式场景而不是离线批处理。7.2 长上下文场景下的带宽账上下文一长压力会从权重侧转移到 KV cache 侧。假设上下文 32K层数 80hidden 8192用 FP16 存 KV一个序列的 KV cache 就是 2 × 80 × 32768 × 8192 × 2 字节 ≈ 86GB。这个量级远超片上 SRAM 的容量必须放到片外或者压缩。于是长上下文场景下的瓶颈就变了KV cache 每次生成都要读读的是片外存储带宽一下掉一个数量级。这时候片上 SRAM 的优势被削弱了。缓解手段无非几条KV 量化8 bit 甚至 4 bit、分组查询注意力GQA减少 KV 头数、滑动窗口局部注意力。这几条都是模型侧的设计跟芯片架构是联动的。提示如果你的业务场景上下文很长比如文档问答、代码补全在选推理架构时一定要把 KV cache 的访存量单独算一遍别被权重全片上的宣传口径带偏。8. 踩坑记录与高频问题速查这部分我结合实际踩过的坑整理成问答形式供快速查阅。8.1 模型迁移时最容易卡住的几处第一处是动态 shape。很多模型导出时会带动态轴比如 batch 维或者序列长度维是不定的。这类图迁到静态架构上编译器往往要求你先把 shape 固定下来。解法通常是把可能的 shape 组合枚举出来编译多个版本运行时按需切换——代价是编译时间和内存占用都上去了。第二处是自定义算子。论文里新出的激活函数、特殊的归一化方式、非标准的注意力变体这些在通用框架上随手就能写但在静态编译器里可能没有对应的模板。遇到这种情况要么拆成基础算子组合要么改回标准实现。我的经验是先做一个小规模的算子扫描把整个模型的所有节点类型列出来挨个对照支持列表比事后 debug 省事得多。第三处是数值精度。静态调度的架构因为调度固定很难在中途插入动态的精度调整。如果模型里有对精度敏感的操作比如累加和很大的地方量化到 8 bit 时容易出现精度塌陷。解法是把这些层单独保留高精度代价是访存量上升。8.2 部署高频问题对照表现象可能原因排查方向编译超时图太大、切分粒度过细增大切分粒度减少跨芯片通信节点首 token 延迟异常高prefll 阶段资源冲突检查编译日志里的资源冲突告警生成速度波动大链路拥塞或热降频看链路利用率曲线和芯片温度精度下降明显KV 量化或权重量化过激逐层对比量化前后的输出差异内存报错但容量显示充足内存碎片或对齐问题检查权重的 bank 对齐设置某些输入下结果错乱动态 shape 走了退化路径确认输入 shape 是否在编译覆盖范围内这张表不用记全记住排查思路就行先看编译期告警再看运行时利用率最后才怀疑数值。很多问题在编译日志里其实已经提示了只是被忽略。9. 我在实际使用中体会到的几点跟这类架构打交道一段时间后我最大的感受是它的边界非常清晰。你几乎不会遇到那种时快时慢、说不准为什么的情况——快就是快慢的时候看利用率曲线也能立刻定位到是哪个资源在瓶颈。这种可预测性在工程上价值很大因为它让容量规划变得可做而不是靠经验拍脑袋。另外一点体会是关于成本核算的。这类方案的单位算力成本不一定最低但它的延迟优势在某些场景下能直接换成收入——比如客服对话、实时助手、代码补全这类交互产品用户在意的就是你多快能出第一个字。如果你的场景对延迟不敏感那选它就不划算老老实实用通用方案更省钱。最后一个建议给准备做模型移植的同学先用一个几层的小模型跑通完整流程把编译、部署、压测、精度校验这几步都走一遍别一上来就上大模型。大模型的编译时间动辄几十分钟踩坑成本极高。小模型跑通了大模型的问题基本都能预判到。