在前面的章节中,我们深入探讨了以TPU为代表的脉动阵列架构,其通过规则的数据流动模式和高度优化的矩阵运算单元实现了卓越的能效比。然而,随着AI模型日益复杂化和多样化,特别是在自动驾驶和具身智能场景中,工作负载呈现出更加动态和异构的特征。本章将介绍另一种重要的NPU架构范式——数据流架构,并以Groq的Tensor Streaming Processor (TSP)为例,分析其如何通过编译时确定性调度和片上大容量存储实现极低延迟和可预测的性能。通过对比数据流架构与脉动阵列的设计理念差异,读者将能够根据具体应用场景选择合适的架构方案。
数据流架构的核心价值在于其能够暴露计算的内在并行性,消除传统冯·诺依曼架构中的控制流瓶颈。在自动驾驶场景中,感知、预测和规划任务往往具有不同的计算特征和实时性要求,数据流架构能够通过细粒度的资源调度和确定性执行保证满足这些异构需求。对于具身智能应用,VLM/VLA模型需要处理多模态输入并产生实时控制输出,数据流架构的灵活性和低延迟特性使其成为理想选择。
本章将从数据流计算的基础理论出发,深入分析其执行机制和优化方法,然后详细介绍Groq TSP的创新设计,最后通过与脉动阵列的全面对比,帮助读者建立选择和设计数据流架构NPU的能力。
数据流计算模型起源于20世纪70年代,其核心思想是将计算表示为有向图,数据在图中的节点间流动并触发计算。与传统的冯·诺依曼架构依赖程序计数器顺序执行不同,数据流架构中的操作仅在其输入数据就绪时执行,天然支持细粒度并行。这一范式的理论基础可以追溯到Petri网和Kahn过程网络,它们为并发计算提供了严格的数学模型。
数据流计算的历史演进反映了计算机体系结构对并行性的不断追求。早期的MIT Tagged-Token Dataflow Architecture (1970s)和Manchester Dataflow Computer (1980s)奠定了理论基础,虽然受限于当时的工艺技术未能商业化成功,但其思想深刻影响了后续的并行计算架构。进入21世纪,随着晶体管密度的持续增长和功耗墙的出现,数据流思想在专用加速器领域重新焕发生机,Google的TPU采用了脉动阵列这一特殊的数据流形式,而Groq的TSP则代表了纯数据流架构的现代实现。
这种计算范式的革命性在于它从根本上改变了程序执行的控制方式。在冯·诺依曼架构中,指令的执行顺序由程序计数器严格控制,即使两条指令之间没有数据依赖关系,它们也必须按照程序顺序执行。这种顺序执行模型可以用状态转移函数表示:
\[S_{t+1} = f(S_t, I_t)\]其中$S_t$是时刻$t$的机器状态,$I_t$是当前指令。而在数据流架构中,执行模型可以表示为:
\[O_i = g_i(I_{i,1}, I_{i,2}, ..., I_{i,k})\]其中操作$i$的输出$O_i$仅依赖于其输入集合${I_{i,j}}$,与全局状态无关。这种无状态计算模型消除了指令间的人为顺序约束,使得所有数据独立的操作可以并发执行。
指令级并行度(ILP)的理论上界由数据依赖图的宽度决定。设图$G=(V,E)$的反链(antichain)集合为$\mathcal{A}$,则最大并行度:
\[ILP_{max} = \max_{A \in \mathcal{A}} |A|\]其中反链是指图中两两之间不存在路径的节点集合。这个理论上界在数据流架构中可以充分利用,而在传统架构中由于控制流约束通常只能达到其一小部分。
为了更深入理解这个概念,考虑一个实际的神经网络层的并行度分析。对于一个Transformer的Multi-Head Attention层,假设有8个注意力头,每个头的计算包括Q、K、V投影和注意力计算。在传统架构中,这些计算通常顺序执行或受限于指令发射宽度(如4-8条指令/周期)。而在数据流架构中,理论上8个头的24个投影矩阵乘法可以同时执行,实际并行度仅受硬件资源限制。数学上,若每个投影需要$d_{model} \times d_k$次乘累加操作,总并行度可达:
\[P_{MHA} = 8 \times 3 \times d_{model} \times d_k = 24 \times 512 \times 64 = 786,432\]这种大规模并行在数据流架构中通过合理的资源分配和调度可以接近实现。
数据流计算模型的另一个重要优势是其固有的确定性。由于执行顺序完全由数据依赖关系决定,相同的输入总是产生相同的执行序列和输出结果。这种确定性可以形式化为幂等性质:
\[\forall x \in X: f^n(x) = f(x), n \geq 1\]| 这种确定性对于安全关键应用(如自动驾驶)至关重要,因为它简化了系统验证和认证过程。形式化验证的状态空间从指数级$O(2^{ | S | })$降低到多项式级$O( | V | \cdot | E | )$,其中$ | S | $是状态空间大小,$ | V | $和$ | E | $分别是节点和边的数量。此外,确定性执行还带来了功耗优化的机会,因为编译器可以精确预测每个单元的活动时间,从而实现激进的时钟门控和功耗管理策略。 |
确定性的价值在自动驾驶场景中尤为突出。考虑一个紧急制动场景,系统必须在检测到障碍物后的100ms内做出反应。在非确定性系统中,由于缓存未命中、DRAM刷新、操作系统调度等因素,同样的感知-决策-控制流程可能在50-150ms之间变化。这种不确定性要求系统按最坏情况设计,导致过度保守。而数据流架构的确定性执行可以保证:
\[T_{response} = T_{sensor} + T_{perception} + T_{planning} + T_{control} = 10 + 40 + 30 + 20 = 100ms \pm 0.1ms\]这种亚毫秒级的抖动对于满足ISO 26262等功能安全标准至关重要。
数据流图(Dataflow Graph, DFG)是数据流架构的核心抽象,由节点(nodes)和边(edges)组成。形式化定义为有向图$G = (V, E, \phi, \psi)$,其中:
这种图表示方法不仅直观地展示了计算的结构,更重要的是它精确地定义了执行语义,使得硬件实现和编译器优化都有明确的目标。
数据流图的表示能力是其被广泛采用的关键原因。从理论角度看,数据流图是图灵完备的,能够表示任意可计算函数。更重要的是,它天然地暴露了计算中的并行机会。考虑一个简单的向量点积运算$c = \sum_{i=1}^{n} a_i \times b_i$,在传统指令流中表现为循环,而在数据流图中展开为n个独立的乘法节点和一个归约树,立即显示出$O(n)$的数据并行和$O(\log n)$的归约并行。这种显式的并行表示使得编译器和硬件都能够更有效地利用可用资源。
节点定义与分类
节点是数据流图的基本计算单元,每个节点$v \in V$封装了一个特定的操作。节点的形式化定义为元组:
\[v = (id, op, I, O, \tau, \sigma)\]其中:
根据功能和复杂度,节点可以分为多个层次:
节点层次的设计反映了硬件实现和编程抽象之间的权衡。在自动驾驶场景中,感知网络主要使用算子节点(如PointPillars的3D卷积),而规划算法可能需要更多控制节点(如A*搜索的条件分支)。具身智能的VLA模型则混合使用各层次节点,视觉编码器使用算子节点,语言模型使用复合节点,动作生成使用控制节点。这种层次化设计允许编译器针对不同节点类型采用专门的优化策略。
每个节点的内部结构包含四个关键组件:
触发条件(Firing Rule):定义激活逻辑 \(fire(v) = \begin{cases} true & \text{if } \forall i_j \in I: available(i_j) \geq required(i_j) \\ false & \text{otherwise} \end{cases}\)
计算函数(Compute Function):定义操作语义 \(f_v: \prod_{j=1}^{|I|} \mathcal{T}(i_j) \rightarrow \prod_{k=1}^{|O|} \mathcal{T}(o_k)\)
| 延迟模型:$d(v) = d_{fixed} + d_{variable}( | data | )$ |
节点的粒度选择是设计中的关键权衡,可以通过成本模型量化:
\[Cost(g) = \alpha \cdot Complexity(g) + \beta \cdot Overhead(g) - \gamma \cdot Parallelism(g)\]其中:
| $Complexity(g) = | V_g | + | E_g | $:图复杂度 |
实际设计中,粒度选择还需考虑目标硬件的特性。以200 TOPS的NPU设计为例,假设有1000个MAC单元,每个运行在1GHz。若采用细粒度设计(每个MAC作为一个节点),图规模达到$10^6$节点级别,编译时间可能超过小时。若采用粗粒度设计(整个矩阵乘法作为节点),虽然图规模降到$10^2$级别,但失去了细粒度调度的灵活性。实践中的最优选择通常是中等粒度,如将$32 \times 32$的矩阵块作为基本节点,这样既保持了合理的图规模($10^3-10^4$节点),又能有效利用硬件并行性。
细粒度节点(如单个乘法器):
粗粒度节点(如整个卷积层):
现代数据流架构通常采用层次化的节点设计,通过多级粒度优化总成本:
\[g_{optimal} = \arg\min_g Cost(g) \text{ s.t. } Resources(g) \leq R_{available}\]边的属性与语义
边不仅仅是简单的连线,它承载了丰富的语义信息。每条边$e = (u, v) \in E$定义了一个生产者-消费者关系,其形式化定义为:
\[e = (src, dst, type, capacity, latency, policy)\]其中:
类型系统设计
| 数据类型系统的复杂度影响硬件开销和编译效率。静态类型系统的类型检查复杂度为$O( | E | )$,而动态类型系统需要运行时开销: |
类型推断可以通过Hindley-Milner算法实现,复杂度为$O(n \cdot \alpha(n))$,其中$\alpha$是逆Ackermann函数。
缓冲深度优化
缓冲深度$B_e$的选择需要平衡性能和面积:
\[B_{optimal} = \arg\min_B [Area(B) + \lambda \cdot Latency(B)]\]其中延迟模型: \(Latency(B) = \begin{cases} 0 & \text{if } B \geq \Delta_{rate} \times T_{burst} \\ \frac{\Delta_{rate} \times T_{burst} - B}{throughput} & \text{otherwise} \end{cases}\)
| $\Delta_{rate} = | production_rate - consumption_rate | $是速率差异。 |
传输延迟分析
端到端延迟包含多个组成部分: \(L_{e2e} = L_{prop} + L_{trans} + L_{queue} + L_{proc}\)
其中:
| 在片上网络中,Manhattan距离$d = | x_1 - x_2 | + | y_1 - y_2 | $决定了跳数,每跳延迟约1-2个周期。 |
延迟优化在实时系统中至关重要。以自动驾驶的传感器融合为例,相机数据(30fps,延迟33ms)、LiDAR数据(10Hz,延迟100ms)和Radar数据(20Hz,延迟50ms)需要时间对齐。数据流架构可以通过精确的延迟控制实现同步:
\[t_{sync} = \max(t_{camera} + L_{camera}, t_{lidar} + L_{lidar}, t_{radar} + L_{radar})\]通过在数据流图中插入可编程延迟节点,编译器可以自动平衡不同路径的延迟,确保数据在融合点同步到达。这种确定性的延迟控制是数据流架构相对于传统架构的重要优势。
触发规则的设计空间
触发规则定义了节点何时可以执行,这是数据流语义的核心。触发条件可以形式化为谓词函数:
\[\mathcal{F}: V \times \mathcal{S} \rightarrow \{true, false\}\]其中$\mathcal{S}$是系统状态空间。不同的触发规则导致不同的执行行为:
严格触发(Strict Firing): \(\mathcal{F}_{strict}(v, s) = \bigwedge_{i \in inputs(v)} available(i, s)\)
硬件复杂度:$O(|inputs|)$的AND门 吞吐量损失:$T_{loss} = \max_i T_i - \bar{T}$,其中$T_i$是输入$i$的到达时间
松散触发(Lenient Firing): \(\mathcal{F}_{lenient}(v, s) = \bigvee_{S \subseteq inputs(v), |S| \geq k} \bigwedge_{i \in S} available(i, s)\)
| 其中$k$是最小输入数。硬件复杂度:$O(\binom{ | inputs | }{k})$ |
条件触发(Conditional Firing): \(\mathcal{F}_{cond}(v, s) = predicate(data\_values(inputs(v))) \land \mathcal{F}_{strict}(v, s)\)
分支预测准确率影响:$IPC_{effective} = IPC_{ideal} \times (1 - penalty \times miss_rate)$
周期触发(Periodic Firing): \(\mathcal{F}_{periodic}(v, s) = (clock(s) \mod period(v) = 0)\)
功耗影响:$P_{periodic} = f_{trigger} \times E_{op}$,即使输入未就绪也消耗能量
触发规则的选择准则
选择最优触发规则需要考虑:
考虑一个简单的表达式 $z = (a + b) \times c$,其数据流图表示和执行分析:
a ──┐
├─[+]─── temp ──┐
b ──┘ ├─[×]─── z
c ─────┘
执行时序分析
假设输入到达时间:$t_a = 0, t_b = 1, t_c = 0$,操作延迟:$d_{add} = 2, d_{mul} = 3$
执行调度:
关键路径:$CP = {b \rightarrow add \rightarrow mul \rightarrow z}$,长度为$1 + 2 + 3 = 6$
资源利用率分析
设系统有1个加法器和1个乘法器:
这种异步执行模式的优势在于:
数据依赖与并行性分析
数据流图的一个关键优势是它明确地暴露了所有的数据依赖关系。依赖关系可以通过可达性矩阵$R$表示:
\[R_{ij} = \begin{cases} 1 & \text{if } \exists \text{ path from } v_i \text{ to } v_j \\ 0 & \text{otherwise} \end{cases}\]| 传递闭包可通过Floyd-Warshall算法计算,复杂度$O( | V | ^3)$。 |
并行性层次分析
任务级并行(Task-Level Parallelism, TLP)
独立子图识别算法: \(Components = ConnectedComponents(G)\) \(TLP = |Components|\)
在自动驾驶系统中的量化:
数据级并行(Data-Level Parallelism, DLP)
对于张量操作$T \in \mathbb{R}^{d_1 \times d_2 \times … \times d_n}$: \(DLP = \prod_{i=1}^{n} d_i\)
矩阵乘法$C = A \times B$的并行分解: \(C_{ij} = \sum_{k=1}^{K} A_{ik} \times B_{kj}\)
可并行的乘累加操作数:$DLP_{GEMM} = M \times N$
SIMD效率:$\eta_{SIMD} = \frac{vector_length}{\lceil \frac{data_size}{vector_length} \rceil \times vector_length}$
流水线并行(Pipeline Parallelism)
对于$L$级流水线,稳态吞吐量: \(Throughput = \frac{1}{\max_{i \in [1,L]} latency_i}\)
流水线效率: \(\eta_{pipeline} = \frac{\sum_{i=1}^{L} latency_i}{L \times \max_i latency_i}\)
启动延迟:$T_{startup} = \sum_{i=1}^{L} latency_i$ 填充率:$Fill_rate = \frac{N}{N + L - 1}$,其中$N$是处理的数据批次
并行度的定量分析
并行度分析是评估架构效率的核心。设图 $G = (V, E)$,其中节点 $v \in V$ 的计算延迟为 $d(v)$。
关键路径分析
关键路径通过动态规划计算: \(T_{critical} = \max_{v \in V} EST(v) + d(v)\)
其中最早开始时间(EST)递归定义: \(EST(v) = \begin{cases} 0 & \text{if } v \text{ is source} \\ \max_{u \in pred(v)} [EST(u) + d(u)] & \text{otherwise} \end{cases}\)
多维并行度模型
理想并行度(Ideal Parallelism): \(P_{ideal} = \frac{W}{T_{critical}} = \frac{\sum_{v \in V} d(v)}{T_{critical}}\)
这是Brent定理的上界,表示无限资源下的最大加速比。
资源受限并行度(Resource-Constrained Parallelism): \(P_{resource} = \min\left(P_{ideal}, \sum_{r \in R} N_r\right)\)
其中$N_r$是资源类型$r$的数量。
带宽受限并行度(Bandwidth-Constrained Parallelism):
使用Little’s Law:$P_{bandwidth} = BW \times L$
其中$BW$是带宽,$L$是平均延迟。对于计算密集型: \(P_{bandwidth} = \frac{BW_{memory}}{bytes\_per\_op \times ops\_per\_second}\)
通信受限并行度(Communication-Constrained Parallelism):
基于BSP模型: \(P_{communication} = \frac{W}{W/p + g \cdot h + l}\)
其中$p$是处理器数,$g$是带宽因子,$h$是通信量,$l$是同步延迟。
有效并行度综合模型
\[P_{effective} = \left(\frac{1}{P_{ideal}} + \frac{1}{P_{resource}} + \frac{1}{P_{bandwidth}} + \frac{1}{P_{communication}}\right)^{-1}\]这是调和平均数,反映了最弱环节的限制作用。
Amdahl定律的数据流扩展
\[Speedup = \frac{1}{(1-f) + \frac{f}{P_{effective}} + \alpha \cdot \log P_{effective}}\]其中$\alpha \cdot \log P_{effective}$项表示调度和同步开销。
图优化与变换
数据流图的显式表示使得各种优化技术可以系统地应用。常见的图优化包括节点融合、节点分裂、重调度和数据布局优化。
节点融合将多个细粒度节点合并为一个粗粒度节点,减少中间数据的存储和传输开销。例如,将批归一化的多个操作(减均值、除标准差、缩放、偏移)融合为单个节点,可以显著减少内存访问。融合的收益可以量化为:
\[Benefit_{fusion} = Cost_{separate} - Cost_{fused} = \sum_{i} (M_i \times BW_i) - M_{fused} \times BW_{fused}\]其中$M_i$是各个节点的内存访问量,$BW_i$是对应的带宽成本。
节点分裂则是相反的操作,将复杂节点分解为简单节点以增加并行机会。这在处理大规模矩阵运算时特别有用,可以将其分解为多个可以并行执行的子矩阵运算。分裂的关键是找到最优的分割点,使得负载均衡的同时最小化通信开销。
数据流架构的一个根本性设计选择是采用静态还是动态的执行模型。这个选择不仅影响硬件复杂度和性能特征,更决定了系统能够高效支持的工作负载类型。理解这两种模型的本质差异和适用场景,对于选择和设计合适的NPU架构至关重要。
静态数据流的理论基础
静态数据流模型源于同步数据流(Synchronous Dataflow, SDF)理论,这是一个在数字信号处理领域广泛应用的计算模型。在SDF中,每个节点在每次执行时消耗和产生固定数量的令牌,这使得整个系统的行为在编译时完全可预测。
静态数据流的核心约束可以形式化表示为单赋值规则:每条边在任意时刻最多包含一个有效数据。数学上,这可以表示为:
\[\forall e \in E, \forall t \in T: tokens(e, t) \leq 1\]其中 $tokens(e, t)$ 表示时刻 $t$ 边 $e$ 上的令牌数。这个约束看似简单,却带来了深远的影响。
首先,它保证了执行的确定性。由于每个数据只能被产生和消费一次,不存在竞争条件或不确定的执行顺序。这使得系统的行为完全可预测,相同的输入总是产生相同的输出和相同的执行轨迹。对于安全关键应用如自动驾驶,这种确定性是系统认证的基础。
其次,单赋值规则简化了硬件实现。不需要复杂的标签匹配单元来区分不同迭代的数据,不需要关联存储器来缓存多个令牌,也不需要动态调度器来决定执行顺序。所有的调度决策都在编译时完成,运行时硬件只需要按照预定的时间表执行即可。
静态调度的编译过程本质上是求解一个约束满足问题。给定数据流图$G=(V,E)$和资源约束$R$,需要找到一个调度函数$S: V \rightarrow T$,将每个节点映射到执行时刻,满足:
这个问题在一般情况下是NP完全的,但通过启发式算法如列表调度、模拟退火或整数线性规划,可以找到接近最优的解。
静态数据流的优势在实际系统中表现显著。零运行时调度开销意味着所有的硬件资源都用于实际计算,而不是控制和协调。时序的完全可预测性使得功耗管理可以做到极致,编译器可以精确地插入时钟门控和电源门控指令。形式化验证变得可行,因为状态空间是有限和确定的。
然而,静态模型也有其固有局限。最大的挑战是处理动态行为,如数据依赖的控制流、可变长度的循环、递归调用等。虽然可以通过保守的静态分析和最坏情况假设来处理这些情况,但会导致资源利用率低下。例如,对于一个条件执行的分支,静态调度必须为两个分支都预留资源和时间,即使实际执行中只会选择一个分支。
动态数据流的演进与创新
动态数据流模型的发展历程反映了计算机体系结构对灵活性和效率平衡的不断探索。早期的MIT Tagged-Token架构和Manchester Dataflow Machine为这一领域奠定了理论基础,而现代的动态数据流设计则在此基础上进行了诸多创新。
动态数据流的核心创新是引入了标签(tagging)机制来区分不同执行实例的数据。每个令牌不仅携带数据值,还包含一个唯一的标签,标识其所属的迭代、线程或执行上下文。这使得同一条边上可以同时存在多个令牌,打破了静态模型的单赋值限制:
\[\forall e \in E, \forall t \in T: tokens(e, t) \in \mathbb{N}, \text{ 每个令牌有唯一标签 } tag \in \mathcal{T}\]标签空间$\mathcal{T}$的设计是一个关键的架构决策。简单的设计使用整数标签表示迭代次数,但这限制了并行的维度。更复杂的设计采用多维标签$(i, j, k, context)$,可以表示嵌套循环、多线程和函数调用等复杂的执行模式。标签的位宽直接影响硬件成本和可支持的并行度:
\[|\mathcal{T}| = 2^{b_{tag}} \text{, 其中} b_{tag} \text{是标签位宽}\]令牌匹配是动态数据流的核心操作,决定了节点何时可以执行。匹配规则可以形式化为:
\[fire(n, tag) \iff \forall i \in inputs(n): \exists token_i \in buffer(i) \text{ with } tag(token_i) = tag\]这个匹配操作在硬件上通常通过关联存储器(CAM)或哈希表实现。匹配单元的复杂度为$O(n \times m)$,其中$n$是输入端口数,$m$是缓冲的令牌数。为了降低复杂度,现代设计采用了多种优化技术:
动态调度带来的灵活性使得系统可以自适应地处理各种不规则的并行模式。例如,在处理稀疏矩阵乘法时,不同行的非零元素数量可能相差很大,静态调度必须按最坏情况分配时间,而动态调度可以让快速完成的行立即开始下一次迭代,实现自然的负载均衡。
然而,这种灵活性是有代价的。首先是硬件复杂度的显著增加。每个节点需要额外的标签存储、匹配逻辑和缓冲管理单元。一个典型的动态数据流节点的面积可能是静态节点的2-3倍。其次是功耗的增加,主要来自于关联搜索和额外的控制逻辑。最后是性能的不可预测性,由于执行顺序依赖于运行时的数据可用性,很难给出精确的性能保证。
混合模型的实践智慧
认识到纯静态和纯动态模型各自的局限性,现代数据流架构普遍采用混合方案,在不同的抽象层次上应用不同的调度策略。这种分层设计充分利用了两种模型的优势,同时规避了它们的缺点。
一种常见的混合策略是”粗粒度动态+细粒度静态”。在这种模型中,系统在任务或子图级别进行动态调度,而每个任务内部采用静态调度。例如,一个神经网络的不同层可以动态调度,但每一层内部的操作是静态编排的。这种方法的优势在于:
\[Overhead_{hybrid} = \alpha \times Overhead_{dynamic} + (1-\alpha) \times Overhead_{static}\]其中$\alpha$是动态调度部分的比例,通常很小(<10%),因此总开销接近静态模型。
另一种混合策略是”控制流动态+数据流静态”。控制流决策(如分支、循环边界)在运行时确定,但一旦选择了执行路径,该路径内的数据流是静态调度的。这特别适合处理具有数据依赖控制流的应用,如自适应算法和动态神经网络。
Groq TSP采用了一个极端但创新的选择:完全静态的全局调度。这个决定基于对目标工作负载的深刻理解——推理任务的计算图在部署时是已知的,不需要运行时的灵活性。通过将所有的调度复杂度转移到编译器,TSP实现了极简的硬件设计和确定性的执行,这对于实时AI应用至关重要。
这种设计哲学可以用”编译时间换运行时间”来概括。虽然编译可能需要几分钟甚至更长,但这是一次性的成本,而运行时的收益是持续的。对于推理部署场景,模型一旦训练完成就很少改变,因此长编译时间是可以接受的。
令牌(Token)是数据流架构中数据传递的基本单位,包含数据值和控制信息。
令牌结构
一个完整的令牌包含:
Token = {
data: 数据负载(标量/向量/张量)
tag: 迭代标识(用于动态数据流)
color: 执行上下文(用于多线程)
valid: 有效位
credit: 流控信息
}
令牌匹配规则
节点执行需要满足令牌匹配条件:
严格匹配(Strict Matching): 所有输入必须具有相同标签 \(\forall i, j \in inputs: tag(token_i) = tag(token_j)\)
松散匹配(Relaxed Matching): 部分输入可以使用通配符 \(\exists S \subseteq inputs: \forall i \in S: tag(token_i) = tag_{current}\)
激活与消耗
节点的执行过程:
令牌生产率和消耗率决定了系统的平衡: \(\rho = \frac{\text{production rate}}{\text{consumption rate}}\)
当 $\rho > 1$ 时需要缓冲,$\rho < 1$ 时产生空闲。
背压与流控
数据流系统需要处理生产者-消费者速度不匹配:
确定性执行是某些数据流架构(如Groq TSP)的关键特性,带来诸多系统级优势。
时序可预测性
在确定性数据流中,任意操作的执行时间可以精确预测:
\[T_{exec}(op_i) = T_{start} + \sum_{j \in path(src, op_i)} d_j\]其中 $path(src, op_i)$ 是从源到操作 $op_i$ 的关键路径。
这种可预测性支持:
调试与验证简化
确定性执行极大简化了系统验证:
验证复杂度从 $O(2^n)$(非确定性)降至 $O(n)$(确定性),其中 $n$ 是状态空间大小。
实时性保证
确定性执行提供硬实时保证:
最坏情况执行时间(WCET): \(WCET = T_{critical} + T_{overhead}\)
其中 $T_{overhead}$ 包括初始化和终结开销。
对于自动驾驶等安全关键应用,确定性执行确保:
抖动(Jitter)最小化: \(\sigma_{jitter} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(T_i - \bar{T})^2} \approx 0\)
功耗优化机会
确定性执行允许激进的功耗优化:
精确的时钟门控: \(P_{saved} = P_{dynamic} \times (1 - \alpha_{activity})\)
其中活动因子 $\alpha_{activity}$ 可以静态确定。
电压频率调节(DVFS): 由于知道精确的执行时间,可以优化: \(E = C \times V^2 \times f \times t\)
在满足截止时间约束下最小化能耗。
功耗门控调度: 编译器可以插入功耗门控指令:
t0-t100: Unit_A active
t101-t200: Unit_A sleep, Unit_B active
t201-t300: Both active
确定性执行是以编译复杂度换取运行时效率的典型权衡,特别适合推理等工作负载相对固定的场景。
Groq Tensor Streaming Processor (TSP) 是数据流架构在AI加速器领域的创新实践,通过软件定义的硬件(Software-Defined Hardware)理念,实现了编译器完全控制的确定性执行。TSP的设计目标是消除冯·诺依曼瓶颈,特别是内存墙问题,同时提供可预测的超低延迟。
TSP最激进的设计决策是完全依赖片上SRAM,避免外部DRAM访问带来的不确定性和能耗开销。
片上存储充分性分析
对于典型的推理工作负载,所需存储容量可以估算为:
\[M_{total} = M_{weights} + M_{activations} + M_{workspace}\]其中:
以BERT-Base为例(110M参数):
TSP单芯片提供220MB SRAM,通过以下技术满足需求:
带宽墙问题规避
传统架构的带宽限制: \(BW_{required} = \frac{OPS \times (bytes_{input} + bytes_{weight} + bytes_{output})}{reuse\_factor}\)
对于200 TOPS系统,假设reuse_factor=10: \(BW_{required} = \frac{200 \times 10^{12} \times 6}{10} = 120 \text{ TB/s}\)
HBM3提供约1TB/s,远不能满足需求。
TSP通过片上SRAM提供的聚合带宽: \(BW_{on-chip} = N_{banks} \times W_{port} \times f_{SRAM} = 1024 \times 32B \times 1.25GHz = 40 \text{ TB/s}\)
配合数据重用优化,完全避免带宽瓶颈。
功耗优势
访问能耗对比(45nm工艺):
对于每秒处理1TB数据的系统:
TSP的编译器承担了传统硬件调度器的全部职责,在编译时生成确定性的执行计划。
静态资源分配
编译器需要解决的资源分配问题可以形式化为整数线性规划(ILP):
目标函数(最小化执行时间): \(\min \sum_{i=1}^{N} t_i\)
约束条件:
其中:
冲突消除
编译器通过以下技术消除运行时冲突:
Bank冲突消除: 通过地址交织(interleaving)确保并行访问不冲突: \(bank(addr) = (addr \oplus (addr >> log_2(N_{banks}))) \mod N_{banks}\)
结构冲突消除: 使用Modulo调度实现软件流水线: \(t_{scheduled}(op) = t_{ASAP}(op) + k \times II\) 其中$II$是初始间隔(Initiation Interval)
数据冲突消除: 寄存器重命名避免WAW和WAR冲突: \(reg_{physical} = reg_{logical} + version \times N_{architectural}\)
优化空间
编译器可以探索的优化维度:
编译时间复杂度:$O(N^3)$对于N个操作,但只需离线执行一次。
TSP通过硬件和软件协同设计提供严格的延迟保证,这对实时AI应用至关重要。
延迟可预测性
每个操作的延迟完全确定: \(L_{op} = L_{compute} + L_{memory} + L_{transport}\)
端到端延迟: \(L_{e2e} = \max_{path} \sum_{op \in path} L_{op}\)
变异系数(CV)接近零: \(CV = \frac{\sigma_L}{\mu_L} < 0.01\)
QoS支持
TSP支持多级QoS通过时间分片:
时间片分配:
├── 高优先级(RT):40% slots,延迟 < 10ms
├── 中优先级(BE):40% slots,延迟 < 100ms
└── 低优先级(BG):20% slots,best effort
调度算法保证: \(\forall task_i \in RT: L_i \leq L_{deadline,i}\)
实时应用适配
自动驾驶延迟要求映射:
延迟分解: \(L_{total} = L_{fixed} + L_{variable} = L_{fixed} + 0\)(TSP中$L_{variable} = 0$)
TSP芯片包含多个精心设计的组件,协同实现高效的数据流执行。
计算单元布局
TSP采用二维阵列组织:
┌─────────────────────────────────┐
│ SuperLane 0 │ SuperLane 1 │...│
│ ┌─────────┐ │ ┌─────────┐ │ │
│ │ MXM Unit│ │ │ MXM Unit│ │ │ 320个MXM单元
│ │ 320 INT8│ │ │ 320 INT8│ │ │ = 20 SuperLanes
│ │ MAC/cyc │ │ │ MAC/cyc │ │ │ × 16 MXM/SuperLane
│ └─────────┘ │ └─────────┘ │ │
│ ┌─────────┐ │ ┌─────────┐ │ │
│ │ VXM │ │ │ VXM │ │ │ 320个VXM单元
│ │ Vector │ │ │ Vector │ │ │ 向量运算
│ └─────────┘ │ └─────────┘ │ │
│ ┌─────────┐ │ ┌─────────┐ │ │
│ │ SXM │ │ │ SXM │ │ │ 320个SXM单元
│ │ Scalar │ │ │ Scalar │ │ │ 标量/控制
│ └─────────┘ │ └─────────┘ │ │
└─────────────────────────────────┘
计算能力:
存储系统组织
分布式SRAM组织:
Memory Hierarchy:
├── L0: Register Files (per unit)
│ ├── Size: 144KB/unit
│ └── BW: 1TB/s/unit
├── L1: Local SRAM (per SuperLane)
│ ├── Size: 11MB/SuperLane
│ └── BW: 2TB/s/SuperLane
└── L2: Global SRAM (shared)
├── Size: 220MB total
└── BW: 40TB/s aggregate
地址映射函数: \(addr_{physical} = base + (x \times stride_x + y \times stride_y) \mod size\)
互连网络设计
TSP使用定制的片上网络连接所有组件:
拓扑结构:
路由策略:
网络性能:
指令流架构
TSP指令采用超长指令字(VLIW)格式:
Instruction Format (512 bits):
┌────────┬────────┬────────┬────────┬────────┐
│MXM_ops │VXM_ops │SXM_ops │MEM_ops │CTRL_ops│
│128-bit │128-bit │64-bit │64-bit │28-bit │
└────────┴────────┴────────┴────────┴────────┘
指令流特征:
这种设计将复杂度从硬件转移到编译器,实现了功耗和面积的最优化。
数据流架构和脉动阵列代表了NPU设计的两种不同理念。理解它们的差异有助于根据具体应用场景做出最优的架构选择。
计算模式支持
脉动阵列优化特定计算模式:
数据流架构支持更广泛的计算:
计算效率对比(以GEMM为例):
脉动阵列利用率: \(\eta_{systolic} = \frac{M \times N \times K}{max(M,N,K) \times Array_{size}^2}\)
当矩阵维度与阵列大小匹配时,$\eta_{systolic} \rightarrow 1$。
数据流架构利用率: \(\eta_{dataflow} = \frac{Ops_{actual}}{Ops_{peak}} \times \frac{1}{1 + \alpha_{overhead}}\)
其中$\alpha_{overhead}$包括数据移动和同步开销,典型值0.1-0.3。
资源利用率
脉动阵列的利用率挑战:
数据流架构的利用率优势:
实际利用率数据(200 TOPS设计):
工作负载 脉动阵列 数据流架构
GEMM(大) 95% 85%
GEMM(小) 45% 75%
稀疏GEMM(2:4) 50% 90%
Conv2D 85% 80%
Attention 70% 85%
Element-wise 30% 90%
功耗效率
功耗分解(典型值):
脉动阵列:
数据流架构:
能效比较: \(\frac{TOPS/W_{dataflow}}{TOPS/W_{systolic}} = \frac{\eta_{dataflow} \times P_{systolic}}{\eta_{systolic} \times P_{dataflow}}\)
对于稀疏工作负载,数据流架构能效提升1.5-2×。
控制流vs数据流
脉动阵列编程模型:
// 伪代码:脉动阵列编程
for t in range(M+N-1): // 时间步
for i in range(M):
for j in range(N):
if (i+j == t): // 对角线执行
C[i][j] += A[i][*] @ B[*][j]
特点:
数据流编程模型:
// 伪代码:数据流编程
Graph g;
Node matmul = g.add_op(MATMUL, {A, B});
Node add = g.add_op(ADD, {matmul, bias});
Node relu = g.add_op(RELU, {add});
compile_and_execute(g);
特点:
编译复杂度
脉动阵列编译主要任务:
总复杂度:$O(M \times N)$,相对简单。
数据流编译任务:
总复杂度:$O(V^3)$,显著更高。
编译时间对比(BERT-Base):
优化机会
脉动阵列优化维度:
数据流架构优化维度:
优化效果量化: \(Speedup = \frac{T_{baseline}}{T_{optimized}} = \frac{1}{(1-f) + \frac{f}{s}}\)
其中f是可优化部分比例,s是优化加速比。数据流架构的f更大。
工作负载特征
适合脉动阵列的工作负载:
性能预测模型: \(T_{systolic} = \lceil \frac{M}{M_a} \rceil \times \lceil \frac{N}{N_a} \rceil \times \lceil \frac{K}{K_a} \rceil \times (M_a + N_a + K_a - 2)\)
适合数据流架构的工作负载:
性能预测模型: \(T_{dataflow} = T_{critical-path} + T_{scheduling-overhead}\)
部署环境要求
数据中心部署:
评分标准 脉动阵列 数据流
吞吐量(batch>128) 10 8
能效(TOPS/W) 9 8
成本($/TOPS) 8 6
可扩展性 9 7
总分 36 29
边缘端部署:
评分标准 脉动阵列 数据流
延迟(batch=1) 7 10
功耗(<10W) 8 9
灵活性 6 10
确定性 7 10
总分 28 39
车载部署(自动驾驶):
评分标准 脉动阵列 数据流
实时性保证 7 10
功能安全 8 10
热设计 8 9
成本敏感度 7 6
总分 30 35
成本考虑
开发成本:
当Volume > 100K时,单位成本主导:
运营成本(TCO): \(TCO = Cost_{hw} + Cost_{power} \times Years + Cost_{cooling} + Cost_{maintenance}\)
数据流架构在功耗相关成本上有优势,特别是边缘部署场景。
架构选择决策树
是否需要极低延迟?
├─是→ 是否工作负载固定?
│ ├─是→ 数据流架构(TSP)
│ └─否→ 需要进一步分析
└─否→ 是否批处理为主?
├─是→ 矩阵运算占比?
│ ├─>80% → 脉动阵列(TPU)
│ └─<80% → 混合架构
└─否→ 数据流架构优先
实际产品选择还需考虑生态系统、软件栈成熟度、供应商支持等因素。两种架构各有优势,关键是匹配应用需求。
本章深入探讨了数据流架构的基本原理及其在NPU设计中的应用,以Groq TSP为例分析了其独特的设计理念。关键要点包括:
数据流计算模型:基于图的执行模型天然支持并行,通过令牌机制协调计算,静态数据流提供确定性执行的优势。
关键公式回顾:
习题9.1 数据流图表示 给定表达式:$y = (a \times b + c) \times (d - e)$,画出对应的数据流图,标注所有节点和边,并计算理想并行度。假设每个操作延迟为1个周期。
习题9.2 静态vs动态数据流 比较以下循环在静态和动态数据流中的执行差异:
for i = 0 to N-1:
if (A[i] > threshold):
B[i] = compute_heavy(A[i])
else:
B[i] = A[i]
分析两种模型的优缺点。
习题9.3 TSP存储容量计算 对于ResNet-50推理(25.6M参数),计算在TSP上部署需要的片上存储。假设:
习题9.4 编译器调度优化 给定一个简化的数据流图,包含6个操作,依赖关系和资源需求如下:
| 操作 | 依赖 | 计算单元需求 | 执行时间 |
|---|---|---|---|
| A | - | MXM×2 | 4 cycles |
| B | - | VXM×1 | 2 cycles |
| C | A | MXM×1 | 3 cycles |
| D | A,B | VXM×2 | 2 cycles |
| E | C | MXM×1 | 2 cycles |
| F | D,E | VXM×1 | 1 cycle |
系统资源:MXM×2, VXM×2
设计最优调度方案,最小化总执行时间。
习题9.5 背压机制设计 设计一个credit-based流控系统,满足以下要求:
计算最小缓冲深度和credit初始值。
习题9.6 能效优化分析 比较两种200 TOPS NPU设计方案的能效:
方案A(类TPU):
方案B(类TSP):
对于BERT-Base推理(batch=1),估算两者的能耗差异。
习题9.7 实时性保证分析 某自动驾驶系统要求:
使用数据流架构设计满足要求的调度方案。考虑:
习题9.8 架构选择决策 为以下三个场景选择最适合的NPU架构(脉动阵列/数据流/混合),并说明理由:
场景1:云端大语言模型推理服务
场景2:机器人实时控制
场景3:手机端多模型并发
陷阱:创建包含环的数据流图而未正确处理
错误示例:
A → B → C
↑ ↓
└───D───┘
问题:可能导致死锁或无限等待
解决方案:
陷阱:认为静态调度总是最优
if (rare_condition): // 概率 < 1%
heavy_computation() // 1000 cycles
else:
light_computation() // 10 cycles
问题:静态调度必须按最坏情况分配资源
解决方案:
陷阱:仅考虑模型参数大小
错误计算:
Memory = Model_weights
问题:忽略了激活、梯度、工作空间
正确计算:
Memory = Weights + Activations + Workspace + Double_buffering
陷阱:简单的阻塞可能传播
Producer → Buffer → Consumer
↓ ↓ ↓
Block Full Slow
问题:局部阻塞导致全局停滞
解决方案:
陷阱:假设编译是一次性成本
问题:
缓解策略:
陷阱:声称完全确定性但有例外
"确定性延迟"但忽略了:
- 错误处理路径
- 资源竞争情况
- 温度节流
最佳实践:
遵循这些最佳实践可以显著提高数据流架构NPU的设计质量和项目成功率。关键是在灵活性和效率之间找到适合具体应用的平衡点。