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都在忙自己的事,没有空转。

我建议在设计数据流架构时,重点关注两个问题:

  1. 数据依赖:如果两个PE需要同一份数据,怎么避免冲突?
  2. 负载均衡:有的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),数据流架构可能更合适。

最后,我画了一张图来总结这三种架构的关系:

AI加速器架构分类 脉动阵列 数据规则流动 适合密集计算 数据流架构 计算跟随数据 适合稀疏/动态 稀疏计算支持 跳过零值操作 增强型技术 选择建议 • 密集模型 + 高吞吐 → 脉动阵列 • 稀疏模型 + 高灵活 → 数据流架构 • 高稀疏度 → 三种技术组合使用

这张图把三种架构的关系说清楚了。脉动阵列和数据流架构是两种基础范式,稀疏计算支持是叠加在上面的优化技术。实际芯片设计时,往往是三者的组合。

好了,这一章的内容就到这里。记住:架构设计没有银弹,理解每种技术的优缺点,才能做出好的权衡。

专注资料整理