Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 人工智能 / Artificial Intelligence

AI 编译器 / AI Compilers

1. AI 编译器全景——为什么模型需要编译器 / The AI Compiler Landscape and Why Models Need Compilers

2. 编译原理速通——面向 ML 工程师的核心概念 / Compiler Fundamentals for Machine Learning Engineers

3. 中间表示基础——理解 IR 层级与 lowering 链路 / Intermediate Representation Levels and Lowering Pipelines

4. 计算图的构建与表示 / Building and Representing Computational Graphs

5. MLIR 架构、方言与渐进式降级 / MLIR Architecture, Dialects, and Progressive Lowering

6. 算子语义、广播、归约与形状推导 / Operator Semantics, Broadcasting, Reduction, and Shape Inference

7. 模型前端格式:ONNX、TFLite、HLO 与 SavedModel / Model Frontend Formats: ONNX, TFLite, HLO, and SavedModel

8. 图优化 Pass——经典优化在 ML 中的应用 / Graph Optimization Passes for Machine Learning

9. 算子融合——编译器最重要的性能优化 / Operator Fusion as a Core Compiler Optimization

10. 内存规划——Buffer 分配与生命周期管理 / Memory Planning, Buffer Allocation, and Lifetime Management

11. Layout 优化——数据排布转换与内存效率 / Layout Optimization for Data Movement and Memory Efficiency

12. 动态 Shape——符号分析与形状处理 / Dynamic Shapes, Symbolic Analysis, and Shape Processing

13. 硬件约束下的操作调度 / Operation Scheduling Under Hardware Constraints

14. 从模板、DSL 到 IR 降级的代码生成架构 / Code Generation Architectures from Templates and DSLs to IR Lowering

15. CPU 后端:SIMD、分块与多线程 / CPU Backends with SIMD, Tiling, and Multithreading

16. CUDA 后端:合并访存与 Tensor Core / CUDA Backends, Memory Coalescing, and Tensor Cores

17. NPU 后端:脉动阵列与端侧 AI 生态 / NPU Backends, Systolic Arrays, and Edge AI Ecosystems

18. Kernel 性能基础:Roofline 与 Occupancy / Kernel Performance Fundamentals with Roofline and Occupancy

19. CUTLASS 与分层 GEMM 模板 / CUTLASS and Hierarchical GEMM Templates

20. TVM Tensor Expression 与计算调度分离 / TVM Tensor Expressions and Compute-Schedule Separation

21. 使用 Triton 编写高性能 GPU Kernel / Triton for High-Performance GPU Kernels in Python

22. 基于成本模型与实测搜索的自动调度 / Automatic Scheduling with Cost Models and Measurement-Based Search

23. XLA 内部机制:HLO、融合与 SPMD / XLA Internals, HLO, Fusion, and SPMD

24. Torch-MLIR:从 PyTorch 算子到 MLIR 方言 / Torch-MLIR from PyTorch Operators to MLIR Dialects

25. torch.compile:Dynamo、AOTAutograd、Inductor 与 Triton / Torch Compile with Dynamo, AOTAutograd, Inductor, and Triton

26. 从 MLIR 经 LLVM 降级到机器码 / Lowering from MLIR Through LLVM to Machine Code

27. 量化——低精度推理的工程实践 / Engineering Low-Precision Inference with Quantization

28. 分布式编译与训练——多设备编排的编译器支持 / Compiler Support for Distributed Training and Multi-Device Orchestration

29. 生产调试——真实问题的编译器视角排查 / Production Debugging from the Compiler Perspective

30. 未来方向——AI 编译器的新挑战与机遇 / Future Challenges and Opportunities for AI Compilers

本页目录

📅 创建时间:2026-06-03 🏷️ 标签:#NPU #TPU #SystolicArray #昇腾 #DaVinci #寒武纪 #QualcommSNPE #AppleANE #EdgeAI #Delegate 📚 前置知识:[[13-codegen-architecture]](代码生成架构) 📚 相关知识:[[15-backend-cuda]](CUDA 后端) [[26-quantization]](量化)


NPU 后端:脉动阵列与端侧 AI 生态 / NPU Backends, Systolic Arrays, and Edge AI Ecosystems ​

