第二章 卷积加速器架构概览:数据流、计算单元、存储系统,一张图看懂全局

各位同学,欢迎来到第二章。上一章我们聊了卷积运算的本质,说白了就是“滑动窗口乘累加”。这一章,咱们把视野拉高,看看整个加速器是怎么搭起来的。

我经常跟新人说一句话:搞架构设计,先别急着写代码,先把数据怎么流、存哪里、谁来算这三件事想清楚。这三件事,就是本章的核心——数据流、存储系统、计算单元。

核心观点:卷积加速器的本质,是一个“数据搬运+计算”的流水线。瓶颈往往不在计算,而在数据搬运。

2.1 一张图看懂全局架构

先别急着看细节,咱们先画一张总图。我习惯用“三层结构”来理解卷积加速器:

卷积加速器三层架构总览 存储系统(Memory Hierarchy) DDR/DRAM 片外存储,容量大 Global Buffer 片上SRAM,中间缓存 Register File 寄存器,零延迟 数据流控制(Dataflow Controller) 权重固定流 Weight Stationary 输入固定流 Input Stationary 输出固定流 Output Stationary 计算单元(Compute Array) PE阵列 乘累加核心 累加器 部分和累加 激活函数 ReLU/Sigmoid 池化 可选

这张图我建议你保存下来。每次做设计时,问自己三个问题:数据从哪来?存在哪?谁在算?答案就在这三层里。

2.2 存储系统:三层缓存,各司其职

存储系统是加速器的“血管”。我见过太多项目,计算单元跑得飞快,但数据喂不上去,白搭。

咱们的存储分三层:

  • DDR/DRAM(片外):容量大,但延迟高。一次读写要几十甚至上百个时钟周期。说白了,这是“仓库”,不是“工作台”。
  • Global Buffer(片上SRAM):这是关键。一般用几十KB到几MB的SRAM。我习惯把它叫做“中间站”——从DDR搬数据到这儿,再从这儿喂给计算单元。
  • Register File(寄存器):每个PE(处理单元)内部的小寄存器,零延迟。但容量极小,通常存几个数。

我的经验:Global Buffer的大小直接决定了加速器的性能。太小了,DDR频繁搬运,功耗爆炸;太大了,芯片面积受不了。一般我会先算一下:一次卷积需要多少输入数据?权重多大?输出多大?然后Buffer至少能装下2~3倍的“一次计算所需数据”。

2.3 数据流:三种主流策略

数据流,说白了就是“谁不动,谁动”。卷积运算涉及三个数据:输入特征图、权重、输出特征图。你让谁待在原地不动,谁频繁移动?

有三种主流策略:

数据流策略 核心思想 优点 缺点
权重固定流 权重存在PE里不动,输入和输出流动 权重复用率高,适合权重小的网络 输入数据需要广播,带宽压力大
输入固定流 输入特征图存在PE里不动,权重流动 输入复用率高,适合大输入 权重需要频繁加载
输出固定流 部分和存在PE里不动,输入和权重流动 减少中间结果写回 PE内部寄存器需求大

我在项目中用得最多的是权重固定流。为什么?因为卷积核通常很小(3x3、5x5),权重数据量不大,可以一次性加载到PE阵列里,然后让输入数据“流”过来。这样DDR的访问次数最少。

注意:数据流的选择不是的。我见过一个项目,为了追求极致性能,搞了个“动态切换”的架构——不同层用不同数据流。结果控制逻辑复杂到爆炸,最后性能没提多少,面积翻了一倍。嗯,有时候“简单”才是最好的。

2.4 计算单元:PE阵列与乘累加

计算单元是加速器的“心脏”。核心就是PE(Processing Element),每个PE里有一个乘法器和一个累加器。

一个典型的PE结构:

// 伪代码:PE内部逻辑
always @(posedge clk) begin
    if (en) begin
        // 乘累加操作
        acc <= acc + weight * input;
    end
end

PE阵列的规模,直接决定了并行度。比如一个16x16的PE阵列,一次可以算256个乘累加。但要注意:不是PE越多越好。我踩过一个坑:把PE阵列做得很大,结果数据喂不饱,很多PE在空转,功耗上去了,性能没上去。

一般我会这样估算PE数量:

  • 先看目标算力:比如要跑1TOPS(每秒1万亿次操作)
  • 再看时钟频率:比如500MHz
  • 那么需要的PE数量 = 1TOPS / (500MHz * 2) = 1000个PE

注意这里乘了2,因为每个PE每周期可以做一次乘法和一次加法(算两次操作)。

2.5 实战:一个简单的数据流示例

咱们拿一个3x3卷积,输入是8x8特征图,步长为1,来走一遍数据流:

  1. 加载权重:9个权重值,一次性加载到PE阵列的寄存器里。
  2. 加载输入:从Global Buffer里读出一行输入数据(比如第一行3个像素),送到PE。
  3. 计算:PE做乘累加,结果暂存在累加器里。
  4. 滑动窗口:输入数据向右滑动一个像素,重复步骤2~3。
  5. 写回:一行计算完,把结果写回Global Buffer。

你看,整个过程就像流水线一样。我习惯用“乒乓操作”来优化——两个Buffer交替读写,一个在算,一个在加载,这样DDR带宽利用率最高。

关键指标:衡量一个加速器好不好,看三个数:算力利用率(实际算力/理论峰值)、DDR带宽利用率、功耗效率(TOPS/W)。这三个数,一个都不能低。

2.6 本章小结

这一章,咱们把卷积加速器的“骨架”搭起来了。记住三句话:

  • 存储系统:三层缓存,Global Buffer是关键。
  • 数据流:选对策略,让数据少搬家。
  • 计算单元:PE阵列是核心,但别贪多。

下一章,咱们会深入PE内部,看看乘累加器到底怎么设计,以及如何用流水线把性能榨干。嗯,到时候我会分享一个我当年调试PE时遇到的“灵异事件”——一个加法器让我查了三天bug。

可可精品资料库