第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的基本操作模式包括:

  1. 行并行计算:同时激活多行,在位线上执行逻辑运算
  2. 列并行计算:对整行数据并行处理
  3. 阵列级计算:利用存储阵列作为查找表或计算矩阵

以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架构包括:

  1. 计算使能逻辑:控制多行同时激活
  2. 感知放大器增强:支持多值检测
  3. 局部ALU:每列或每几列配置简单运算单元
  4. 结果缓冲器:暂存中间计算结果

典型的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设计通过以下技术实现安全的多行激活:

  1. 弱激活技术:降低字线电压,限制单元驱动能力 $$V_{WL} = V_{DD} - \Delta V_{margin}$$

  2. 时序控制:精确控制激活时间窗口 $$t_{active} < \frac{C_{BL} \cdot \Delta V_{sense}}{I_{cell}}$$

  3. 隔离晶体管:在关键路径插入隔离开关

并行度分析:假设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的功耗优势可以从多个层面分析:

  1. 数据搬移消除 传统路径: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}$$

  1. 电压摆幅降低 - 传统:全摆幅(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$$

  1. 并行计算摊销 固定开销(如译码、时钟)被大量并行操作摊销: $$E_{per-op} = \frac{E_{fixed} + n \times E_{variable}}{n}$$ 当 $n$ 足够大时,$E_{per-op} \to E_{variable}$,接近理论下限。

  2. 实测功耗对比 以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后的特征图
  • 局部运算:卷积、池化
  • 查找表操作:激活函数、量化/反量化

设计优化建议:

  1. 采用分层位线减少电容
  2. 使用本地感知放大器降低延迟
  3. 实现可配置并行度适应不同工作负载
  4. 集成压缩解码器直接处理压缩数据

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的关键创新:

  1. Bank级PIM单元:每个Bank配置专用计算逻辑
  2. TSV互连:提供~1TB/s的内部带宽
  3. 近数据处理:计算单元距离存储阵列<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

计算模式:

  1. SIMD模式:所有Bank执行相同操作 - 适合:矩阵乘法、卷积 - 吞吐量:2048 × 16-bit MAC × 1.2GHz = 4.9 TOPS

  2. MIMD模式:各Bank独立操作 - 适合:稀疏运算、不规则访问 - 灵活性高但编程复杂

  3. 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操作期间的刷新策略:

  1. 刷新感知调度 将PIM操作划分为可中断的子任务: $$T_{task} < T_{refresh_interval} - T_{refresh_time}$$ 典型值:$T_{task} < 7.8\mu s - 350ns \approx 7.45\mu s$

  2. 选择性刷新 只刷新包含有效数据的行:

if (row.valid && row.age > threshold):
    refresh(row)
else:
    skip(row)

可减少30-50%的刷新开销。

  1. PIM操作作为隐式刷新 某些PIM操作(如行复制)可以起到刷新作用: $$Refresh_{implicit} = Read_{row} + Write_{row}$$

  2. 刷新并行化 利用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映射需要考虑三个维度的并行化。

  1. 输出静态映射(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, :]

优势:输出无需移动,减少写回开销 劣势:输入数据需要广播,增加互连压力

  1. 权重静态映射(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})$$

  1. 行并行分块策略

对于大矩阵,采用分块策略以适应有限的存储容量: $$\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$
  1. 稀疏感知映射

对于稀疏矩阵(如剪枝后的权重),采用压缩存储格式:

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允许直接在存储器中执行卷积,避免数据重排。

  1. 直接卷积映射

对于卷积 $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)]
  1. 滑窗缓冲优化

利用卷积的滑窗特性,实现数据重用:

     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%。

  1. 深度可分离卷积的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%。

  1. 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实现步骤:

  1. 输入变换:$\tilde{X} = B_T X B$(使用PIM的矩阵运算)
  2. 权重变换:$\tilde{W} = G W G_T$(离线预计算)
  3. 逐元素乘法:$\tilde{Y} = \tilde{X} \odot \tilde{W}$(高度并行)
  4. 输出变换:$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)、分段线性近似和专用硬件。

  1. 查找表实现

将激活函数预计算并存储在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 × 基础大小
  1. 分段线性近似