┌──────────────────────────────────────────────────────────────────────────────┐ │ 情 境 描 述 │ ├──────────────────────────────────────────────────────────────────────────────┤ │ 你需要在华为昇腾 910B NPU 上部署模型。文档说支持"主流 AI 框架",但实际: │ │ - PyTorch 模型需要用 MindSpore 重新训练 │ │ - TensorFlow 模型需要 ONNX 转换再 lower 到 HiAI backend │ │ - INT8 量化需要用华为自研的 QAT 工具,否则精度掉 10% │ │ │ │ 每一步都有人为的生态壁垒。NPU 编译器生态为什么这么碎片化? │ └──────────────────────────────────────────────────────────────────────────────┘

第1节:NPU 的特殊性——专用硬件的设计哲学 ​

1.1 为什么需要 NPU ​

GPU 虽然通用,但并非最优:

┌─────────────────────────────────────────────────────────────────────────────┐
│                    GPU vs NPU:通用 vs 专用的权衡                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  GPU (通用):                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  ✓ 编程简单(CUDA/Triton)                                            │   │
│  │  ✓ 生态完善(cuDNN, cuBLAS, PyTorch 原生支持)                        │   │
│  │  ✓ 算子灵活(任何自定义 op 都可实现)                                  │   │
│  │  ✗ 能效低(通用计算浪费在图形渲染上)                                  │   │
│  │  ✗ 面积效率低(大量晶体管用于渲染管线)                                │   │
│  │  ✗ 价格贵(H100 A100 成本高)                                         │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  NPU (专用):                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  ✓ 能效极高(专用硬件做专用计算)                                      │   │
│  │  ✓ 面积效率高(脉动阵列等密集矩阵计算单元)                            │   │
│  │  ✓ 推理延迟低(硬件优化过的算子)                                      │   │
│  │  ✗ 编程复杂(厂商 SDK, DSL, 限制多)                                  │   │
│  │  ✗ 生态碎片(每家 SDK 不同)                                          │   │
│  │  ✗ 算子限制(只支持预定义的算子)                                      │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

1.2 NPU 的分类 ​

类型架构代表特点
云端训练脉动阵列TPU v2/v3, 昇腾 910高 TFLOPS,支持 training
云端推理脉动阵列/向量TPU v1, 昆仑芯强调 throughput
边缘推理VLIW/DSP/NN accel寒武纪 MLU, Hexagon低功耗,INT8 为主
移动端NN acceleratorApple ANE, DSP超低功耗,always-on

1.3 NPU 的共同特征 ​

python
class NPUCommonCharacteristics:
    """
    NPU 的共同特征
    """
    
    # 1. 固定形状的矩阵计算单元
    # 不支持动态 shape,必须是编译时确定的固定大小
    matrix_unit_shape = {
        'TPU v2': '128×128',      # 每单元
        'TPU v3': '128×128',
        '昇腾 910': '16×16×16',   # Cube 计算单元
        '寒武纪 MLU220': '16×16',
        'Hexagon HVX': '1024 (vector)'
    }
    
    # 2. 本地 SRAM 代替 HBM
    # NPU 通常有较小的本地内存,带宽高但容量小
    local_sram = {
        'TPU v2': '28 MB',        # Unified Buffer
        'TPU v3': '32 MB',
        '昇腾 910': '16 MB',
        '寒武纪 MLU220': '8 MB'
    }
    
    # 3. 量化原生支持
    # NPU 设计时就考虑了 INT8/INT4/FP16
    # 硬件直接支持量化计算
    native_quant = ['INT8', 'INT4', 'FP16', 'BF16']
    
    # 4. 固定的数据流
    # 数据流 (Dataflow) 是编译时确定的
    # 输入 → 累加器 → 输出,不能随意排列
    dataflow = ['固定数据流', '行稳态数据流', '权重平稳态数据流']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

第2节:脉动阵列——TPU 的核心架构 ​

2.1 脉动阵列原理 ​

脉动阵列 (Systolic Array) 是 NPU 最常见的架构:

