3. 片上存储层次:全局缓冲区(GLB)、局部寄存器文件(RF)、存储层次与带宽优化。

好,我们接着聊Eyeriss的存储。说实话,很多做AI加速器的朋友,一开始都把精力扑在计算单元上,觉得MAC阵列猛就完了。结果呢?数据搬来搬去,功耗全耗在走线上,计算单元饿得嗷嗷叫。这就是典型的“存储墙”问题。

Eyeriss的设计思路很实在——它把存储拆成了三个层次:全局缓冲区(GLB)、局部寄存器文件(RF),以及它们之间的数据通路。说白了,就是用层次化的存储来对抗带宽瓶颈。我当年做第一版加速器原型时,就是没想明白这个层次,结果GLB做得太大,RF又太小,调度起来别提多别扭了。

3.1 全局缓冲区(GLB):片上的“数据池”

GLB是Eyeriss片上的主存储,它连接着片外的DRAM和片内的计算阵列。你可以把它想象成一个——数据从DRAM搬进来,先存在GLB里,再分发给各个PE。

核心参数:Eyeriss的GLB大小为108 KB,采用SRAM实现。这个容量是经过精心权衡的——既要能装下足够多的输入特征图和权重,又不能太大导致芯片面积失控。

我个人习惯把GLB看作一个“双缓冲”结构。什么意思呢?就是它内部被分成了两个Bank:一个Bank在给PE喂数据,另一个Bank同时在从DRAM搬新数据。这样读写可以流水起来,不会让计算停下来等数据。

这里有个关键点——GLB的带宽。Eyeriss的GLB支持多端口访问,但端口数有限。我记得在项目里,我们曾经为了省面积,把GLB的读端口从4个砍到2个,结果PE阵列的利用率直接掉了15%。嗯,这个坑踩过之后,我再也不敢在带宽上省面积了。

存储层次 容量 访问延迟 主要作用
GLB 108 KB 2-3 周期 片内数据中转,减少DRAM访问
RF 每个PE 24 B 1 周期 PE内部数据暂存,支持零开销循环
DRAM 片外(GB级) 几十到上百周期 存储完整模型和输入

3.2 局部寄存器文件(RF):PE的“工作台”

RF是每个PE私有的小存储。Eyeriss里每个PE有24字节的RF,分成几个独立的寄存器组。你想想看,一个PE要同时处理权重、输入特征图和部分和,如果所有数据都去GLB拿,那GLB的端口早就被挤爆了。

RF的设计哲学是“够用就好”。24字节能存多少?以典型的3x3卷积为例,一个PE一次处理一个输出通道的部分和,加上几个权重和输入像素,刚好塞得下。我建议在设计RF时,一定要算清楚每个PE的“工作集”大小——太大浪费面积,太小则频繁从GLB取数,功耗反而更高。

避坑指南:我曾经在另一个项目里,把RF做得特别大(每个PE 128字节),想着“反正面积够”。结果呢?RF的访问功耗占了PE总功耗的40%以上,得不偿失。Eyeriss的24字节是经过大量仿真验证的,别轻易改大。

RF还有一个妙用——支持“零开销循环”。当PE在计算一个卷积窗口内的多个像素时,权重可以一直留在RF里,不用反复从GLB加载。这个特性对稀疏计算尤其重要,因为非零权重本来就少,更要充分利用RF的局部性。

3.3 存储层次与带宽优化

好了,GLB和RF都讲完了,那它们怎么协同工作呢?这就涉及到Eyeriss最核心的带宽优化策略——数据复用。

Eyeriss的存储层次设计,本质上是在做一件事:让数据尽量在靠近计算的地方多待一会儿。具体来说,有三种复用模式:

  1. 权重复用(Weight Stationary):权重从GLB加载到RF后,在多个输入像素上重复使用。适合卷积核较小的层。
  2. 输入复用(Input Stationary):输入特征图在GLB中广播给多个PE,每个PE用不同的权重去算。适合输入通道数多的层。
  3. 部分和复用(Output Stationary):部分和留在PE的累加器中,不断累加新的乘积。适合输出通道数多的层。

你可能会问:“这三种模式怎么选?” 嗯,Eyeriss的做法是——不选。它通过一个灵活的数据流调度器,在运行时根据层的形状动态切换复用模式。我当年看到这个设计时,觉得真是聪明:硬件上只做简单的多路选择,复杂的调度逻辑交给编译器。

注意:复用模式切换是有代价的。每次切换时,GLB和RF里的数据需要重新排布,这会产生几个周期的“气泡”。在层数很深的网络中,频繁切换反而会降低效率。我建议在部署时,尽量把相同复用模式的层放在一起执行。

下面这张图展示了Eyeriss的存储层次和数据流动路径。你可以看到,数据从DRAM到GLB,再到RF,最后进入MAC阵列,每一级都在做“降频提速”——带宽越来越窄,但访问速度越来越快。

Eyeriss片上存储层次与数据流 Eyeriss 片上存储层次与数据流 DRAM(片外) 高带宽,高延迟 GLB(108 KB SRAM) 中带宽,中延迟 数据分发网络 PE阵列 每个PE含RF(24 B) PE阵列 每个PE含RF(24 B) 数据流动方向:DRAM → GLB → 分发网络 → PE(RF)→ MAC计算

3.4 带宽优化的实战技巧

讲完了理论,来点实际的。我在做稀疏加速器时,总结了几条存储层次优化的经验:

  • GLB容量要匹配“层内复用度”:如果一个卷积层,权重复用次数很高,那GLB里多放几组权重是划算的。反之,如果复用度低,GLB再大也是浪费。
  • RF的读写端口要对称:我见过一些设计,RF的读端口比写端口多,结果写数据时排队,读数据时空闲。Eyeriss的RF读写端口是1:1的,很合理。
  • 小心“伪共享”:当多个PE同时访问GLB的同一个Bank时,会产生冲突。解决办法是让编译器做地址交错——把连续的数据分散到不同Bank里。

一个具体的例子:假设我们要在Eyeriss上跑一个卷积层,输入是56x56x64,权重是3x3x64x128。GLB里需要同时存:输入特征图(56x56x64 ≈ 200 KB,放不下,只能分块)、权重(3x3x64x128 ≈ 73 KB,可以全放)、部分和(56x56x128 ≈ 400 KB,放不下,需要流式处理)。你看,GLB的108 KB其实很紧张,必须精细调度。

最后说一句,存储层次的设计没有银弹。Eyeriss的108 KB GLB + 24 B RF是针对移动端场景优化的。如果你做的是云端加速器,GLB可能要做到几MB,RF也要更大。但核心思想不变——让数据靠近计算,减少远距离搬运。这个道理,做芯片的人应该都懂。