第9章:数字存内计算架构
本章深入探讨数字存内计算(Processing-In-Memory, PIM)架构,这是突破冯诺依曼瓶颈、大幅降低数据搬移功耗的关键技术。我们将从存储墙问题出发,系统分析SRAM和DRAM两种主流数字PIM实现方案,探讨算子映射策略,并通过Samsung HBM-PIM等工业案例理解实际设计权衡。本章还将深入讨论近数据计算中的缓存一致性挑战,为设计高效能数字PIM系统提供理论和实践指导。
9.1 冯诺依曼瓶颈与存储墙
9.1.1 冯诺依曼架构的根本限制
冯诺依曼架构自1945年提出以来,一直是现代计算机系统的基础。其核心特征是计算单元与存储单元的物理分离,通过总线进行数据交换。这种架构在传统计算中运行良好,但在数据密集型的AI推理任务中暴露出严重的效率问题。
从信息理论角度看,冯诺依曼架构的根本问题在于信息的时空局部性失配。AI推理中的张量运算具有高度的数据并行性,理想情况下应该在数据存储位置就地计算。然而,传统架构强制要求数据必须经过以下路径:
存储器 → 缓存层次 → 寄存器 → ALU → 寄存器 → 缓存层次 → 存储器
这种往返搬移不仅增加延迟,更关键的是消耗大量能量。根据45nm工艺节点的测量数据:
- 32位整数加法:0.1 pJ
- 32位SRAM访问:5 pJ
- 32位DRAM访问:640 pJ
可见,数据搬移的能耗比实际计算高出2-3个数量级。对于具有百亿参数的大模型,仅权重读取就需要数十焦耳的能量,这在边缘设备上是不可接受的。
9.1.2 存储墙的量化分析
存储墙(Memory Wall)问题可以从带宽和功耗两个维度量化分析。我们定义计算强度(Computational Intensity)为:
$$CI = \frac{\text{Operations}}{\text{Memory Access}} \quad [\text{OPs/Byte}]$$ 对于典型的矩阵乘法 $\mathbf{C} = \mathbf{A} \times \mathbf{B}$,其中 $\mathbf{A} \in \mathbb{R}^{M \times K}$,$\mathbf{B} \in \mathbb{R}^{K \times N}$:
- 计算量:$2MNK$ OPs
- 内存访问:$(MK + KN + MN) \times \text{sizeof(datatype)}$ Bytes
当无法充分重用数据时,$CI$ 值很低。以 GEMM 为例,假设 $M=N=K=1024$,使用FP16: $$CI = \frac{2 \times 1024^3}{3 \times 1024^2 \times 2} \approx 341 \text{ OPs/Byte}$$ 而现代GPU的计算吞吐量与内存带宽之比(机器平衡点)为: $$\text{Machine Balance} = \frac{\text{Peak FLOPS}}{\text{Memory Bandwidth}}$$ 以NVIDIA A100为例:
- 峰值FP16性能:312 TFLOPS
- HBM2e带宽:2039 GB/s
- 机器平衡点:$\frac{312 \times 10^{12}}{2039 \times 10^9} \approx 153$ OPs/Byte
当 $CI < \text{Machine Balance}$ 时,系统受内存带宽限制。这解释了为什么许多AI工作负载无法充分利用计算资源。
9.1.3 数据搬移的能耗分解
数据搬移能耗可以分解为多个层次,每个层次的访问能耗呈指数级增长:
寄存器文件 (RF): 0.1-0.5 pJ/access
L1 Cache: 1-5 pJ/access
L2 Cache: 5-20 pJ/access
L3 Cache: 20-50 pJ/access
DRAM: 200-640 pJ/access
Off-chip I/O: 1000-2500 pJ/access
考虑一个简单的向量加法 $\mathbf{c} = \mathbf{a} + \mathbf{b}$,其中向量长度为 $n$:
- 计算能耗:$E_{compute} = n \times E_{add} \approx 0.1n$ pJ
- DRAM访问能耗:$E_{mem} = 3n \times E_{DRAM} \approx 1920n$ pJ
- 能耗比:$\frac{E_{mem}}{E_{compute}} \approx 19200$
这个巨大的差异促使我们重新思考计算架构。数据搬移的能耗还可以用RC模型建模: $$E_{wire} = \alpha \cdot C_{wire} \cdot V_{dd}^2 \cdot L$$ 其中 $C_{wire}$ 是单位长度电容,$L$ 是互连长度,$\alpha$ 是活动因子。随着芯片面积增大,长距离互连的能耗问题愈发严重。
9.1.4 存内计算的基本原理
存内计算(Processing-In-Memory, PIM)通过将计算单元集成到存储阵列中,从根本上消除了数据搬移开销。其核心思想是利用存储阵列的内在并行性执行计算。
数字PIM的基本操作模式包括:
- 行并行计算:同时激活多行,在位线上执行逻辑运算
- 列并行计算:对整行数据并行处理
- 阵列级计算:利用存储阵列作为查找表或计算矩阵
以SRAM为例,传统读操作只激活一行,而PIM模式可以:
传统模式:激活Row[i] → 读取Data[i] → 送至ALU
PIM模式:激活Row[i]和Row[j] → 位线上直接计算AND/OR → 写回Row[k]
这种计算方式的能效优势来自:
- 短距离:计算在存储单元附近完成,互连长度从毫米级降至微米级
- 高并行度:一次操作可处理整行/列数据
- 低电压摆幅:利用位线的小信号特性
存内计算的理论能效极限可以用Landauer原理估算: $$E_{min} = k_B T \ln(2) \approx 2.87 \times 10^{-21} \text{ J/bit} \quad (@300K)$$ 虽然实际电路远未达到这个极限,但相比传统架构已有数量级的改进空间。
9.2 SRAM数字存内计算
9.2.1 SRAM-PIM基本架构
SRAM作为片上存储的主力,具有高速、低延迟的特点,是实现数字PIM的理想载体。标准6T SRAM单元由两个交叉耦合的反相器和两个访问晶体管组成:
VDD VDD
| |
┌─┴─┐ ┌─┴─┐
│MP1│ │MP2│
└─┬─┘ └─┬─┘
├────────┬────────┤
│ │ │
┌─┴─┐ ┌─┴─┐ ┌─┴─┐
WL──┤MN3├────┤ ├────┤MN4├──WL
└───┘ │ Q │ └───┘
└───┘
│ │
┌─┴─┐ ┌─┴─┐
│MN1│ │MN2│
└───┘ └───┘
│ │
GND GND
│ │
BL BLB
在PIM模式下,SRAM阵列不仅存储数据,还执行计算。关键创新在于利用位线(BL)的电荷共享机制实现逻辑运算。基本的SRAM-PIM架构包括:
- 计算使能逻辑:控制多行同时激活
- 感知放大器增强:支持多值检测
- 局部ALU:每列或每几列配置简单运算单元
- 结果缓冲器:暂存中间计算结果
典型的SRAM-PIM操作序列:
1. 预充电位线至VDD/2
2. 同时激活多个字线(WL)
3. 位线电压根据存储值发生变化
4. 感知放大器检测并放大信号
5. 结果写回指定行或输出
这种架构的关键优势是复用现有SRAM结构,仅需少量额外逻辑即可实现PIM功能。
9.2.2 位线计算技术
位线计算是SRAM-PIM的核心技术,通过控制多行激活实现不同的逻辑功能。当两行同时激活时,位线电压由两个单元的存储值共同决定:
对于AND操作:
- Cell1=1, Cell2=1 → BL保持高电平(逻辑1)
- Cell1=0, Cell2=X → BL下拉至低电平(逻辑0)
- Cell1=X, Cell2=0 → BL下拉至低电平(逻辑0)
位线电压可以建模为: $$V_{BL} = V_{pre} + \frac{\Delta Q}{C_{BL}}$$ 其中 $V_{pre}$ 是预充电压,$\Delta Q$ 是电荷变化量,$C_{BL}$ 是位线电容。
更复杂的运算通过级联基本操作实现。例如,全加器可以分解为:
Sum = A ⊕ B ⊕ Cin
Cout = AB + BCin + ACin
每个基本操作映射到一次或多次位线计算。通过精心设计激活序列,可以实现:
- 布尔运算:AND, OR, XOR, NOT
- 算术运算:加法、减法、比较
- 向量运算:点积、归约操作
位线计算的能效优势来自: $$E_{BL-compute} = C_{BL} \cdot V_{DD} \cdot \Delta V \approx 0.5-2 \text{ pJ/op}$$ 相比传统ALU(~10-50 pJ/op),能效提升5-10倍。
9.2.3 多行激活与并行计算
传统SRAM设计中,多行激活会导致位线冲突和数据破坏。PIM设计通过以下技术实现安全的多行激活:
-
弱激活技术:降低字线电压,限制单元驱动能力 $$V_{WL} = V_{DD} - \Delta V_{margin}$$
-
时序控制:精确控制激活时间窗口 $$t_{active} < \frac{C_{BL} \cdot \Delta V_{sense}}{I_{cell}}$$
-
隔离晶体管:在关键路径插入隔离开关
并行度分析:假设SRAM阵列有 $m$ 行 $n$ 列,每次激活 $k$ 行:
- 并行度:$P = n \times k$
- 吞吐量:$T = \frac{n \times k}{t_{cycle}}$ ops/s
- 能效:$\eta = \frac{n \times k \times E_{op}}{P_{total}}$ ops/J
实际设计中,$k$ 的选择需要平衡:
- 过小:并行度不足,未充分利用硬件
- 过大:位线噪声增加,可能导致错误
典型设计选择 $k=2-8$,对应不同的计算模式:
k=2: 基本逻辑运算(AND/OR)
k=3: 三输入函数(全加器)
k=4-8: 复杂函数或查找表
9.2.4 SRAM-PIM的功耗优势
SRAM-PIM的功耗优势可以从多个层面分析:
- 数据搬移消除 传统路径:SRAM → L1 → ALU → L1 → SRAM PIM路径:SRAM内部完成
能耗节省: $$\Delta E = n \times (E_{L1-read} + E_{L1-write} + E_{interconnect}) \approx 10-20 \text{ pJ/op}$$
- 电压摆幅降低 - 传统:全摆幅(0 to VDD) - PIM:小信号(~100-200mV)
功耗降低比例: $$\frac{P_{PIM}}{P_{traditional}} = \left(\frac{\Delta V_{small}}{V_{DD}}\right)^2 \approx 0.01-0.04$$
-
并行计算摊销 固定开销(如译码、时钟)被大量并行操作摊销: $$E_{per-op} = \frac{E_{fixed} + n \times E_{variable}}{n}$$ 当 $n$ 足够大时,$E_{per-op} \to E_{variable}$,接近理论下限。
-
实测功耗对比 以1MB SRAM阵列执行矩阵乘法为例(28nm工艺):
| 指标 | 传统架构 | SRAM-PIM | 改进比 |
| 指标 | 传统架构 | SRAM-PIM | 改进比 |
|---|---|---|---|
| 动态功耗 | 125 mW | 18 mW | 6.9× |
| 静态功耗 | 15 mW | 16 mW | 0.94× |
| 能效 | 0.8 TOPS/W | 5.5 TOPS/W | 6.9× |
| 面积开销 | 基准 | +8% | - |
SRAM-PIM特别适合以下场景:
- 位宽不敏感运算:二值网络、三值网络
- 稀疏激活:ReLU后的特征图
- 局部运算:卷积、池化
- 查找表操作:激活函数、量化/反量化
设计优化建议:
- 采用分层位线减少电容
- 使用本地感知放大器降低延迟
- 实现可配置并行度适应不同工作负载
- 集成压缩解码器直接处理压缩数据
9.3 DRAM-PIM架构(HBM-PIM)
9.3.1 DRAM存储层次与带宽限制
DRAM作为主存储器,容量大但访问延迟高,是系统性能的主要瓶颈。现代DRAM的层次结构为:
Channel → Rank → Chip → Bank → Subarray → Mat → Cell
每一层都引入了带宽限制:
- 通道带宽:受I/O引脚数和频率限制,典型DDR4-3200为25.6 GB/s
- Bank冲突:多个请求访问同一Bank导致串行化
- 行缓冲局部性:频繁的行激活/预充电开销
带宽利用率可以建模为: $$BW_{eff} = BW_{peak} \times \eta_{bus} \times \eta_{bank} \times \eta_{row}$$ 其中:
- $\eta_{bus}$:总线利用率(~70-80%)
- $\eta_{bank}$:Bank并行效率(~60-70%)
- $\eta_{row}$:行缓冲命中率(~50-80%)
实际有效带宽仅为峰值的25-45%。AI工作负载的随机访问模式使情况更糟:
以Transformer的注意力计算为例,访问模式近似随机: $$P(row_miss) = 1 - \frac{1}{n_{rows}} \approx 1 \quad (n_{rows} >> 1)$$ 每次行未命中的开销: $$t_{penalty} = t_{PRE} + t_{ACT} + t_{CAS} \approx 50-60 \text{ ns}$$ 这相当于损失200-240个时钟周期的计算机会。
9.3.2 HBM架构与PIM集成
高带宽内存(HBM)通过3D堆叠和硅通孔(TSV)技术大幅提升带宽:
┌─────────────────┐
│ Logic Die │ ← PIM计算单元
├─────────────────┤
│ DRAM Die 8 │ ← 16个Bank
├─────────────────┤
│ DRAM Die 7 │ 每个Bank:
├─────────────────┤ - 16-32MB容量
│ ... │ - 独立控制
├─────────────────┤ - 局部计算单元
│ DRAM Die 1 │
└─────────────────┘
││││
││││ ← TSV (每个~10-20 μm)
││││
┌─────────────────┐
│ Silicon Inter- │
│ poser │
└─────────────────┘
HBM-PIM的关键创新:
- Bank级PIM单元:每个Bank配置专用计算逻辑
- TSV互连:提供~1TB/s的内部带宽
- 近数据处理:计算单元距离存储阵列<1mm
HBM2E规格(8-Hi堆叠):
- 容量:16GB(8层×2GB)
- 带宽:460 GB/s(1024-bit × 3.6 Gbps)
- Bank数:128个(8层×16 Banks)
- 功耗:~7-10W
PIM集成后的改进: $$Speedup = \frac{BW_{internal}}{BW_{external}} = \frac{1024 \text{ GB/s}}{460 \text{ GB/s}} \approx 2.2×$$ 但更重要的是消除了片外数据传输: $$E_{saved} = n_{ops} \times (E_{HBM-controller} + E_{PHY} + E_{PCB}) \approx 15-20 \text{ pJ/bit}$$
9.3.3 Bank级并行计算
Bank级并行是HBM-PIM的核心优势。每个Bank可以独立执行计算,实现大规模并行:
并行度分析:
- Bank数量:128个
- 每Bank计算单元:16-bit MAC × 16个
- 总并行度:128 × 16 = 2048个并行MAC
Bank内计算架构:
Row Buffer (8KB)
↓
┌─────────────────────────┐
│ 16×16-bit MAC Array │ ← 可编程计算单元
├─────────────────────────┤
│ Local Register File │ ← 256B局部存储
├─────────────────────────┤
│ Control Logic │ ← 指令译码
└─────────────────────────┘
↓
Global I/O
计算模式:
-
SIMD模式:所有Bank执行相同操作 - 适合:矩阵乘法、卷积 - 吞吐量:2048 × 16-bit MAC × 1.2GHz = 4.9 TOPS
-
MIMD模式:各Bank独立操作 - 适合:稀疏运算、不规则访问 - 灵活性高但编程复杂
-
Pipeline模式:Bank间流水线 - 适合:深度网络推理 - 降低中间结果传输
功耗效率分析: $$\eta_{energy} = \frac{E_{compute}}{E_{compute} + E_{access}} = \frac{0.5}{0.5 + 20} \approx 2.4\%$$ PIM后: $$\eta_{energy}^{PIM} = \frac{E_{compute}}{E_{compute} + E_{local}} = \frac{0.5}{0.5 + 2} = 20\%$$ 能效提升约8倍。
9.3.4 DRAM刷新与PIM操作协调
DRAM需要定期刷新以保持数据,这与PIM操作产生冲突。标准DRAM刷新要求:
- 刷新周期:64ms(常温)/ 32ms(高温)
- 刷新时间:~350ns per row
- 刷新开销:~7%的带宽
PIM操作期间的刷新策略:
-
刷新感知调度 将PIM操作划分为可中断的子任务: $$T_{task} < T_{refresh_interval} - T_{refresh_time}$$ 典型值:$T_{task} < 7.8\mu s - 350ns \approx 7.45\mu s$
-
选择性刷新 只刷新包含有效数据的行:
if (row.valid && row.age > threshold):
refresh(row)
else:
skip(row)
可减少30-50%的刷新开销。
-
PIM操作作为隐式刷新 某些PIM操作(如行复制)可以起到刷新作用: $$Refresh_{implicit} = Read_{row} + Write_{row}$$
-
刷新并行化 利用Bank级并行,交错执行刷新和PIM:
Bank0: PIM操作
Bank1: 刷新
Bank2: PIM操作
Bank3: 刷新
...
刷新对PIM性能的影响建模: $$Performance_{degradation} = \frac{T_{refresh}}{T_{window}} \times P_{conflict}$$ 其中 $P_{conflict}$ 是刷新与PIM操作冲突的概率。
优化后的协调机制可将性能损失控制在5%以内,关键技术包括:
- 智能刷新控制器:预测PIM操作模式
- 弹性刷新时序:根据温度和错误率调整
- 刷新-计算融合:将刷新操作扩展为简单计算
9.4 数字PIM的算子映射
将神经网络算子高效映射到PIM硬件是实现性能和能效优势的关键。不同于传统处理器的串行执行模型,PIM需要充分利用存储阵列的内在并行性,同时考虑数据布局、访问模式和硬件约束。本节详细分析主要算子的映射策略,为PIM编译器设计提供理论基础。
9.4.1 矩阵乘法映射策略
矩阵乘法是深度学习的核心算子,占据了推理计算的70-90%。对于矩阵乘法 $\mathbf{C} = \mathbf{A} \times \mathbf{B}$,其中 $\mathbf{A} \in \mathbb{R}^{M \times K}$,$\mathbf{B} \in \mathbb{R}^{K \times N}$,PIM映射需要考虑三个维度的并行化。
- 输出静态映射(Output Stationary)
每个PIM单元负责计算输出矩阵的一个或多个元素: $$C_{ij} = \sum_{k=1}^{K} A_{ik} \times B_{kj}$$ 映射策略:
- 将 $\mathbf{C}$ 的每行分配给一个Bank
- Bank内的MAC阵列计算该行的多个元素
- 输入数据 $\mathbf{A}$ 和 $\mathbf{B}$ 流式传输
Bank[i]负责计算C[i, :]
for k in range(K):
broadcast A[i, k] to all MACs in Bank[i]
load B[k, :] to MAC array
MAC_array += A[i, k] * B[k, :]
优势:输出无需移动,减少写回开销 劣势:输入数据需要广播,增加互连压力
- 权重静态映射(Weight Stationary)
将权重矩阵 $\mathbf{B}$ 预先加载到PIM单元:
每个Bank存储B的若干列
for batch in input_batches:
for i in range(M):
broadcast A[i, :] to all Banks
Bank[j] computes C[i, j] = A[i, :] · B[:, j]
这种映射特别适合推理场景,因为权重是静态的:
- 权重利用率:100%(推理期间不变)
- 激活重用度:$N$(列数)
- 部分和累加:本地完成
能耗分析: $$E_{WS} = M \times (E_{broadcast} + N \times E_{MAC} + N \times E_{accumulate})$$
- 行并行分块策略
对于大矩阵,采用分块策略以适应有限的存储容量: $$\mathbf{C} = \begin{bmatrix} \mathbf{A}_1 \\ \mathbf{A}_2 \\ \vdots \end{bmatrix} \times [\mathbf{B}_1, \mathbf{B}_2, \cdots] = \begin{bmatrix} \mathbf{A}_1\mathbf{B}_1 & \mathbf{A}_1\mathbf{B}_2 & \cdots \\ \mathbf{A}_2\mathbf{B}_1 & \mathbf{A}_2\mathbf{B}_2 & \cdots \\ \vdots & \vdots & \ddots \end{bmatrix}$$ 块大小选择需要平衡:
- 存储容量:$BlockSize \leq \frac{BankCapacity}{DataWidth}$
- 计算效率:$BlockSize \geq \frac{K}{NumBanks}$
- 带宽利用:$BlockSize = n \times CacheLine$
- 稀疏感知映射
对于稀疏矩阵(如剪枝后的权重),采用压缩存储格式:
CSR格式映射:
values[]: 非零元素值
col_idx[]: 列索引
row_ptr[]: 行指针
PIM执行稀疏矩阵乘法:
for i in range(M):
start = row_ptr[i]
end = row_ptr[i+1]
for j in range(start, end):
col = col_idx[j]
val = values[j]
C[i, :] += val * B[col, :] # 只计算非零元素
稀疏度 $s$ 时的加速比: $$Speedup = \frac{1}{1-s} \times \eta_{overhead}$$ 其中 $\eta_{overhead}$ 考虑索引开销,典型值0.7-0.9。
9.4.2 卷积操作的PIM实现
卷积运算可以转换为矩阵乘法(im2col),但这会引入大量数据复制。PIM允许直接在存储器中执行卷积,避免数据重排。
- 直接卷积映射
对于卷积 $Y = X * W$,其中:
- 输入:$X \in \mathbb{R}^{C_{in} \times H \times W}$
- 卷积核:$W \in \mathbb{R}^{C_{out} \times C_{in} \times K_h \times K_w}$
- 输出:$Y \in \mathbb{R}^{C_{out} \times H' \times W'}$
PIM映射策略:
将输入特征图X分布存储在多个Bank
每个Bank负责输出特征图的一个区域
for oc in range(C_out):
for ic in range(C_in):
for kh in range(K_h):
for kw in range(K_w):
weight = W[oc, ic, kh, kw]
# 并行计算所有输出位置
Y[oc, :, :] += weight * X[ic, shifted(kh, kw)]
- 滑窗缓冲优化
利用卷积的滑窗特性,实现数据重用:
Input Feature Map
┌─────────────────┐
│ █ █ █ ░ ░ ░ ░ ░ │ ← 窗口1
│ █ █ █ ░ ░ ░ ░ ░ │
│ █ █ █ ░ ░ ░ ░ ░ │
│ ░ █ █ █ ░ ░ ░ ░ │ ← 窗口2(重用2列)
│ ░ █ █ █ ░ ░ ░ ░ │
│ ░ █ █ █ ░ ░ ░ ░ │
└─────────────────┘
重用率计算: $$Reuse = \frac{K_h \times K_w - 1}{K_h \times K_w} \times 100\%$$ 对于3×3卷积,重用率达88.9%。
- 深度可分离卷积的PIM优化
深度可分离卷积分为深度卷积和逐点卷积两步:
深度卷积(Depthwise):
- 每个通道独立处理
- 自然适合Bank级并行
- 每个Bank处理一个或多个通道
Bank[c]存储Channel[c]的数据
Bank[c]执行: Y_dw[c] = X[c] * W_dw[c]
逐点卷积(Pointwise):
- 转换为1×1卷积
- 等价于矩阵乘法
- 采用9.4.1的映射策略
总计算量降低比: $$\frac{Compute_{DSC}}{Compute_{Conv}} = \frac{1}{C_{out}} + \frac{1}{K^2}$$ 对于 $K=3, C_{out}=256$,计算量降至原来的11.5%。
- Winograd卷积的PIM实现
Winograd算法通过预处理减少乘法次数。对于F(2,3)(2×2输出,3×3卷积核):
变换矩阵: $$B_T = \begin{bmatrix} 1 & 0 & -1 & 0 \\ 0 & 1 & 1 & 0 \\ 0 & -1 & 1 & 0 \\ 0 & 1 & 0 & -1 \end{bmatrix}$$ PIM实现步骤:
- 输入变换:$\tilde{X} = B_T X B$(使用PIM的矩阵运算)
- 权重变换:$\tilde{W} = G W G_T$(离线预计算)
- 逐元素乘法:$\tilde{Y} = \tilde{X} \odot \tilde{W}$(高度并行)
- 输出变换:$Y = A_T \tilde{Y} A$
乘法减少率: $$\frac{Mult_{Winograd}}{Mult_{Direct}} = \frac{(m+r-1)^2}{m^2 r^2}$$ 对于F(2,3):$\frac{16}{36} = 44.4\%$
9.4.3 激活函数与非线性操作
非线性激活函数是神经网络的关键组件,但在PIM中实现较为困难。主要策略包括查找表(LUT)、分段线性近似和专用硬件。
- 查找表实现
将激活函数预计算并存储在SRAM中:
ReLU: LUT[x] = max(0, x)
Sigmoid: LUT[x] = 1/(1+exp(-x))
Tanh: LUT[x] = tanh(x)
地址映射(8-bit量化): $$addr = \lfloor \frac{x - x_{min}}{x_{max} - x_{min}} \times 255 \rfloor$$ 存储开销:
- 8-bit输入/输出:256 Bytes
- 16-bit精度:512 Bytes
- 多函数支持:N × 基础大小
- 分段线性近似
将非线性函数分段线性化: $$f(x) \approx \begin{cases} a_0x + b_0, & x \in [x_0, x_1) \\ a_1x + b_1, & x \in [x_1, x_2) \\ \vdots \\ a_nx + b_n, & x \in [x_n, x_{n+1}) \end{cases}$$ PIM实现:
segment = binary_search(x, breakpoints[])
result = slopes[segment] * x + intercepts[segment]
误差控制: $$\epsilon_{max} = \max_{x \in [x_i, x_{i+1}]} |f(x) - (a_ix + b_i)|$$ 对于ReLU6,只需2段;对于Sigmoid,通常需要4-8段以达到1%精度。
- GELU的高效近似
GELU激活函数:$GELU(x) = x \cdot \Phi(x)$,其中 $\Phi$ 是高斯累积分布函数。
PIM友好的近似: $$GELU(x) \approx 0.5x\left(1 + \tanh\left[\sqrt{\frac{2}{\pi}}\left(x + 0.044715x^3\right)\right]\right)$$ 分解为PIM操作:
- 计算 $x^3$:两次乘法
- 线性组合:$y = x + 0.044715x^3$
- 缩放:$z = 0.7978845y$
- Tanh查表:$t = \tanh(z)$
-
最终计算:$0.5x(1+t)$
-
Softmax的分布式计算
Softmax需要全局归一化:$y_i = \frac{e^{x_i}}{\sum_j e^{x_j}}$
PIM分布式实现:
Step 1: 各Bank计算局部最大值
max_local[bank] = max(x[bank_start:bank_end])
Step 2: 全局归约得到最大值
max_global = max(max_local[:])
Step 3: 计算稳定的指数(避免溢出)
exp_x[i] = exp(x[i] - max_global)
Step 4: 局部求和
sum_local[bank] = sum(exp_x[bank_start:bank_end])
Step 5: 全局归约
sum_global = sum(sum_local[:])
Step 6: 归一化
y[i] = exp_x[i] / sum_global
通信开销:2次全局归约,O(log(NumBanks))
9.4.4 数据布局优化
数据布局直接影响PIM的访问效率和并行度。优化目标是最大化空间局部性和Bank级并行。
- 通道优先 vs 空间优先
两种主要布局方式:
- NCHW:批次-通道-高度-宽度
- NHWC:批次-高度-宽度-通道
PIM偏好分析:
卷积层:NCHW更优(通道间独立计算)
全连接层:NHWC更优(向量化操作)
深度卷积:NHWC更优(通道内计算)
转换开销: $$T_{transform} = \frac{DataSize}{Bandwidth} + N \times T_{permute}$$
- Bank交织策略
将数据交织存储以提高并行度:
传统布局:
Bank0: A[0:1024]
Bank1: A[1024:2048]
...
交织布局:
Bank0: A[0,128,256,...]
Bank1: A[1,129,257,...]
...
交织粒度选择:
- 细粒度(字级):最大并行度,但地址计算复杂
- 粗粒度(页级):简单管理,但可能负载不均
- 自适应:根据访问模式动态调整
- 稀疏数据的紧凑存储
对于稀疏张量,采用压缩格式减少存储和带宽:
COO格式(坐标格式):
values: [1.2, 3.4, 5.6, ...]
rows: [0, 1, 1, ...]
cols: [2, 0, 3, ...]
CSR格式的Bank映射:
Bank[i]存储第i行的非零元素
row_ptr[i]指向Bank[i]的起始位置
动态负载均衡:根据nnz(row)分配Bank
压缩率: $$CompressionRatio = \frac{1}{sparsity} \times \frac{ElementSize}{ElementSize + 2 \times IndexSize}$$ 对于90%稀疏度的FP16矩阵(16-bit索引): $$CR = 10 \times \frac{16}{16 + 32} = 3.33×$$
- 预取与双缓冲
隐藏数据传输延迟的关键技术:
Buffer A: 当前计算数据
Buffer B: 预取下一批数据
while (has_more_data):
parallel:
compute(Buffer A)
prefetch(Buffer B)
swap(Buffer A, Buffer B)
缓冲区大小优化: $$BufferSize = \max(ComputeTime, TransferTime) \times Bandwidth$$ 保证计算和传输完全重叠。
- 数据对齐与填充
PIM硬件通常要求特定的对齐:
对齐要求:64-byte(缓存行)
原始大小:1000 × 1000
填充后:1024 × 1024(2的幂次,便于地址计算)
填充开销: $$OverheadRatio = \frac{AlignedSize - OriginalSize}{OriginalSize}$$
权衡:填充开销 vs 访问效率提升
9.5 工业界案例:Samsung HBM-PIM与UPMEM
本节通过分析两个代表性的商用PIM产品,展示数字存内计算从概念到产品的技术演进。Samsung HBM-PIM代表了高端服务器市场的解决方案,而UPMEM则面向通用计算的大规模部署。
9.5.1 Samsung HBM-PIM架构分析
Samsung HBM-PIM是业界首个量产的HBM集成PIM解决方案,于2021年正式发布。它在标准HBM2 Aquabolt基础上集成了可编程计算单元(PCU),实现了存储与计算的深度融合。
架构概览:
┌─────────────────────────────────┐
│ Host Processor │
└─────────────┬───────────────────┘
│ HBM Interface
┌─────────────┴───────────────────┐
│ Base Logic Die │
│ ┌─────────────────────────┐ │
│ │ Command Processor │ │
│ │ PIM Controller │ │
│ │ Data Router │ │
│ └─────────────────────────┘ │
└─────────────┬───────────────────┘
│ TSV Array (>5000)
┌─────────────┴───────────────────┐
│ DRAM Stack │
│ ┌──────────────────────┐ │
│ │ Bank 0 │ PCU 0 │ │
│ ├──────────────────────┤ │
│ │ Bank 1 │ PCU 1 │ │
│ ├──────────────────────┤ │
│ │ ... │ ... │ │
│ ├──────────────────────┤ │
│ │ Bank 15│ PCU 15 │×8层 │
│ └──────────────────────┘ │
└─────────────────────────────────┘
关键规格:
- 容量:16GB(8层×2GB)
- 带宽:410 GB/s(外部),1.2 TB/s(内部)
- PCU数量:128个(16 Banks × 8层)
- 计算能力:1.2 TFLOPS(FP16)
- 功耗:~20W(包含计算)
PCU微架构:
每个PCU包含:
┌──────────────────────────────┐
│ Bank Row Buffer (8KB) │
├──────────────────────────────┤
│ Programmable MAC Unit │
│ ┌────┬────┬────┬────┐ │
│ │MAC0│MAC1│MAC2│MAC3│ ×4 │
│ └────┴────┴────┴────┘ │
├──────────────────────────────┤
│ Vector Register File │
│ (16 × 256-bit) │
├──────────────────────────────┤
│ Scalar Unit & Control │
└──────────────────────────────┘
MAC单元特性:
- 16-bit定点运算
- 支持INT16/INT8/Binary
- 流水线深度:3级
- 峰值吞吐:16 ops/cycle
编程模型:
Samsung HBM-PIM采用SIMD编程模型,所有PCU执行相同指令:
// PIM指令示例
PIM_MAC(dst, src1, src2, acc); // MAC操作
PIM_ADD(dst, src1, src2); // 向量加法
PIM_RELU(dst, src); // 激活函数
PIM_LOAD(reg, addr); // 从Bank加载
PIM_STORE(addr, reg); // 存储到Bank
编译器自动将高层算子映射到PIM指令序列:
# PyTorch层
output = F.linear(input, weight, bias)
# 编译后的PIM代码
for i in range(0, M, TILE_M):
for j in range(0, N, TILE_N):
PIM_LOAD(R0, weight[i:i+TILE_M])
PIM_LOAD(R1, input[j:j+TILE_N])
PIM_MAC(R2, R0, R1, R2)
PIM_ADD(R2, R2, bias)
PIM_RELU(R2, R2)
PIM_STORE(output[i,j], R2)
性能优化技术:
- Bank级流水线:
时刻t: Bank0执行计算
时刻t+1: Bank0写回,Bank1执行计算
时刻t+2: Bank1写回,Bank2执行计算
-
数据预取机制: - 硬件预取器识别访问模式 - 提前将数据加载到row buffer - 隐藏DRAM访问延迟
-
稀疏加速: - 零值检测单元 - 跳过零权重的MAC操作 - 稀疏度50%时加速1.8×
9.5.2 UPMEM DPU设计
UPMEM是首个商用的通用型PIM处理器,采用标准DDR4 DIMM封装,可直接插入现有服务器。每个DIMM包含多个DPU(DRAM Processing Unit),实现真正的大规模并行计算。
DPU架构:
┌─────────────────────────┐
│ DPU Core (32-bit) │
│ ┌──────────────────┐ │
│ │ 24 GP Registers │ │
│ │ Condition Codes │ │
│ │ Program Counter │ │
│ └──────────────────┘ │
├─────────────────────────┤
│ 14-stage Pipeline │
│ - Fetch (2 stages) │
│ - Decode (2 stages) │
│ - Execute (8 stages) │
│ - Writeback (2 stages) │
├─────────────────────────┤
│ 24KB IRAM │
│ (Instruction RAM) │
├─────────────────────────┤
│ 64KB WRAM │
│ (Working RAM) │
├─────────────────────────┤
│ 64MB MRAM │
│ (Main RAM - DRAM) │
└─────────────────────────┘
关键特性:
- 频率:350-500 MHz
- 指令集:专用RISC ISA
- 并行度:每DIMM 128-256个DPU
- 功耗:~1W per DPU
- 内存带宽:14 GB/s per DPU(内部)
三级存储层次:
-
WRAM(工作内存): - 64KB SRAM - 单周期访问 - 用于频繁访问的数据
-
MRAM(主内存): - 64MB DRAM - ~100周期访问延迟 - DMA传输到WRAM
-
IRAM(指令内存): - 24KB专用指令存储 - 支持循环缓冲优化
编程接口:
UPMEM提供C语言SDK和运行时API:
// Host端代码
#include <dpu.h>
struct dpu_set_t dpu_set;
DPU_ASSERT(dpu_alloc(NR_DPUS, NULL, &dpu_set));
// 加载程序到DPU
DPU_ASSERT(dpu_load(dpu_set, DPU_BINARY, NULL));
// 广播数据到所有DPU
DPU_FOREACH(dpu_set, dpu) {
DPU_ASSERT(dpu_copy_to(dpu, "input_data", 0,
&input[dpu_id], size));
}
// 启动DPU执行
DPU_ASSERT(dpu_launch(dpu_set, DPU_SYNCHRONOUS));
// 收集结果
DPU_FOREACH(dpu_set, dpu) {
DPU_ASSERT(dpu_copy_from(dpu, "output_data", 0,
&output[dpu_id], size));
}
DPU端核心代码:
// DPU端代码
#include <mram.h>
#include <perfcounter.h>
__mram_noinit uint8_t input_data[INPUT_SIZE];
__mram_noinit uint8_t output_data[OUTPUT_SIZE];
int main() {
// 从MRAM加载到WRAM
mram_read(input_data, wram_buffer, size);
// 执行计算
for (int i = 0; i < size; i++) {
result[i] = process(wram_buffer[i]);
}
// 写回MRAM
mram_write(result, output_data, size);
return 0;
}
性能优化策略:
-
WRAM管理: - 双缓冲技术 - 软件流水线 - 数据预取
-
DPU间通信: - 通过host中转 - 批量同步减少开销 - 局部归约优化
-
负载均衡: - 静态任务划分 - 工作窃取机制 - 动态重分配
9.5.3 性能与功耗评估
Samsung HBM-PIM性能分析:
在实际AI工作负载上的表现:
| 工作负载 | 传统HBM | HBM-PIM | 加速比 | 能效提升 |
| 工作负载 | 传统HBM | HBM-PIM | 加速比 | 能效提升 |
|---|---|---|---|---|
| BERT-Base | 100ms | 35ms | 2.86× | 2.3× |
| ResNet-50 | 15ms | 8ms | 1.88× | 1.6× |
| LSTM | 120ms | 28ms | 4.29× | 3.8× |
| Recommendation | 80ms | 18ms | 4.44× | 4.1× |
性能提升来源分析:
- 带宽提升贡献:40%
- 数据搬移减少:35%
- 并行度提升:25%
功耗分解(20W总功耗):
DRAM刷新: 3W (15%)
DRAM访问: 5W (25%)
PIM计算: 8W (40%)
控制逻辑: 2W (10%)
I/O接口: 2W (10%)
UPMEM DPU性能评估:
基准测试结果(256 DPU系统):
| 应用类型 | CPU基线 | UPMEM | 加速比 | 能效比 |
| 应用类型 | CPU基线 | UPMEM | 加速比 | 能效比 |
|---|---|---|---|---|
| 基因组分析 | 1.0× | 12.5× | 12.5× | 8.7× |
| 数据库Join | 1.0× | 3.8× | 3.8× | 15.2× |
| 图遍历 | 1.0× | 5.2× | 5.2× | 10.1× |
| 稀疏矩阵 | 1.0× | 7.6× | 7.6× | 12.3× |
扩展性分析:
DPU数量 吞吐量 效率
1 1.0× 100%
16 15.2× 95%
64 58.8× 92%
256 225× 88%
1024 860× 84%
对比分析:
| 特性 | Samsung HBM-PIM | UPMEM DPU |
| 特性 | Samsung HBM-PIM | UPMEM DPU |
|---|---|---|
| 目标市场 | AI加速 | 通用计算 |
| 集成度 | 高(HBM内) | 中(DDR4) |
| 编程模型 | SIMD | MIMD |
| 单位算力 | 高 | 中 |
| 灵活性 | 低 | 高 |
| 部署成本 | 高 | 低 |
9.5.4 应用场景与局限性
Samsung HBM-PIM适用场景:
-
推荐系统: - 大规模embedding查表 - 稀疏特征交叉 - 内存带宽密集
-
自然语言处理: - Attention计算 - 大词表softmax - Beam search
-
科学计算: - 稀疏线性代数 - 图神经网络 - 分子动力学模拟
UPMEM DPU适用场景:
-
数据库加速: - 并行扫描 - Hash join - 聚合操作
-
生物信息学: - 序列比对 - 基因组装 - 变异检测
-
数据分析: - 时间序列处理 - 模式匹配 - 数据压缩
技术局限性:
-
编程复杂性: - 需要重写算法 - 数据布局优化困难 - 调试工具不完善
-
硬件约束: - 固定的计算能力 - 有限的局部存储 - 缺乏浮点支持(部分产品)
-
生态系统: - 软件栈不成熟 - 缺乏标准化接口 - 有限的框架支持
-
成本效益: - 初期投资高 - 需要专门优化 - ROI周期长
未来发展方向:
-
标准化: - 统一编程模型 - 标准化接口(如CXL) - 开放生态系统
-
架构演进: - 支持更复杂运算 - 改进互连架构 - 集成专用加速器
-
软件优化: - 自动并行化编译器 - 高层抽象框架 - 性能分析工具
-
应用拓展: - 边缘AI推理 - 实时分析 - 新兴工作负载