┌─────────────────────────────────────────────────────────────────────────────┐
│                           脉动阵列架构                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  2D 脉动阵列示意图 (以 4×4 为例):                                           │
│                                                                             │
│         W(0,0)  W(0,1)  W(0,2)  W(0,3)                                     │
│              ↓       ↓       ↓       ↓                                     │
│         ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐  ← 权重输入                        │
│         │ PE  │ │ PE  │ │ PE  │ │ PE  │                                    │
│  I(0) → │(0,0)│ │(0,1)│ │(0,2)│ │(0,3)│→ Y(0,0) Y(0,1) Y(0,2) Y(0,3)        │
│         └──┬────┘ └──┬────┘ └──┬────┘ └──┬────┘                            │
│            ↓       ↓       ↓       ↓                                        │
│         ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐                                    │
│         │ PE  │ │ PE  │ │ PE  │ │ PE  │                                    │
│  I(1) → │(1,0)│ │(1,1)│ │(1,2)│ │(1,3)│→ ...                               │
│         └──┬────┘ └──┬────┘ └──┬────┘ └──┬────┘                            │
│            ↓       ↓       ↓       ↓                                        │
│         ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐                                    │
│         │ PE  │ │ PE  │ │ PE  │ │ PE  │                                    │
│  I(2) → │(2,0)│ │(2,1)│ │(2,2)│ │(2,3)│→ ...                               │
│         └──┬────┘ └──┬────┘ └──┬────┘ └──┬────┘                            │
│            ↓       ↓       ↓       ↓                                        │
│         ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐                                    │
│         │ PE  │ │ PE  │ │ PE  │ │ PE  │                                    │
│  I(3) → │(3,0)│ │(3,1)│ │(3,2)│ │(3,3)│→ Y(3,0) Y(3,1) Y(3,2) Y(3,3)        │
│         └─────┘ └─────┘ └─────┘ └─────┘                                    │
│                                                                             │
│  每个 PE:                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  输入数据 → [Register] → [Multiply] → [Accumulator] → 输出数据      │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  脉动的工作方式:                                                            │
│  - 权重从左向右流动 (W 寄存器)                                               │
│  - 输入从上向下流动 (I 寄存器)                                               │
│  - 每个 PE 做一次乘法和一次累加                                              │
│  - 结果从右下角流出                                                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

2.2 脉动阵列的计算过程 ​

python
def systolic_array_computation():
    """
    脉动阵列计算 GEMM: Y = I × W
    假设 4×4 阵列,W 是 4×4,I 是 4×N
    """
    
    # 初始化
    # PE[i][j] 的权重寄存器初始化为 W[i][j]
    # PE[i][j] 的累加器初始化为 0
    
    # 计算过程
    # 每个时间步:
    # 1. PE[i][j] 的 I_register 接收来自 PE[i-1][j] 的数据(或输入 I[i][t])
    # 2. PE[i][j] 的 W_register 接收来自 PE[i][j-1] 的数据(或权重 W[i][j])
    # 3. PE[i][j] 计算: accumulator += I_register * W_register
    
    # 时间步 t=0:
    # PE[0][*] 接收 I[0][0], I[1][0], I[2][0], I[3][0]
    # PE[*][0] 接收 W[0][0], W[1][0], W[2][0], W[3][0]
    # PE[0][0]: acc = I[0][0] * W[0][0]
    
    # 时间步 t=1:
    # PE[0][*] 接收 I[0][1], I[1][1], ...
    # PE[1][0] 接收 W[1][0](从 PE[0][0] 流来)
    # PE[0][0]: acc += I[0][1] * W[0][0]
    # PE[1][0]: acc = I[1][0] * W[1][0]
    
    # 时间步 t=4 (第一个输出):
    # PE[3][3] 输出 Y[0][0] = sum_k(I[0][k] * W[k][0])
    
    print("脉动阵列的计算延迟 = 2N-1 个周期")
    print("每个周期完成 N 个 MAC 操作")
    print("理论吞吐量: N×N 个 MAC/周期")
    

def tpu_vs_gpu_efficiency():
    """
    TPU vs GPU 效率对比
    """
    
    # TPU (脉动阵列):
    # - 每周期 MAC 数 = 阵列大小 = 128×128 = 16384
    # - 无需寄存器文件访问,每个 MAC 直接从相邻 PE 获取数据
    # - 能效极高
    
    # GPU (CUDA Core):
    # - 每 SM 每周期: 2×FP32 FMA = 2 MAC (Ampere)
    # - 108 SM (A100): 108 × 2 = 216 MAC/周期
    # - 需要从寄存器文件读取操作数
    
    tpu_mac_per_cycle = 128 * 128  # = 16384
    gpu_mac_per_cycle = 108 * 2     # A100 = 216
    
    print(f"TPU MAC/cycle: {tpu_mac_per_cycle}")
    print(f"GPU MAC/cycle: {gpu_mac_per_cycle}")
    print(f"TPU 优势: {tpu_mac_per_cycle / gpu_mac_per_cycle:.0f}x")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

