2. GEMM基础
在FPGA脉动阵列加速器的设计过程中,GEMM(General Matrix Multiply,通用矩阵乘法)是最核心的计算原语。无论是卷积神经网络中的特征图运算,还是Transformer中的注意力机制,最终都可以转化为矩阵乘加操作。理解GEMM的数学定义、计算复杂度以及数据复用特性,是设计高效脉动阵列架构的前提。
2.1 GEMM的数学定义
GEMM描述的是两个矩阵相乘并累加到第三个矩阵上的运算,其标准形式为:
C = α × A × B + β × C
其中:
A ∈ R^(M×K) 左矩阵
B ∈ R^(K×N) 右矩阵
C ∈ R^(M×N) 累加矩阵/输出矩阵
α, β 标量系数
展开后每个输出元素的计算为:
C[i][j] = α × Σ(k=0→K-1) A[i][k] × B[k][j] + β × C[i][j]
当α=1、β=0时,退化为最基础的矩阵乘法C=A×B。在深度学习中,全连接层、卷积层(通过im2col展开)、注意力中的QK^T和PV计算,本质上都是GEMM的特例。FPGA脉动阵列的设计目标,就是让这个三重循环(i、j、k)在硬件上以最高的吞吐率和能效比执行。
2.2 计算复杂度分析
GEMM的计算复杂度直接决定了硬件加速器的设计目标。对于M×K的矩阵A与K×N的矩阵B相乘,其计算量为:
- 乘法次数:M × N × K
- 加法次数:M × N × (K-1) ≈ M × N × K
- 总乘加操作(MAC):M × N × K
- 数据搬运量:输入 M×K + K×N,输出 M×N
以典型的Transformer层为例,假设M=512、K=768、N=768,则单次GEMM需要约3.02亿次乘加操作。若FPGA运行在200MHz,每个时钟周期完成1024次MAC,则理论计算时间为:
计算量 = 512 × 768 × 768 = 301,989,888 MACs
理论周期数 = 301,989,888 / 1024 ≈ 294,912 cycles
理论时间 = 294,912 / 200MHz ≈ 1.47 ms
关键洞察:GEMM的计算强度(Compute Intensity)为 O(MNK) / O(MK+KN+MN)。当M、N、K都较大时,计算强度趋近于min(M,N,K)/3,这意味着数据复用空间巨大,非常适合脉动阵列架构。
2.3 数据复用机会与脉动阵列的契合
GEMM中存在三种经典的数据复用模式,这正是脉动阵列设计的理论基础:
| 复用类型 | 复用对象 | 复用次数 | 脉动阵列实现方式 |
|---|---|---|---|
| 行复用 | A矩阵的每个元素A[i][k] | N次 | 沿水平方向广播到PE阵列 |
| 列复用 | B矩阵的每个元素B[k][j] | M次 | 沿垂直方向广播到PE阵列 |
| 累加复用 | 部分和C[i][j] | K次 | 在PE内部累加寄存器中保持 |
脉动阵列的核心思想是:让数据像血液一样在PE(Processing Element)阵列中有节奏地流动,每个PE从水平方向接收A的元素,从垂直方向接收B的元素,完成一次乘加后将部分和传递给下一个PE。这种结构天然匹配GEMM的三重循环,能够以极低的数据搬运代价实现高计算吞吐。
设计启示:脉动阵列的尺寸(如16×16、32×32)直接决定了单周期MAC数量。阵列越大,数据复用率越高,但布线延迟和功耗也会增加。需要在吞吐率、面积和功耗之间做权衡。
2.4 典型应用场景
GEMM在深度学习和科学计算中无处不在,以下是几个典型场景:
- 全连接层:输入向量与权重矩阵相乘,本质是M=1的GEMM(矩阵-向量乘),但批处理时M=batch_size。
- 卷积层:通过im2col将卷积转化为GEMM,其中M=输出通道数,N=输出空间位置数,K=输入通道数×卷积核尺寸。
- Transformer注意力:QK^T计算(M=seq_len, K=head_dim, N=seq_len)和PV计算(M=seq_len, K=seq_len, N=head_dim)均为GEMM。
- 科学计算:线性方程组求解、特征值分解、有限元分析中的刚度矩阵组装等,都依赖大规模GEMM。
2.5 常见误区与复盘
误区一:认为GEMM只是简单的三重循环,忽略内存层次的影响。实际上,当矩阵规模超过片上缓存时,数据搬运能耗可能远超计算能耗。脉动阵列的价值正在于通过数据复用减少片外访存。
误区二:盲目追求大阵列。32×32阵列的MAC单元数量是16×16的4倍,但若数据供给带宽不足,PE将大量空闲。必须保证数据带宽与计算吞吐匹配。
误区三:忽略边界处理。当M、N、K不是阵列尺寸的整数倍时,需要padding或边界PE屏蔽,这会引入额外的控制逻辑和效率损失。
误区二:盲目追求大阵列。32×32阵列的MAC单元数量是16×16的4倍,但若数据供给带宽不足,PE将大量空闲。必须保证数据带宽与计算吞吐匹配。
误区三:忽略边界处理。当M、N、K不是阵列尺寸的整数倍时,需要padding或边界PE屏蔽,这会引入额外的控制逻辑和效率损失。