将非线性函数分段线性化: $$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%精度。

  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操作:

  1. 计算 $x^3$:两次乘法
  2. 线性组合:$y = x + 0.044715x^3$
  3. 缩放:$z = 0.7978845y$
  4. Tanh查表:$t = \tanh(z)$
  5. 最终计算:$0.5x(1+t)$

  6. 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级并行。

  1. 通道优先 vs 空间优先

两种主要布局方式:

  • NCHW:批次-通道-高度-宽度
  • NHWC:批次-高度-宽度-通道

PIM偏好分析:

卷积层:NCHW更优(通道间独立计算)
全连接层:NHWC更优(向量化操作)
深度卷积:NHWC更优(通道内计算)

转换开销: $$T_{transform} = \frac{DataSize}{Bandwidth} + N \times T_{permute}$$

  1. Bank交织策略

将数据交织存储以提高并行度:

传统布局:
Bank0: A[0:1024]
Bank1: A[1024:2048]
...

交织布局:
Bank0: A[0,128,256,...]
Bank1: A[1,129,257,...]
...

交织粒度选择:

  • 细粒度(字级):最大并行度,但地址计算复杂
  • 粗粒度(页级):简单管理,但可能负载不均
  • 自适应:根据访问模式动态调整
  1. 稀疏数据的紧凑存储

对于稀疏张量,采用压缩格式减少存储和带宽:

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×$$

  1. 预取与双缓冲

隐藏数据传输延迟的关键技术:

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$$ 保证计算和传输完全重叠。

  1. 数据对齐与填充

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)

性能优化技术:

  1. Bank级流水线:
时刻t:   Bank0执行计算
时刻t+1: Bank0写回Bank1执行计算
时刻t+2: Bank1写回Bank2执行计算
  1. 数据预取机制: - 硬件预取器识别访问模式 - 提前将数据加载到row buffer - 隐藏DRAM访问延迟

  2. 稀疏加速: - 零值检测单元 - 跳过零权重的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(内部)

三级存储层次:

  1. WRAM(工作内存): - 64KB SRAM - 单周期访问 - 用于频繁访问的数据

  2. MRAM(主内存): - 64MB DRAM - ~100周期访问延迟 - DMA传输到WRAM

  3. 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;
}

性能优化策略:

  1. WRAM管理: - 双缓冲技术 - 软件流水线 - 数据预取

  2. DPU间通信: - 通过host中转 - 批量同步减少开销 - 局部归约优化

  3. 负载均衡: - 静态任务划分 - 工作窃取机制 - 动态重分配

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适用场景:

  1. 推荐系统: - 大规模embedding查表 - 稀疏特征交叉 - 内存带宽密集

  2. 自然语言处理: - Attention计算 - 大词表softmax - Beam search

  3. 科学计算: - 稀疏线性代数 - 图神经网络 - 分子动力学模拟

UPMEM DPU适用场景:

  1. 数据库加速: - 并行扫描 - Hash join - 聚合操作

  2. 生物信息学: - 序列比对 - 基因组装 - 变异检测

  3. 数据分析: - 时间序列处理 - 模式匹配 - 数据压缩

技术局限性:

  1. 编程复杂性: - 需要重写算法 - 数据布局优化困难 - 调试工具不完善

  2. 硬件约束: - 固定的计算能力 - 有限的局部存储 - 缺乏浮点支持(部分产品)

  3. 生态系统: - 软件栈不成熟 - 缺乏标准化接口 - 有限的框架支持

  4. 成本效益: - 初期投资高 - 需要专门优化 - ROI周期长

未来发展方向:

  1. 标准化: - 统一编程模型 - 标准化接口(如CXL) - 开放生态系统

  2. 架构演进: - 支持更复杂运算 - 改进互连架构 - 集成专用加速器

  3. 软件优化: - 自动并行化编译器 - 高层抽象框架 - 性能分析工具

  4. 应用拓展: - 边缘AI推理 - 实时分析 - 新兴工作负载

9.6 高级话题:近数据计算的缓存一致性

9.6.1 缓存一致性协议挑战

9.6.2 PIM感知的缓存管理

9.6.3 虚拟内存与地址转换

9.6.4 多核PIM系统的同步机制

本章小结

练习题

常见陷阱与错误

最佳实践检查清单