第3节:主流 NPU 生态详解 ​

3.1 Google TPU ​

python
class TPU:
    """
    Google TPU 架构
    """
    
    # TPU v1 (2016): 推理专用
    v1 = {
        'matrix_unit': '256×256 脉动阵列',
        'precision': 'INT8 (推断), FP16 (训练)',
        'memory': '8 GB HBM',
        'bandwidth': '34 GB/s',
        'tflops': 92,  # INT8
        'backend': 'XLA'
    }
    
    # TPU v2 (2017): 训练+推理
    v2 = {
        'matrix_unit': '128×128 脉动阵列 × 2',
        'precision': 'FP16, INT8',
        'memory': '64 GB HBM (16 GB per chip)',
        'bandwidth': '700 GB/s (per chip)',
        'tflops': 45,  # FP16
        'interconnect': 'Custom interconnect, 2D torus'
    }
    
    # TPU v3 (2018)
    v3 = {
        'matrix_unit': '128×128 脉动阵列 × 2',
        'precision': 'FP16, INT8, BFLOAT16',
        'memory': '128 GB HBM',
        'bandwidth': '900 GB/s',
        'tflops': 123,  # BF16
        'pods': '1024 chips, 100+ PFLOPS'
    }
    
    # TPU v4 (2020)
    v4 = {
        'matrix_unit': '128×128 脉动阵列 × 2',
        'precision': 'FP16, INT8, BFLOAT16',
        'memory': '32 GB HBM per chip',
        'interconnect': 'Optical interconnect, 3D torus',
        'tflops': 275,  # BF16 per chip
        'pods': '4096 chips, 1 exaflop'
    }
    
    # XLA 编译流程
    def xla_compilation():
        """
        TensorFlow → XLA → TPU Binary
        """
        # 1. TensorFlow 图 → XLA HLO
        # 2. XLA 优化 pass (fusion, layout, scheduling)
        # 3. TPU 特定 lower (HLO → TPU IR)
        # 4. TPU 代码生成 (TPU binary)
        
        pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

3.2 华为昇腾 (DaVinci) ​

python
class Ascend:
    """
    华为昇腾 NPU
    """
    
    # 昇腾 910 (云端训练/推理)
    ascend_910 = {
        'architecture': 'Da Vinci',
        'compute': '512 TB-FLOPS (FP16) / 256 TFLOPS (FP32)',
        'cubes': '32 个 AI Core (类似 Tensor Core)',
        'memory': '32 GB HBM2',
        'bandwidth': '1.2 TB/s',
        'process': '7nm + CoWoS',
        'sdk': 'CANN (Compute Architecture for Neural Networks)',
        'framework': 'MindSpore, PyTorch (via CANN), TensorFlow (via CANN)'
    }
    
    # 昇腾 310 (边缘推理)
    ascend_310 = {
        'compute': '22 TOPS (INT8) / 11 TFLOPS (FP16)',
        'power': '8W TDP',
        'process': '12nm',
        'sdk': 'CANN Lite'
    }


def cann_workflow():
    """
    CANN 工作流程
    """
    
    # 昇腾 CANN 编译流程:
    # 1. 模型转换: PyTorch/TensorFlow → ONNX → AhmModel (昇腾模型格式)
    # 2. 图优化: 算子融合, shape 推断
    # 3. 算子编译: 算子 → TBE (Tensor Boost Engine) 生成的代码
    # 4. 离线模型: AhmModel → .om 模型文件
    
    workflow = """
    PyTorch Model
         ↓ (torch.onnx.export)
    ONNX Model
         ↓ (atc converter)
    AhmModel
         ↓ (optimizer)
    Optimized AhmModel
         ↓ (builder)
    .om (Offline Model)
    """
    
    print(workflow)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

3.3 寒武纪 MLU ​

