🏠

AIE_ML_Design_Graphs 技术深度解析

模块概述

AIE_ML_Design_Graphs 是 AMD/Xilinx Versal 自适应计算架构中 AI Engine (AIE-ML) 的顶层数据流图设计框架。它不是一个简单的代码库,而是一套硬件-软件协同设计的蓝图系统——它让开发者能够用 C++ 描述复杂的数字信号处理 (DSP) 和机器学习 (ML) 计算流水线,然后将这些描述编译成在 AIE 阵列上运行的物理映射。

想象一下:你手中有一块由数百个向量处理器组成的阵列,每个处理器都有自己的本地内存,它们通过片上网络互联。你的任务是实现一个 1008 点 FFT、一个 32 通道的滤波器组、或者一个 LeNet 推理引擎。AIE_ML_Design_Graphs 就是连接抽象算法与物理硬件的桥梁——它让你像搭积木一样组合计算单元(kernels),像规划城市一样安排数据流(streams),像分配房产一样精确控制每个计算单元在芯片上的位置(tile mapping)。


架构全景

核心抽象层次

flowchart TB subgraph "Algorithm Layer" A[Mathematical Algorithm - FFT/Filter/ConvNet] end subgraph "ADF Graph Layer This Module" B[adf::graph - Hierarchical Composition] C[kernel - Compute Functions] D[buffer/stream - Data Movement] E[PLIO - External Interface] end subgraph "Spatial Mapping Layer" F[tile x y AIE Core Assignment] G[bank x y z Memory Assignment] H[shim z PL Interface Assignment] end subgraph "Physical Hardware" I[AIE-ML Array Vector Processors] J[NoC Network on Chip] K[PL and PS Programmable Logic Processor] end A --> B B --> C B --> D B --> E C --> F D --> G E --> H F --> I G --> I H --> K I --> J

数据流架构模式

flowchart LR subgraph "Prime Factor FFT Pipeline" A[Input PLIO] --> B[DFT7 Stage] B --> C[DFT9 Stage] C --> D[DFT16 Stage] D --> E[Transpose Stage] E --> F[Output PLIO] end subgraph "Channelizer Data Flow" G[Input Streams] --> H[TDM FIR Bank] H --> I[IFFT 4096 2D] I --> J[Output Streams] end subgraph "MNIST ConvNet Layer" K[Input Feature Map] --> L[Conv2D Kernel] M[Weights] --> L L --> N[Max Pooling] N --> O[Output Feature Map] end

设计哲学与关键决策

1. 显式优于隐式:空间映射的可控性

设计抉择:在 AIE 编程中,我们可以让编译器自动决定每个 kernel 运行在哪个 tile 上,也可以像代码中那样显式使用 location<kernel>(kernel) = tile(x,y) 指定位置。

模块的选择显式控制。观察 dft7_app.cppdft9_app.cpp 等文件,你会发现严格的 tile 坐标分配:

location<kernel>(dft7.kk0) = tile(X+0,Y+0);
location<kernel>(dft7.kk1) = tile(X+1,Y+0);
location<kernel>(dft7.kk2) = tile(X+2,Y+0);

权衡分析

  • 优势:可预测的性能、精确的资源控制、避免路由拥塞、支持物理时序闭合
  • 代价:代码与硬件拓扑紧耦合、可移植性降低、需要深入理解芯片布局
  • 适用场景:高性能 DSP 流水线(如本模块的 FFT、Channelizer)需要确定性延迟和最大吞吐量

2. 分层组合:从原子 Kernel 到完整系统

设计模式:模块采用**层次化数据流图(Hierarchical Dataflow Graph)**架构。

层次示例(以 MNIST ConvNet 为例):

mnist_app.dut_graph (顶层)
├── conv2d_w1_graph (卷积层 w1)
│   ├── weights_graph (权重加载子图)
│   └── compute kernel (卷积计算核)
├── max_pooling2d_w2_graph (池化层)
├── dense_w7_graph (全连接层)
└── 各种 PLIO 接口

关键洞察:每个层次都遵循单一职责原则conv2d_w1 只负责一个卷积层;dft7 只负责 7 点 DFT。这种原子性带来了:

  • 可测试性:每个子图可以独立仿真验证
  • 可复用性dft7_graph 在 Prime Factor FFT 的多个阶段被复用
  • 可组合性:通过模板参数和 connect<> 像乐高积木一样组装

3. 内存架构:显式 Bank 分配与 Ping-Pong 策略

硬件现实:每个 AIE tile 有 4 个独立的 memory bank(通常标记为 0-3),支持单周期多端口访问。但如果不加控制,编译器可能将多个 buffer 分配到同一个 bank,造成存储体冲突(bank conflict)

模块的策略:在关键路径上(如 channelizertdm_fir),代码显式指定每个 buffer 的 bank 位置:

location<buffer>(dut.tdmfir.m_firKernels[ii].in[0])  = bank(start_fb+FBX[ii],FBY[ii],0);
location<buffer>(dut.tdmfir.m_firKernels[ii].out[0]) = {bank(start_fb+FBX[ii],FBY[ii],1), bank(start_fb+FBX[ii],FBY[ii],3)};

