3、AI芯片存储层次:片上存储与片外存储

大家好,我是你们的讲师。今天我们来聊聊AI芯片里一个特别关键、也特别容易让人头疼的话题——存储层次。

说实话,我刚开始做AI芯片那会儿,觉得算法才是核心,存储嘛,不就是放数据的地方?后来被现实狠狠教育了一顿。你想想看,计算单元跑得飞快,数据却堵在门口进不来,这芯片性能再强也是白搭。这就是所谓的“存储墙”问题。

今天,我就把我在项目中踩过的坑、积累的经验,一次性讲清楚。

3.1 为什么存储层次这么重要?

AI计算,说白了就是“数据搬运”的游戏。卷积、矩阵乘,这些操作的本质都是:把数据从某个地方搬过来,算完再搬回去。

搬得快,芯片就快。搬得慢,再牛的算力也白费。

我见过一个团队,设计了一款理论算力很高的芯片,结果实测性能只有理论值的30%。查到最后,问题就出在数据搬运上——存储带宽不够,计算单元一直在空等。嗯,这教训挺深刻的。

核心观点:AI芯片的性能瓶颈,往往不在计算单元,而在存储系统。

3.2 片上存储:SRAM与Scratchpad

片上存储,就是芯片内部集成的存储器。它的特点是:离计算单元近,速度快,但容量小。

3.2.1 SRAM(静态随机存取存储器)

SRAM是片上存储的主力。它不需要像DRAM那样定期刷新,所以访问延迟很低,通常能做到1-2个时钟周期。

我个人习惯把SRAM分成两类:

  • Cache(缓存):硬件自动管理,对软件透明。你只管访问地址,硬件帮你判断命中还是缺失。
  • Scratchpad(便签存储器):软件显式管理,程序员自己控制数据搬入搬出。

在AI芯片里,我更倾向于用Scratchpad。为什么?因为AI计算的数据流是高度可预测的。你提前知道下一层卷积要用哪些权重、哪些特征图,完全可以手动调度,避免Cache的替换开销。

我的经验:在项目里,我们给每个计算核配了256KB的Scratchpad。这个大小是反复权衡过的——太小了装不下一个卷积核,太大了芯片面积受不了。

3.2.2 Scratchpad的典型结构

一个典型的Scratchpad包含:

  • 存储体(Bank):多个独立的存储块,支持并行访问
  • 地址译码器:将地址映射到具体的Bank
  • 控制逻辑:处理读写请求、仲裁冲突

下面这张图是我手绘的Scratchpad内部结构,你一看就明白了:

Scratchpad内部结构示意图 地址译码器 Bank 0 32KB Bank 1 32KB Bank 2 32KB Bank 3 32KB 控制逻辑(仲裁、冲突处理) 数据总线(256-bit) 计算单元(MAC阵列)

3.3 片外存储:HBM与GDDR

片上存储容量有限,装不下整个模型。这时候就需要片外存储来救场。

目前主流的选择有两个:HBM(高带宽存储器)和GDDR(图形双倍数据率存储器)。

3.3.1 HBM vs GDDR:怎么选?

特性 HBM GDDR
带宽 极高(1TB/s+) 高(500GB/s+)
容量 中等(8-16GB/堆叠) 大(16-32GB)
功耗 较低(每比特) 较高
成本 高(2.5D/3D封装) 低(成熟工艺)
典型应用 高端AI训练芯片 推理芯片、游戏GPU

我在项目里做过一个对比:同样做ResNet-50推理,用HBM的芯片带宽利用率能达到85%,而GDDR只有60%左右。原因很简单——HBM的堆叠结构让数据路径更短,访问延迟更低。

注意:HBM虽然好,但封装成本高。如果你的芯片目标市场是边缘设备,GDDR可能是更务实的选择。我曾经有个项目,为了追求极致性能选了HBM,结果成本超了预算,最后不得不砍掉一半的HBM堆叠层数。

3.4 存储带宽计算

带宽,就是单位时间内能搬运多少数据。公式很简单:

带宽 = 总线宽度 × 时钟频率 × 传输次数/周期

举个例子:

  • 总线宽度:512位(64字节)
  • 时钟频率:1GHz
  • DDR(双倍数据率):每个时钟传输2次

那么理论带宽 = 64字节 × 1GHz × 2 = 128GB/s

但实际能用到多少?我告诉你,能到理论值的70%就算不错了。为什么?

  • 协议开销:读写命令、地址、校验位都要占用带宽
  • 刷新开销:DRAM需要定期刷新,这期间不能访问
  • 访问冲突:多个请求同时访问同一个Bank,需要排队

我的建议:做带宽规划时,按理论值的60%来估算。这样留出余量,后期不会手忙脚乱。

3.5 数据复用策略

带宽有限,怎么让有限的数据发挥最大价值?答案是:复用。

AI计算里,数据复用主要有三种模式:

3.5.1 权重复用

同一个卷积核,要跟输入特征图的多个位置做卷积。权重只加载一次,反复使用。

我习惯的做法是:把权重存在Scratchpad里,然后让计算单元按行扫描输入特征图。这样权重只搬一次,输入数据流式读取。

3.5.2 输入特征图复用

多个卷积核共享同一个输入特征图。比如3×3卷积,9个权重值要跟同一个输入像素做乘加。

这时候,我会把输入特征图的一小片区域(比如4×4)加载到Scratchpad里,然后让多个卷积核轮流使用。这能显著减少片外访问次数。

3.5.3 输出特征图复用

多个输入通道累加到同一个输出像素。比如输入有64个通道,每个通道的卷积结果都要累加到同一个输出位置。

嗯,这里要注意:输出累加需要额外的存储空间。我一般会在Scratchpad里划出一块区域专门放部分和(partial sum),等所有通道算完再写回片外。

3.6 实战:一个数据流调度示例

说了这么多,我们来个实际的例子。假设我们要做一次3×3卷积,输入是32×32×64,输出是32×32×128,卷积核是3×3×64×128。

数据量有多大?

  • 输入特征图:32×32×64 = 65,536个元素
  • 权重:3×3×64×128 = 73,728个元素
  • 输出特征图:32×32×128 = 131,072个元素

如果全部放片外,每次计算都要搬数据,带宽根本扛不住。

我的调度策略是这样的:

  1. 分块(Tiling):把输入特征图分成4×4的小块,每次只处理一个块
  2. 权重预加载:把当前块需要的卷积核权重提前搬到Scratchpad
  3. 流水线执行:计算当前块的同时,预取下一个块的权重
  4. 输出累加:部分和暂存在Scratchpad,等所有通道算完再写回

这样,片外访问量从原来的几十万次,降到了几千次。效果立竿见影。

核心思路:数据复用就是“一次搬入,多次使用”。搬得越少,算得越快。

3.7 避坑指南

最后,分享几个我踩过的坑:

  • 别迷信理论带宽:实际带宽受限于访问模式、协议开销、刷新周期。我见过一个团队,理论带宽800GB/s,实测只有300GB/s,就是因为访问模式太随机,导致Bank冲突严重。
  • Scratchpad大小要精打细算:太大浪费面积,太小装不下数据。我一般按“能装下最大卷积核+两行输入特征图”来估算。
  • 数据复用不是越多越好:过度复用会导致计算单元闲置(等数据)。要找到计算和存储的平衡点。

好了,这一章的内容就到这里。存储层次是AI芯片设计的基石,理解透了,后面的计算单元设计、数据流调度才能游刃有余。

想要更多资料,联系可可