python
class Cambricon:
    """
    寒武纪 MLU (Machine Learning Unit)
    """
    
    # MLU220 (边缘推理)
    mlu220 = {
        'process': '16nm',
        'compute': '16 TOPS (INT8) @ 8W',
        'memory': '4 GB LPDDR4',
        'bandwidth': '25.6 GB/s',
        'sdk': 'BangC (基于 GCC 扩展)'
    }
    
    # MLU290 (云端)
    mlu290 = {
        'process': '7nm',
        'compute': '256 TOPS (INT8) / 256 TFLOPS (FP16)',
        'memory': '32 GB HBM2',
        'bandwidth': '1 TB/s',
        'sdk': 'BangC'
    }
    
    # BangC 编程模型
    def bangc_kernel():
        """
        BangC 是类 C 的 DSL
        """
        code = """
        // BangC kernel 示例
        __mlu_entry__ void gemm_kernel(...) {
            // 分配本地内存到 MLU 片上 SRAM
            __mlu_shared__ float As[BLOCK_M][BLOCK_K];
            __mlu_shared__ float Bs[BLOCK_K][BLOCK_N];
            
            // 加载数据
            __memcpy(As, A, sizeof(float) * M * K, GDRAM2L1);
            
            // 计算
            for (int k = 0; k < K; k += BLOCK_K) {
                // 矩阵乘累加
                // __bang_fma: fused multiply-add
                __bang_fma(As, As, Bs, BLOCK_M * BLOCK_K);
            }
            
            // 写回
            __memcpy(C, Cs, sizeof(float) * M * N, L1GDRAM);
        }
        """
        print(code)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

3.4 高通 Hexagon (SNPE) ​

python
class QualcommHexagon:
    """
    高通 Hexagon DSP + NPU
    """
    
    # Hexagon V65/V66 (Snapdragon 865/888)
    hexagon_v66 = {
        'type': 'Hexagon DSP + Adreno GPU + Kryo CPU',
        'nn_engine': 'SNPE (Snapdragon Neural Processing Engine)',
        'compute': '15 TOPS (combined)',
        'precision': 'INT8, INT16, FP16',
        'sdk': 'QNN (Qualcomm Neural Network)',
        'framework': 'TFLite, ONNX, PyTorch (via DLC)'
    }
    
    # SNPE 工作流程
    def snpe_workflow():
        """
        Qualcomm SNPE 工作流程
        """
        workflow = """
        PyTorch/TF Model
             ↓
        Framework → ONNX → DLC (Deep Learning Container)
             ↓
        SNPE Runtime
             ↓
        目标: Hexagon DSP / Adreno GPU / Kryo CPU
        """
        print(workflow)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

3.5 Apple Neural Engine ​

python
class AppleANE:
    """
    Apple Neural Engine (ANE)
    """
    
    # A14/A15/A16/M1/M2
    ane_specs = {
        'A14 Bionic': '11 TOPS',
        'A15 Bionic': '15.8 TOPS',
        'A16 Bionic': '17 TOPS',
        'M1': '11 TOPS',
        'M2': '15.8 TOPS',
        'precision': 'FP16, INT8 (ANE 原生)',
        'sdk': 'CoreML, Metal Performance Shaders'
    }
    
    # CoreML 流程
    def coreml_workflow():
        """
        Apple CoreML 流程
        """
        # 1. 模型转换: PyTorch/TF → .mlmodel
        # 2. 编译: .mlmodel → .mlmodelc (加速)
        # 3. 执行: ANE 自动调度算子
        
        workflow = """
        PyTorch Model
             ↓ (coremltools)
        .mlmodel (CoreML format)
             ↓ (compiler)
        .mlmodelc (compiled)
             ↓
        ANE / GPU / CPU (自动选择)
        """
        print(workflow)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

第4节:主流 NPU 架构对比 ​

特性Google TPU华为昇腾 910寒武纪 MLU290高通 HexagonApple ANE
架构脉动阵列Cube+Vector自研 MLU CoreVLIW+DSP自研
精度BF16/FP16/INT8FP16/INT8FP16/INT8FP16/INT8FP16
内存HBM 32GBHBM2 32GBHBM2 32GBLPDDR5统一内存
带宽900 GB/s1.2 TB/s1 TB/s~50 GB/s共享
SDKXLA/JAXCANNBangCQNN/SNPECoreML
框架TF/JAXMindSpore自有框架TFLite自有生态
适用云端训练云端训练云端推理边缘移动端

第5节:Delegate 模式——TFLite 的扩展机制 ​

5.1 Delegate 原理 ​

python
class TFLiteDelegate:
    """
    TFLite Delegate 模式
    允许将部分图 lower 到加速器执行
    """
    
    def __init__(self, delegate_library):
        self.delegate = tflite.load_delegate(delegate_library)
    
    def interpret(self, model_path):
        interpreter = tflite.Interpreter(
            model_path,
            experimental_delegates=[self.delegate]
        )
        return interpreter