设计意图

  • Input buffer 放在 bank 0
  • Output buffer 跨 bank 1 和 3(可能是 ping-pong 双缓冲)
  • StackParameters 放在 bank 3

这种物理布局优化确保了高吞吐量数据路径不会出现内存访问瓶颈。


子模块全景

本模块包含以下主要设计教程子系统,每个都展示了特定的 AIE-ML 架构能力:

1. Prime Factor FFT Pipeline Graphs

核心能力:互质因子分解 FFT、多阶段数据流编排、显式转置与置换阶段。

关键组件

  • dft7_graph / dft9_graph / dft16_graph:小点数 DFT 计算单元
  • permute_i_graph:输入数据重排子图
  • transpose0_graph / transpose1_graph:矩阵转置数据搬移

架构价值:展示了如何将数学上的 FFT 算法分解为适合 AIE 向量处理器的数据流图,通过显式控制数据局部性和计算阶段重叠来最大化吞吐量。


2. LeNet ML System DMA Integration

核心能力:AIE-ML 与可编程逻辑 (PL) 的 DMA 数据搬移集成、CNN 推理加速器。

关键组件

  • lenet_x1.cfg:系统级连接配置,定义了 dma_hlslenet_kernel 之间的流连接
  • DMA HLS 内核与 AIE 图之间的 stream_connect 拓扑

架构价值:展示了异构计算系统的设计模式——AIE 负责密集向量计算,PL 负责数据预处理和存储器接口,通过显式的流连接 (stream_connect) 构建端到端流水线。


3. API-Based FFT Multi-Instance Graph

核心能力:AIE-API 编程模型、多实例并行 FFT、模板化可配置性。

关键组件

  • fft1k_128_graph:基于 AIE-API 的 1024 点 FFT 实现
  • dut_graph:包装器,支持 128 个并行实例 (N_INST=128)
  • 动态 PLIO 数组创建和连接

架构价值:展示了现代 AIE-API 编程风格——相比底层 ADF API,AIE-API 提供更高级的向量运算抽象。多实例化能力 (N_IO 数组) 展示了如何通过参数化模板实现"一次设计,多实例部署"的扩展模式。


4. Farrow Filter Design Variants

核心能力:分数延迟滤波器、设计空间探索、渐进式优化方法论。

关键组件

  • farrow_port_initial:初始移植的参考设计
  • farrow_opt_1 / farrow_opt_2:中间优化阶段(资源、吞吐量、延迟权衡)
  • farrow_final_aie:最终优化的 AIE 实现

架构价值:这是一个设计方法论教程,而非单一设计。它展示了 AIE 开发的典型工作流:从功能正确的初始实现开始,通过多轮优化(数据流重构、并行度提升、内存层次优化)逼近性能目标。每个变体都保留了相同的接口契约,但内部拓扑截然不同。


5. Channelizer, IFFT and TDM FIR Graphs

核心能力:多通道数字下变频、基于 Vitis DSP 库的系统集成、TDM (Time-Division Multiplexing) 滤波器组。

关键组件

  • channelizer_graph:完整通道化器(滤波器组 + IFFT)
  • ifft4096_2d_graph:4096 点 2D IFFT(支持 SSR 分解)
  • tdm_fir_graph / firbank_graph:时分解复用 FIR 滤波器组
  • 显式的 tile 和 bank 位置约束(避免路由拥塞)

架构价值:这是生产级 DSP 系统设计的参考实现。它展示了如何处理 AIE 开发中最困难的挑战之一:在大量并行计算单元(32+ 个 FIR 核)和复杂数据流(2D IFFT 转置)之间协调,同时通过显式物理布局约束确保编译后的设计能在芯片上布线成功。Vitis DSP 库的集成展示了如何复用经过验证的 IP 核构建更大系统。


6. MNIST ConvNet Layer and Full Network Graphs

核心能力:卷积神经网络推理、分层计算图、权重流式加载、多精度数据类型。

关键组件

  • conv2d_w1/w3/w5_graph:不同卷积核尺寸 (1x1, 3x3, 5x5) 的卷积层
  • max_pooling2d_w2/w4_graph:2x2 和 4x4 最大池化层
  • dense_w7_graph:全连接层(密集层)
  • mnist_graph:完整的 LeNet-风格网络拓扑
  • 独立的权重加载子图 (weights_graph) 与计算核解耦

架构价值:这是机器学习加速器设计的教材级实现。它展示了如何将神经网络层映射到 AIE 的向量架构:卷积运算利用 AIE 的 SIMD 乘加单元,权重通过独立的 PLIO 流式加载以重叠计算与数据传输,不同层通过 FIFO 深度控制实现流水线平衡。特别值得注意的是权重与计算的解耦设计——权重通过独立的数据流路径加载,允许在推理过程中动态更换模型参数或实现权重压缩。


关键依赖与系统集成

上游依赖(本模块依赖的外部框架)

