4、AI加速器架构基础:脉动阵列、数据流架构、稀疏计算支持
各位同学,今天我们来聊聊AI加速器里最核心的几个架构概念。说实话,这部分内容我当年刚接触时也觉得有点抽象,但后来在几个项目里反复折腾,慢慢就摸透了。你想想看,AI计算说白了就是矩阵乘法和卷积,怎么算得快、算得省电,才是关键。
4.1 脉动阵列:数据像心跳一样流动
脉动阵列这个名字挺形象的。数据就像血液一样,在计算单元之间有节奏地“泵”过去。每个处理单元(PE)只做一件事:乘加运算。数据从左到右、从上到下流动,中间不需要复杂的路由。
核心思想:每个PE只与相邻PE通信,数据流是规则的、可预测的。这非常适合矩阵乘法。
我在项目中遇到过一个问题:刚开始用脉动阵列做卷积时,总觉得数据加载太慢。后来发现,其实可以把权重提前“驻留”在PE里,只让输入特征图流动。这样一来,数据搬移量直接减少了一半。
来看一个简单的2x2脉动阵列矩阵乘法示例:
// 伪代码:2x2脉动阵列矩阵乘法
// A矩阵:a11 a12 B矩阵:b11 b12
// a21 a22 b21 b22
// 初始化PE
PE[0][0].weight = b11; PE[0][1].weight = b12;
PE[1][0].weight = b21; PE[1][1].weight = b22;
// 数据流动
for (t = 0; t < 2; t++) {
// 第t拍
PE[0][0].input = a11; // 从左侧输入
PE[0][1].input = PE[0][0].output; // 从左侧PE传递
PE[1][0].input = a21; // 从上方输入
PE[1][1].input = PE[1][0].output; // 从上方PE传递
// 每个PE执行乘加
PE[i][j].acc += PE[i][j].input * PE[i][j].weight;
}
嗯,这里要注意:脉动阵列的吞吐量很高,但延迟也相对大。说白了就是“流水线填满”需要时间。我建议在做小批量推理时,要考虑这个启动开销。
4.2 数据流架构:让计算跟着数据走
脉动阵列是“数据动、计算不动”。那反过来呢?数据流架构就是“计算跟着数据走”。每个PE有自己的本地存储,数据到了就触发计算,不需要全局同步。
个人经验:数据流架构特别适合稀疏场景。因为只有非零数据才会触发计算,零数据直接跳过。我曾经在一个稀疏卷积加速器里用了数据流设计,能效比提升了3倍多。
数据流架构主要有两种风格:
- 静态数据流:计算图在编译时就固定了,运行时不变。适合固定形状的模型。
- 动态数据流:计算图可以动态调整,适合变长序列或动态网络。
你想想看,为什么现在很多AI芯片都开始用数据流?因为传统CPU的“取指-译码-执行”模式,在AI计算里效率太低了。数据流架构天然支持流水线并行,每个PE都在忙自己的事,没有空转。
我建议在设计数据流架构时,重点关注两个问题:
- 数据依赖:如果两个PE需要同一份数据,怎么避免冲突?
- 负载均衡:有的PE忙死,有的PE闲死,怎么办?
我曾经在一个项目里踩过坑:数据流图没画好,导致某些PE一直在等数据,利用率不到30%。后来加了一个简单的“数据预取”机制,利用率直接拉到85%以上。
4.3 稀疏计算支持:跳过那些没用的零
说到稀疏计算,我得先问一个问题:为什么AI模型里会有那么多零?
原因很简单:ReLU激活函数会把负数变成零。再加上剪枝、量化这些技术,模型里可能有60%-90%的参数都是零。如果还按稠密方式计算,那大部分算力都浪费了。
避坑指南:我曾经天真地以为,只要检测到零就跳过乘法就行了。结果发现,跳过的代价比计算还大——因为要额外判断、还要处理不规则的数据流。后来才明白,稀疏计算需要硬件和软件协同设计。
稀疏计算支持通常包括这几个层面:
| 技术 | 原理 | 我踩过的坑 |
|---|---|---|
| 零值跳过 | 检测到零操作数,不触发计算 | 判断逻辑太复杂,反而拖慢时钟 |
| 稀疏编码 | 用索引+非零值的方式存储 | 索引占用的存储空间比想象中大 |
| 结构化稀疏 | 按块或按行剪枝,保持规则性 | 剪枝粒度太粗,精度损失大 |
| 动态稀疏 | 运行时根据激活值动态跳过 | 硬件调度复杂度飙升 |
我个人比较推荐的做法是:先用结构化稀疏把模型剪到50%左右,再用零值跳过处理剩下的稀疏性。这样既保证了规则性,又能充分利用稀疏度。
来看一个稀疏矩阵乘法的示例:
// 稀疏矩阵乘法:只处理非零元素
// 使用CSR(压缩稀疏行)格式
typedef struct {
int row_ptr[N+1]; // 每行的起始位置
int col_idx[NNZ]; // 非零元素的列索引
float values[NNZ]; // 非零元素的值
} CSR_Matrix;
// 稀疏矩阵乘向量 y = A * x
void spmv_csr(CSR_Matrix *A, float *x, float *y) {
for (int i = 0; i < N; i++) {
float sum = 0.0;
for (int j = A->row_ptr[i]; j < A->row_ptr[i+1]; j++) {
sum += A->values[j] * x[A->col_idx[j]];
}
y[i] = sum;
}
}
嗯,这里要注意:稀疏计算虽然能省算力,但访存模式变得不规则了。我建议在硬件里加一个“稀疏感知”的缓存,专门缓存那些频繁访问的非零数据。
4.4 三种架构的对比与选择
说了这么多,到底该选哪种架构?我个人的经验是:
- 脉动阵列:适合规则、密集的计算。比如大矩阵乘法、标准卷积。硬件实现简单,但灵活性差。
- 数据流架构:适合不规则、稀疏的计算。比如图神经网络、动态网络。灵活性高,但调度复杂。
- 稀疏计算支持:不是独立的架构,而是对前两者的增强。适合高稀疏度的模型。
我在一个实际项目里做过对比:用脉动阵列跑ResNet-50,能效比是数据流架构的1.5倍。但换成稀疏度80%的剪枝模型后,数据流架构反而领先了2倍。所以说,没有最好的架构,只有最合适的。
核心建议:如果你做通用AI芯片,建议用脉动阵列+稀疏支持。如果你做特定场景(比如自动驾驶、NLP),数据流架构可能更合适。
最后,我画了一张图来总结这三种架构的关系:
这张图把三种架构的关系说清楚了。脉动阵列和数据流架构是两种基础范式,稀疏计算支持是叠加在上面的优化技术。实际芯片设计时,往往是三者的组合。
好了,这一章的内容就到这里。记住:架构设计没有银弹,理解每种技术的优缺点,才能做出好的权衡。