# 使用 GPU Delegate
interpreter = tflite.Interpreter(
    model_path='model.tflite',
    experimental_delegates=[tflite.load_delegate('libtensorflowlite_gpu_delegate.so')]
)


# 使用 NPU Delegate (Android)
interpreter = tflite.Interpreter(
    model_path='model.tflite',
    experimental_delegates=[tflite.load_delegate('libnnapi_delegate.so')]
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

5.2 实现自定义 Delegate ​

cpp
// 实现自定义 Delegate
#include <tensorflow/lite/delegates/utils.h>

// 1. 定义 Delegate Options
TfLiteDelegate* CreateMyDelegate() {
    TfLiteDelegate* delegate = TfLiteDelegateCreate();
    
    delegate->flags = kTfLiteDelegateFlagsNone;
    
    // 指定哪些节点由 Delegate 处理
    delegate->Prepare = [](TfLiteContext* context, TfLiteDelegate* delegate) {
        // 图遍历,设置 node->builtin_data = (void*)kTfLiteDelegate
        // 表示这些节点由 Delegate 处理
    };
    
    return delegate;
}

// 2. 实现 Delegate 的 Eval
// 遍历 Delegate 处理的节点
// 调用加速器 API 执行
delegate->Eval = [](TfLiteContext* context, TfLiteDelegate* delegate) {
    // 找到所有标记为 Delegate 的节点
    // 按拓扑序执行
    for (auto node : delegate_nodes) {
        // 调用加速器执行
        accelerator.Execute(node->inputs, node->outputs);
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

第6节:NPU 编译的特殊挑战 ​

6.1 内存层次不同于 GPU ​

python
class NPUMemoryChallenge:
    """
    NPU 内存层次挑战
    """
    
    # GPU: HBM → L2 → L1 → Register
    gpu_hierarchy = """
    HBM (800 GB/s, 80 GB)
        ↓
    L2 Cache (A100: 40 MB)
        ↓
    L1/Shared Memory (128 KB)
        ↓
    Register (~1 MB)
    """
    
    # NPU: 通常没有 Cache,本地 SRAM 直接和 HBM 交互
    npu_hierarchy = """
    HBM (400 GB/s, 32 GB)
        ↓
    Local SRAM (16 MB)  ← 没有中间层 Cache!
        ↓
    脉动阵列 (MAC)
    """
    
    # 挑战:
    # 1. Local SRAM 很小(16 MB vs GPU L2 40 MB)
    # 2. 需要精确的数据放置策略
    # 3. 编译器必须知道数据何时在 SRAM 中
    # 4. 无法依赖硬件自动 Cache

def memory_placement_strategy():
    """
    NPU 内存放置策略
    """
    
    strategy = """
    1. 确定哪些数据必须放在 SRAM:
       - 频繁访问的小张量
       - 权重(如果能放下)
    
    2. 确定哪些数据直接从 HBM 读取:
       - 只读一次的大张量
       - 中间结果
    
    3. 计算数据流:
       - 确定每个算子的输入输出
       - 最小化 HBM ↔ SRAM 传输
    
    4. 调度:
       - 计算和数据传输重叠
       - Double Buffering
    """
    print(strategy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

6.2 算子支持不完整 ​

python
class OperatorSupportChallenge:
    """
    NPU 算子支持挑战
    """
    
    # 常见问题:
    issues = [
        "自定义算子: NPU 通常只支持预定义的算子",
        "动态 shape: NPU 需要固定形状,动态 shape 需要特殊处理",
        "精度限制: INT8 量化可能导致精度损失",
        "数值范围: NPU 的 INT8 范围可能和 PyTorch 不同"
    ]
    
    # 解决方案:
    solutions = {
        'fallback_to_cpu': '不支持的算子回退到 CPU',
        'kernel_fusion': '多个小算子融合成支持的大算子',
        '拆解重组': '复杂算子拆解成多个简单算子'
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

6.3 量化校准的特殊性 ​

python
class NPUQuantizationChallenge:
    """
    NPU 量化校准的特殊挑战
    """
    
    # 问题:
    # 1. NPU 的 INT8 乘法器是定点,乘加结果需要截断
    # 2. 不同 NPU 的量化参数计算方式不同
    # 3. 需要在目标 NPU 上进行 calibration
    
    def npu_quantization_flow():
        """
        NPU 量化流程
        """
        flow = """
        1. FP32 模型训练
        
        2. Calibration (目标 NPU 上运行):
           - 使用代表性数据集
           - 收集激活值范围
           - 计算 scale/zero_point
        
        3. QAT (可选,但华为等要求):
           - 在训练时模拟量化
           - 端到端训练量化参数
        
        4. 模型转换:
           - PyTorch → ONNX → NPU 格式
           - 内嵌量化参数
        
        5. 验证精度:
           - 如果精度损失 > 阈值,回到步骤 1 或 3
        """
        print(flow)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

第7节:跨 NPU 移植策略——MLIR 作为统一底层 ​

7.1 为什么需要统一 IR ​

python
class UnifiedIRChallenge:
    """
    NPU 生态碎片化的痛点
    """
    
    # 每个 NPU 都有自己的:
    # - 模型格式 (ONNX, MindSpore, DLC, .mlmodel)
    # - SDK (CANN, BangC, QNN, SNPE)
    # - 工具链
    # - 优化方式
    
    # 开发者需要为每个 NPU 学习:
    # - 模型转换工具
    # - SDK API
    # - 调试方法
    # - 性能优化
    
    pain_points = [
        "重复工作: 每个 NPU 都要重新部署模型",
        "学习成本: 文档质量参差不齐",
        "调试困难: 厂商工具封闭",
        "升级风险: NPU 升级可能导致不兼容"
    ]


class MLIRAsUnifiedIR:
    """
    MLIR 作为统一底层
    """
    
    # MLIR 的优势:
    # 1. 可扩展的 Dialect 系统
    # 2. 每家厂商可以定义自己的 Dialect
    # 3. 统一的 lowering 路径
    
    def mlir_pipeline():
        """
        MLIR 多后端编译流程
        """
        pipeline = """
        Frontend (PyTorch/TF)        Frontend (PyTorch/TF)
              ↓                              ↓
        Torch MLIR                    TF MLIR
              ↓                              ↓
        ─────────────────────────────────────────
                         ↓
                   Linalg Dialect
                   (通用算子表示)
                         ↓
        ┌────────────────┼────────────────┐
        ↓                ↓                ↓
    GPU Dialect     CPU Dialect      NPU Dialect
        ↓                ↓                ↓
    CUDA/ROCm        LLVM-IR         厂商 Dialect
        ↓                ↓                ↓
    SASS            native code     NPU Binary
        ↓                ↓                ↓
     GPU              CPU              NPU
        """
        print(pipeline)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

升华 ​

┌─────────────────────────────────────────────────────────────────────────────────┐ │ NPU 生态的核心洞察 │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 1. 专用硬件的代价是碎片化:没有 CUDA 这样的统一生态 │ │ │ │ 2. 脉动阵列是云端 NPU 的主流:专用硬件做矩阵乘,通用硬件处理控制流 │ │ │ │ 3. 量化是 NPU 的核心竞争力:INT8/INT4 的极致能效 │ │ │ │ 4. MLIR 可能是统一 NPU 生态 的希望:但需要时间成熟 │ │ │ │ 5. 实际部署要接受妥协:每个 NPU 都有自己的限制和癖好 │ │ │ └─────────────────────────────────────────────────────────────────────────────────┘

"AI 可查 vs 必须理解"清单 ​

必须理解(不理解就等于不会):

  • 🔴 脉动阵列的工作原理——NPU 的核心架构,不知道就无法理解为什么叫"脉动"
  • 🔴 NPU 和 GPU 的本质区别——专用 vs 通用,能效 vs 灵活
  • 🔴 量化校准的必要性——NPU 原生支持 INT8,但需要校准才能保证精度
  • 🔴 Delegate 模式——TFLite 如何扩展到 NPU

AI 可查(知道去哪查就行):

  • ✅ 具体 NPU 的 SDK API——每个厂商都不同,需要时查官方文档
  • ✅ 特定 NPU 的算子支持列表——厂商会提供,但经常变化
  • ✅ 量化参数的具体计算方式——INT8 的 scale/zero_point
  • ✅ 厂商特定的优化技巧——通常是经验积累,需要交流

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇16. CUDA 后端:合并访存与 Tensor Core / CUDA Backends, Memory Coalescing, and Tensor Cores
下一篇18. Kernel 性能基础:Roofline 与 Occupancy / Kernel Performance Fundamentals with Roofline and Occupancy

持续记录,持续成长

Copyright © Tidenflow