第二章 卷积加速器架构概览:数据流、计算单元、存储系统,一张图看懂全局
各位同学,欢迎来到第二章。上一章我们聊了卷积运算的本质,说白了就是“滑动窗口乘累加”。这一章,咱们把视野拉高,看看整个加速器是怎么搭起来的。
我经常跟新人说一句话:搞架构设计,先别急着写代码,先把数据怎么流、存哪里、谁来算这三件事想清楚。这三件事,就是本章的核心——数据流、存储系统、计算单元。
核心观点:卷积加速器的本质,是一个“数据搬运+计算”的流水线。瓶颈往往不在计算,而在数据搬运。
2.1 一张图看懂全局架构
先别急着看细节,咱们先画一张总图。我习惯用“三层结构”来理解卷积加速器:
这张图我建议你保存下来。每次做设计时,问自己三个问题:数据从哪来?存在哪?谁在算?答案就在这三层里。
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,来走一遍数据流:
- 加载权重:9个权重值,一次性加载到PE阵列的寄存器里。
- 加载输入:从Global Buffer里读出一行输入数据(比如第一行3个像素),送到PE。
- 计算:PE做乘累加,结果暂存在累加器里。
- 滑动窗口:输入数据向右滑动一个像素,重复步骤2~3。
- 写回:一行计算完,把结果写回Global Buffer。
你看,整个过程就像流水线一样。我习惯用“乒乓操作”来优化——两个Buffer交替读写,一个在算,一个在加载,这样DDR带宽利用率最高。
关键指标:衡量一个加速器好不好,看三个数:算力利用率(实际算力/理论峰值)、DDR带宽利用率、功耗效率(TOPS/W)。这三个数,一个都不能低。
2.6 本章小结
这一章,咱们把卷积加速器的“骨架”搭起来了。记住三句话:
- 存储系统:三层缓存,Global Buffer是关键。
- 数据流:选对策略,让数据少搬家。
- 计算单元:PE阵列是核心,但别贪多。
下一章,咱们会深入PE内部,看看乘累加器到底怎么设计,以及如何用流水线把性能榨干。嗯,到时候我会分享一个我当年调试PE时遇到的“灵异事件”——一个加法器让我查了三天bug。