小智是一位 AI 工程师,最近被一个线上推荐系统折磨得寝食难安——输入几百个用户 ID,系统却要花上好几毫秒才能吐出结果。他在服务器上放着上百万行的“用户偏好表”(嵌入表),可每次推理真正读到的行往往只有几十个,就像一家藏书百万册的图书馆,读者每次只借三五本书,传统做法却要把整个书架都搬下来翻一遍,大部分时间都浪费在搬运没用的大部头上。直到他遇见了 TPU 上的 SparseCore——一个专门为这种“书极多、借得极少”的场景而生的硬件分拣系统。 SparseCore 是 Google TPU 中负责处理稀疏数据的专用硬件单元。它不像传统矩阵加速器那样要求数据整整齐齐排满表格,而是用一套取书员(访存引擎)、借阅台(嵌入片)、汇总处(汇聚片)和热门书柜(准入缓存)的协同机制,只搬运真正用到的那几行数据,让推荐系统、图神经网络这类“大表小查”的工作负载飞速运转。本文将带你以小智的视角,走进这座智能图书馆的深处。
对 AI 从业者而言,理解 SparseCore 意味着掌握 AI 硬件如何在大模型时代突破显存与带宽瓶颈——这是设计高性能推荐、搜索和广告系统的底层核心能力。
可视化演示
演示TPU SparseCore的gather/scatter架构、嵌入表稀疏查找优化及稀疏vs稠密计算性能对比,交互切换模式与稀疏度。
本节配有交互动效(进入视口后自动加载,约 3KB)。
SparseCore架构与数据流 Gather单元收集稀疏嵌入向量 Scatter单元回写梯度更新 Speedup≈5-7x @5%面积代价 SparseCore将稀疏内存取数从MXU主路径解耦
稀疏计算困境
小智走进的第一间库房,就是存放“用户偏好表”的地方。这座库房有上百万个格子,每个格子里放着一份向量档案——这就是嵌入表(Embedding Table),记录着每个用户、商品、视频的特征。理论上,AI 模型在推理时要查这张表,把用户和物品变成可以相乘计算的向量。
问题在于访问模式。一次推荐请求,往往只需要查几十到几百个 ID 的档案,就像读者进馆只借三五本书。可是传统的矩阵计算单元(如 TPU 上的 MXU、GPU 上的 Tensor Core)是为“稠密矩阵乘法”设计的——它们要求把整个表的所有行都读出来,排成规则的大方块,才肯开始算。于是每次推理,硬件都要把上百万行从 HBM 显存浩浩荡荡搬一遍,绝大多数行根本没用到就被搬进计算单元,再原封不动搬回去。
这场“满表搬家”造成的访存浪费,在每次只查少量 ID 的推荐、搜索场景中触目惊心。真正完成有用的计算只占搬运量极小比例,访存带宽成了整个系统的咽喉。以一次查询 1000 个 ID、表共 1000 万行为例:
小智明白了:这座百万格子的库房,每次只为借几本书就把所有书搬一遍,自然慢得离谱。要提速,必须换一种思路——不搬整个书架,让硬件学会“按索引取书”。这正是 SparseCore 登场的理由。
- $N$(总行数)嵌入表的总规模,如上百万用户 ID,表示表中的总行数。
- $M$(实际访问行数)一次推理真正用到的行数,往往只有数百到数千。
- $s$(稀疏度)没被用到的行占全部行的比例,$s$ 越接近 1,说明浪费越严重。
SparseCore架构
图书馆请来了一位经验丰富的分拣主管,他把整套流程拆成了三个角色来分工。取书员(访存引擎)拿着读者递来的借书单(ID 列表),飞奔到库房里只把对得上号的书取出来;借阅台(嵌入片)负责把书中的关键段落(向量)做计算处理;最后,汇总处(汇聚片)把多路取回的资料合并成完整的答复。
在 SparseCore 中,这三个角色是硬件电路层面真实存在的模块。访存引擎(Access Engine)的核心任务是高效索引——它根据输入的稀疏 ID,直接计算出各行在存储中的物理地址并发出访问请求,不再遍历全表。嵌入片(Embedding Tile)是计算主力的所在地,它把从存储器取回的向量行与权重做乘加运算,类似于借阅台在有限资料内完成深度分析。汇聚片则把从多个嵌入片返回的碎片化结果按用户 ID 聚合起来,还原成完整的输出张量。
三个角色按硬件流水线(Pipeline)方式协同工作。访存引擎去取“下一批”数据时,嵌入片同时在算“这一批”,汇聚片则在整理“上一批”的结果——像图书馆的取书、翻书、登记三条流水线并行运转,谁也不等谁。流水线让访存延迟被计算时间掩盖。
分拣主管的这套流水线让小智大受启发:只要让取书员、借阅台、登记处并行干活,库房再大也不怕。但小智还注意到一件事:取书员能在百万格子里瞬间定位,光靠跑得快还不够——仓库里的书必须按照某种巧妙的方式摆放。这就引出了压缩存储格式。
- $T_{访存}$访存引擎按索引取回数据的时间,流水线中通常最慢的一环。
- $T_{计算}$嵌入片执行乘加运算的时间,与向量维度成正比。
- $T_{汇聚}$汇聚片合并多路结果的时间,与批次内 ID 数量成正比。
压缩存储格式
为了取书员能飞速定位,分拣主管重整了库房:不再把百万本书整整齐齐占满整个楼层,而是把所有书压缩进一排紧凑的书架上,并单独做一本“索引册”,记录每本书在书架上的实际位置。这本索引册,对应到 SparseCore 中就是 CSR(压缩稀疏行)格式的核心思想。
CSR 格式用两个数组描述一张稀疏表:索引数组(Indices)按顺序记录每本“有内容的书”的原始 ID;数值数组(Values)紧挨着存放与索引一一对应的向量。当读者报出一个 ID,取书员只需要在索引册里用二分查找或哈希定位到该 ID 的位置,再顺着位置在同一“书架层”取出相邻数据即可。由于稀疏行不再按原始 ID 大排列布,而是压缩成连续存储,局部性大大提高——一次取一个 ID 往往能顺带把附近几个 ID 的数据一起搬进缓存。
更妙的是“就地更新”(In-place Update)机制。推荐系统每来一批新点击,都要更新对应行的向量。在传统满表计算中,更新一个行往往要先把整个表拷到新地址再整体写回;而在 SparseCore 中,更新只发生在 CSR 紧凑区域内,直接找到行号覆盖写入,不需要移动其他数据。压缩后的存储开销显著下降:
小智看着这本索引册感慨:百万本书被压成几排书架,索引册一翻就能找到,存储省了 99% 都不稀奇。不过他又想到一层——哪怕取书员再快,如果每次都要跑到仓库深处去取,速度终究有限。要是能在借阅台旁边放一个“热门书柜”就好了,这就轮到准入缓存登场。
- $N \times d$(原始存储量)稠密表为全部 $N$ 行各存一个 $d$ 维向量,是压缩前占用空间。
- $2M$(压缩后主体)只存 $M$ 个非空行的数值和对应索引,索引与数值各一份。
- $\gamma$(压缩率)压缩后空间与原始空间的比值,衡量省了多少显存。
准入缓存机制
分拣主管显然早有准备。他在借阅台旁增设了一个“热门书柜”(准入缓存),专门存放最近高频借阅的书。读者来借书时,先看热门书柜里有没有,有就直接递过去;没有才让取书员跑仓库。这个热门书柜不需要太大,放最常访问的几百本,就能挡住绝大部分取书跑腿。
硬件上,这个热门书柜就是 SparseCore 中的准入缓存(Access Cache)。它位于核心与主存之间,容量远比主存小但访问速度极快,专门缓存近期被访问过的嵌入行。其核心指标是命中率 $h$——所有访问请求中,能在缓存里直接满足的比例。若访问模式呈“二八分布”(20% 的热门行承接 80% 的请求),那么只要缓存能容纳下这部分热门行,命中率就能冲到 80% 甚至更高。
但缓存不是无脑吸收所有数据。SparseCore 设计了一个“准入队列”(Admission Queue),只有被判定为“值得缓存”的行才被放入缓存,防止那些只被访问一次就永不出现的冷门行把热门行挤出去。更关键的设计是“幂等性”(Idempotency):同一份访存请求即使被重复执行多次,得到的结果也完全一致,不会因为缓存中数据状态新旧而产生混乱——就像热门书柜里的一本书无论被借多少次,归还时内容都不会被改坏。这保证了缓存替换策略可以大胆工作而不必担心数据一致性崩溃。命中率提升带来的总延时变化:
小智把热门书柜的故事记在笔记本上:缓存就是“让 80% 的借书需求在几步之内解决”。不过他很快又想到一个更深的问题——仓库里的书在不断变化:新书补充、旧书被淘汰、书被借走又还回,长期下来书架上会留下大量空洞(碎片)。谁来收拾这个烂摊子?分拣主管微微一笑,指了指调度室里的仓库管理系统。
- $h$(命中率)缓存能直接满足的请求占全部请求的比例,取值范围 0 到 1。
- $T_{缓存}$(缓存延迟)接近核心、容量小、速度快,通常只有主存延迟的十分之一。
- $T_{有效}$(平均延迟)加权平均后的访存延迟,$h$ 越高,$T_{有效}$ 越接近 $T_{缓存}$。
内存管理策略
仓库管理系统(内存管理)是分拣主管的另一项秘密武器。它负责两件事:一是给新入库的书分配书位(单元分配),二是把那些已经无人问津、长期占据书位的书进行回收(隐式回收)。在 SparseCore 中,存储器被划分为固定大小的“单元”(Cells),每个单元可容纳一个嵌入向量。分配器维护着一张空闲单元表,取书员需要空间时以 O(1) 复杂度从中取一个空闲单元。
隐式回收则更像图书馆的“还书检测系统”:当某个嵌入行被覆盖更新时,旧的向量值如果没有其他引用,就会被自动标记为可回收。SparseCore 不依赖软件垃圾回收器,而是用硬件计数器追踪每个单元的最后使用时间,超时未用的单元会被硬件悄悄回收进空闲库。这套机制让内存管理的开销几乎被隐藏在正常访存流程中。
长期运行后,仓库难免出现碎片——一些单元被释放后与相邻空闲不连续,形同书架上的空洞。此时系统会计算碎片率 $f$,若碎片率超过阈值,则触发一次“紧凑整理”,把碎片中间的存活单元移动到连续区域,腾出大片完整空间。整理操作是昂贵的,所以控制在碎片率不足以影响大块分配时才触发,实现“懒整理”。
小智终于理解,SparseCore 之所以敢把主存让给稀疏表随便用,正是因为背后有一套自动化的“书位管家”。现在他迫不及待想知道:这套取书、缓存、整理体系,究竟让真实世界的哪些应用焕然一新?
- $S_{碎片}$(碎片空间)已被释放但无法合并成大块连续空间的大小,像书架上零散的空洞。
- $S_{已分配}$(存活数据)当前仍被访问的嵌入行占用的空间,是真正有价值的容量。
- $f$(碎片率)碎片占总空间比例,超过阈值如 30% 时触发紧凑整理。
工作负载加速
小智打开 TPU 的测试报告,发现受益最大的恰好就是他做的那类系统。推荐系统是非常典型的工作负载:嵌入表有数亿行,每次推理只查几十个槽位(slot)对应的行。在 SparseCore 上,推荐模型不用再被迫把整个嵌入表压实进计算单元,而是“查一行算一行”,配合准入缓存的超高命中率,吞吐量比传统稠密执行方式提升数倍。
图神经网络(GNN)是第二类大赢家。GNN 做邻居聚合时,每个节点要访问其邻居节点的特征行,而真实世界的图往往是幂律分布的——少数“明星节点”拥有海量邻居,大多数节点的邻居寥寥无几。SparseCore 对这类不规则访存模式尤其擅长:访存引擎为每个节点并行取邻居行,嵌入片就地聚合,汇聚片再把不同节点子图的结果拼接。过去 GPU 上因邻居数参差不齐导致的线程发散和访存浪费,在这里被硬件流水线吸收。
除了这两种场景,Transformer 中的稀疏注意力、大规模 MoE(专家混合)模型中专家路由等也呈现出稀疏特性。SparseCore 的设计哲学是“多类稀疏共优化”——只要有“大表 + 少数索引”的访问规律,就能压缩存储、缓存提速、流水线隐藏延迟。综合性能提升可以用加速比衡量:
合上测试报告,小智长长舒了一口气。当年那个让他在深夜抓狂的推荐系统,如今在 SparseCore 上跑得飞快。他这才彻底明白:面对“书极多、借得极少”的世界,聪明的方法从来不是像传统硬件那样把图书馆整个搬空,而是派一个懂索引的取书员,备一个放热门书的书柜,再雇一个细心的书位管家——只为需要的行搬书,就是 SparseCore 的全部秘密。
- $T_{传统稠密执行}$把整个嵌入表全部读入计算单元的耗时,随总行数 $N$ 线性增长。
- $T_{SparseCore执行}$只读取 $M$ 个实际访问行、配合缓存命中后的耗时。
- $S$(加速比)两者之比。若只查 1% 的行,理论加速比可达两个数量级。
AI 应用场景
广告点击率预估
阶段:稀疏特征嵌入与模型推理
解决的问题:广告系统每个请求要读取用户画像、广告属性等十几个特征槽位的嵌入向量,传统稠密执行方式需要把上亿行的嵌入表全部加载,访存带宽被大量无效数据吞噬。SparseCore 通过 CSR 压缩存储和准入缓存,让系统只做“按 ID 取行”的精准访存,极大降低延迟与功耗。
具体案例:某大型线上广告平台在广告点击率预估模型中部署 TPU SparseCore 后,将嵌入表从 5 亿行压缩存储,配合缓存命中,单个请求的推理延迟从 8ms 降至 2ms,同时单卡可承载的模型规模提升近两倍。
图神经网络节点分类
阶段:邻居特征聚合
解决的问题:GNN 每层都要聚合每个节点邻居的特征向量,邻居分布极不均衡,GPU 上容易出现线程发散和大量无效访存。SparseCore 的访存引擎支持不规则索引访问,嵌入片就地做聚合运算,配合内存管理的单元分配,大幅提升聚合效率。
具体案例:在拥有 10 亿节点、200 亿条边的社交网络图上运行 GraphSAGE 模型,传统 GPU 因邻居访存不规则导致利用率不足 30%;迁移到 TPU SparseCore 后,聚合吞吐量提升 4 倍,训练时间由数周压缩到数天。
Python 演示
import random class DenseEmbedding: """传统稠密嵌入表:预分配全部行,模拟满表计算""" def __init__(self, vocab_size: int, dim: int): self.vocab_size = vocab_size self.rows = [[0.0] * dim for _ in range(vocab_size)] def lookup(self, ids): return [self.rows[i][:] for i in ids] class SparseEmbedding: """稀疏嵌入表:按需分配行,模拟 SparseCore 的惰性分配""" def __init__(self, vocab_size: int, dim: int): self.dim = dim self.rows = {} def lookup(self, ids): result = [] for i in ids: if i not in self.rows: self.rows[i] = [0.0] * self.dim result.append(self.rows[i]) return result def simulate(): vocab_size = 100000 dim = 32 batch_ids = [random.randint(0, vocab_size - 1) for _ in range(500)] dense = DenseEmbedding(vocab_size, dim) sparse = SparseEmbedding(vocab_size, dim) dense_rows = dense.lookup(batch_ids) sparse_rows = sparse.lookup(batch_ids) dense_size = vocab_size * dim sparse_size = sum(len(v) for v in sparse.rows.values()) print('稠密表元素数:', dense_size) print('稀疏表实际元素数:', sparse_size) print('内存节省比例: {:.2%}'.format(1 - sparse_size / dense_size)) print('访问行数/总行数: {}/{}'.format(len(sparse.rows), vocab_size)) if __name__ == '__main__': simulate()
self.rows = [[0.0] * dim for _ in range(vocab_size)]稠密表预先把 10 万行全部建好,模拟传统 GPU 满表常驻显存的做法。self.rows = {}稀疏表用字典只保存真正被访问过的行,模拟 SparseCore 的按需分配。if i not in self.rows: self.rows[i] = [0.0] * self.dim首次访问某行时才分配内存,这就是隐式分配的精髓。batch_ids = [random.randint(0, vocab_size - 1) for _ in range(500)]生成 500 个随机查询 ID,模拟一批推荐请求的稀疏访问。sparse_size = sum(len(v) for v in sparse.rows.values())统计稀疏表实际占用的元素总数,通常远小于稠密表。print('内存节省比例: {:.2%}'.format(...))直观输出相对稠密表节省的显存百分比,通常在 95% 以上。
常见误区
误区“TPU 上加了个 SparseCore,是不是我随便什么模型跑上去都能变快?我看它名字里带'稀疏',应该是对所有模型都有优化。”
正解SparseCore 只对“大表小查”——即嵌入表等稀疏访问模式的工作负载有效。对纯稠密矩阵乘法(如大语言模型的标准 FFN 层)来说,数据本就整齐密集,没有稀疏可压,SparseCore 几乎没有收益。它像图书馆的取书员,主要优势在“书多借得少”的场景;如果读者每次把全馆的书都借走,取书员的索引技巧就派不上用场。
为何常见:人们看到“稀疏加速”字样,容易默认所有模型都隐含稀疏性,混淆了参数稀疏与访问稀疏。SparseCore 针对的是访问模式的稀疏,而非模型权重的稀疏。
误区“压缩存储不就是把嵌入表变小点、多省点显存嘛,推理速度该多慢还是多慢吧?”
正解SparseCore 的核心收益恰恰是速度。传统稠密执行要搬运全表,访存带宽被大量无效数据占用;SparseCore 把访存量从 O(N) 降到 O(M),配合准入缓存命中,直接削减了数据搬运时间。速度提升来自“少搬数据”,而省内存只是副产品——就像图书馆提速的关键是少搬书,而不是书架变小。
为何常见:大家习惯认为“压缩 = 省空间”,忽视了访存带宽常常是推理的真正瓶颈,从而低估了按需访存带来的延迟收益。
误区“既然准入缓存能提速,那把缓存做到和嵌入表一样大,岂不 100% 命中?”
正解准入缓存是芯片上的 SRAM,容量受面积和功耗约束,无法做到与主存级嵌入表相当。且在实际工作负载中,请求呈长尾分布,缓存只适合装高频头部的行;盲目扩容到容纳低频长尾,收益边际递减——命中率从 80% 提到 90% 也许需要 10 倍缓存容量,得不偿失。此外缓存还要维护一致性和幂等性,容量越大管理开销越高。
为何常见:“缓存越大越快”是直觉推断,忽略了硬件成本与长尾分布的客观规律,真正的设计目标是在给定面积下最大化有效命中率。
误区“把整张嵌入表都塞进 SparseCore 的本地存储里,之后就不用管内存了。”
正解嵌入表规模常达数亿行,远超 SparseCore 片上缓存容量,绝大多数数据依然驻留在 HBM 主存中。SparseCore 的价值在于把访存变得“精准”——只取需要的行、缓存热门的行、自动回收废弃的行。它管理的是一整套层级存储体系,而不是让整张表都驻留核心。哪怕表再大,只要访问模式稀疏,SparseCore 就能高效工作。
为何常见:把“加速器件”误解为“超大内存”,忽视了 SparseCore 的本质是访存模式的优化器,而非存储容量的扩展器。
面试题
Q1. SparseCore 主要解决哪一类计算场景的性能瓶颈?
- A.稠密矩阵乘法的算力不足
- B.稀疏嵌入表的大表小查访存← 正确答案
- C.卷积神经网络的并行度低
- D.大语言模型的生成速度慢
答案:B。SparseCore 是专门为大而稀疏的嵌入表按索引查询设计的硬件单元(选项 B)。选项 A 是传统 MXU 等稠密计算单元的职责;选项 C、D 问题虽涉及性能,但并非“稀疏嵌入表访问”这一核心场景。
Q2. SparseCore 的三个核心硬件模块不包括以下哪一项?
- A.访存引擎
- B.嵌入片
- C.汇聚片
- D.注意力计算单元← 正确答案
答案:D。SparseCore 由访存引擎、嵌入片、汇聚片组成,分别负责按索引取数、执行嵌入计算、合并结果(选项 A、B、C)。注意力计算单元属于 Transformer 加速器,不属于 SparseCore 的组成模块。
Q3. 嵌入表采用 CSR 压缩存储后,索引数组的主要作用是什么?
- A.记录每行向量的存储校验值
- B.映射原始 ID 到压缩后的物理位置← 正确答案
- C.保存稀疏行的梯度累加结果
- D.替代数值数组完成所有计算
答案:B。CSR 把稀疏行压缩成连续数值数组,索引数组记录每个原始 ID 对应数据在数值数组中的位置,实现 O(1) 定位(选项 B)。校验值、梯度与索引无关,数值数组才承载实际向量。
Q4. 在 SparseCore 中,准入缓存的核心作用是什么?
- A.加大主存容量
- B.缓存热门嵌入行以降低访存延迟← 正确答案
- C.替代嵌入片做矩阵运算
- D.压缩嵌入表的数值精度
答案:B。准入缓存专门缓存近期高频访问的嵌入行,命中时直接从快速缓存返回,避免去主存搬运(选项 B)。它不扩大主存、不算矩阵、也不压缩精度。
Q5. 幂等性在 SparseCore 缓存中的意义是什么?
- A.保证缓存命中率不低于 90%
- B.同一访存请求可重复执行且结果一致← 正确答案
- C.缓存中的数据永不失效
- D.访存引擎只能按顺序取数
答案:B。幂等性即同一请求执行多次结果不变,使缓存可以大胆替换、更新而不必担心数据一致性崩溃(选项 B)。它不是命中率承诺,也不意味着不失效。
Q6. SparseCore 内存管理中“隐式回收”是指什么?
- A.软件显式调用 free 释放空间
- B.硬件标记不再使用的单元并自动回收← 正确答案
- C.每次访问后立即清除缓存行
- D.用哈希表重建整个嵌入表
答案:B。隐式回收由硬件追踪单元状态,超时未用即自动回收进空闲池,无需软件参与(选项 B)。SparseCore 面向免拷贝、免软件管理设计,回收完全内嵌在访存管线中。
Q7. 某嵌入表有 1000 万行,一次推理访问 1000 行且全部能命中准入缓存。与无缓存满表执行相比,访存量约降至原来的多少?
- A.1%
- B.0.01%← 正确答案
- C.0.1%
- D.10%
答案:B。满表执行需访问 1000 万行,SparseCore 只访问实际需要的 1000 行,加上缓存命中和压缩存储,访存量从 N 降到 M,即 1000/10000000 = 0.01%(选项 B)。选项 C 计算有误,选项 A、D 明显偏大。
Q8. 以下哪些工作负载适合使用 SparseCore 加速?
- A.推荐系统中的嵌入表查询← 正确答案
- B.图神经网络的邻居特征聚合← 正确答案
- C.纯稠密的卷积神经网络
- D.广告点击率预估的特征嵌入← 正确答案
答案:ABD。推荐系统嵌入查询、GNN 邻居聚合、广告点击率预估都呈现“大表 + 稀疏索引”的访问模式(选项 A、B、D),适合 SparseCore。纯稠密卷积计算没有稀疏性,无法从中获益。
Q9. SparseCore 中访存引擎的职责包括哪些?
- A.根据 ID 计算物理地址← 正确答案
- B.发出对 HBM 主存的读取请求← 正确答案
- C.执行嵌入向量的乘加运算
- D.配合准入缓存判断是否命中← 正确答案
答案:ABD。访存引擎负责地址计算、主存请求和缓存命中判断(选项 A、B、D)。向量乘加运算由嵌入片完成,不归访存引擎管。
Q10. SparseCore 通过以下哪些机制协同降低稀疏工作负载的访存开销?
- A.CSR 压缩按需存储← 正确答案
- B.准入缓存缓冲热门行← 正确答案
- C.隐式回收整理废弃单元← 正确答案
- D.增加 HBM 显存带宽
答案:ABC。压缩存储减少搬运量、准入缓存拦截重复访问、隐式回收与碎片整理维持空间连续,三者协同(选项 A、B、C)。SparseCore 是优化访存模式而非增加物理带宽,选项 D 不属于其设计机制。