依赖模块 用途 集成方式
Vitis_Platform_Creation 提供底层硬件平台定义、设备树、启动配置 graph 基类与平台配置链接
AIE_Design_Graphs_and_Algorithms 提供底层算法核实现(FFT 蝶形运算、FIR 滤波器抽头) 子图实例化与算法核连接
AIE_Design_System_Integration 提供 PL 侧 DMA、数据搬移器、存储器接口 PLIO 与 PL 内核的 stream_connect

下游依赖(依赖本模块的系统组件)

本模块是 AIE-ML 设计教程的顶层示例集合,主要作为参考实现被以下场景使用:

  • 产品开发团队复用其中的 firbank_graphfft_graph 架构模式
  • 验证团队引用其测试向量和仿真流程
  • 系统集成团队参考其 PL-AIE 连接配置 (*.cfg 文件)

关键陷阱与工程实践建议

1. Tile 位置约束的"紧耦合"风险

问题:代码中大量使用硬编码的 tile 坐标(如 tile(18,0)tile(34+ff,4))。这导致:

  • 可移植性差:在更大的 AIE 阵列(如 xcve2802 vs xcve1752)上编译可能失败
  • 维护困难:任何拓扑修改都需要手动调整大量坐标

缓解策略

  • 使用模板参数(如 template<int X, int Y>)将基坐标参数化(已在 dft16_graph 等中使用)
  • 定义命名常量(constexpr int BASE_TILE_X = 18;
  • 使用 location<kernel>(kernel) = relative_tile(offset_x, offset_y) 抽象(如果 ADF 版本支持)

2. 内存 Bank 分配的"静默冲突"

问题location<buffer>(...) = bank(x,y,z) 将 buffer 分配到特定 bank。如果多个 buffer 被分配到同一 bank 且访问模式冲突,可能导致:

  • 性能下降:Bank 冲突导致流水线停顿
  • 编译失败:如果 bank 容量超限,Vitis 编译器报错

最佳实践

  • 遵循 "One Buffer per Bank" 原则(观察 tdm_fir 代码:in[0] 在 bank 0,out[0] 跨 bank 1 和 3)
  • 使用 single_buffer() 约束明确声明单缓冲(非乒乓),避免编译器生成额外的乒乓缓冲区占用更多 bank
  • 在注释中记录每个 bank 的分配意图(如 // Bank 0: Input ping, Bank 1: Output pong

3. 仿真与硬件的行为差异 (AIE_SIM_ONLY)

问题:代码中大量使用条件编译:

#ifdef AIE_SIM_ONLY
    sig_i[0] = input_plio::create(..., "data/sig_i.txt");  // 仿真:从文件读取
#else
    sig_i[0] = input_plio::create(...);  // 硬件:连接实际 PL 接口
#endif

风险

  • 仿真通过但硬件失败:如果 PL 侧逻辑未正确实现,硬件运行时数据流可能中断
  • 文件 I/O 与实际 DMA 的时序差异:仿真中的文件读取通常是"无限带宽",而硬件受限于 DMA 带宽和延迟

工程实践

  • 确保 PL 侧的 DMA HLS 内核与 AIE 图在数据宽度(plio_64_bits)、时钟域和握手协议上匹配
  • 在仿真阶段注入延迟模型(如果 ADF 支持)以更接近硬件时序
  • 使用 __X86SIM____AIESIM__ 宏区分 x86 功能仿真与 AIE 周期精确仿真

4. 数据宽度与类型对齐 (plio_64_bits)

观察:所有 PLIO 创建都使用 plio_64_bits

sig_i = input_plio::create("PLIO_i", plio_64_bits, "data/sig_i.txt");

含义

  • 每个 PLIO 端口每周期传输 64 比特(8 字节)
  • 对于 cint16(复数 16 位,共 32 位),64 比特 PLIO 每周期可传输 2 个复数样本
  • 数据在 AXI4-Stream 接口上的打包格式必须严格匹配(通常是 {imag, real} 或 {real, imag} 的级联)

陷阱

  • 如果 PL 侧 HLS 内核使用 ap_uint<128> 而 AIE 侧期望 64 位,会导致数据错位或流控制失败
  • 复数类型的字节序(Endianness)和分量顺序(实部在前 vs 虚部在前)必须在 PL 和 AIE 间约定一致

总结:设计意图的灵魂

AIE_ML_Design_Graphs 的核心设计意图可以概括为:在可编程性、性能与确定性之间取得硬件工程的最优平衡

它不是追求最灵活的框架(牺牲了自动调度和动态调度能力),也不是追求性能极限的手动汇编(牺牲了可维护性),而是找到了一个"甜蜜点":

  1. 通过层次化图组合提供结构性可编程性,让复杂的 DSP 系统可以被分解为可管理、可复用的组件;
  2. 通过显式空间映射提供性能确定性,让关键数据路径的延迟和吞吐量可以被精确预测和优化;
  3. 通过声明式约束(location<>、single_buffer 等)提供编译器协作,让人类工程师的架构洞察与自动化工具的优化能力相结合。

对于新加入团队的工程师,理解这个设计意图比记住任何具体 API 都重要——它是指导你做出正确设计决策(何时显式映射、何时使用库、何时优化内存布局)的北极星。

On this page