端侧 AI · 15 天工程路线
目录首页 English
DAY 04

算子与 Kernel

从数学定义走到布局、融合与硬件执行路径

建议阅读:约 18 分钟

学习目标

理解算子语义、内存布局、kernel 选择和算子融合之间的关系。

本章关键词

关键词解释ESP32 工程类比
Kernel针对具体硬件实现一个算子的低层计算代码。像同一外设 API 的芯片专用驱动。
Layout张量维度在内存中的排列方式,如 NCHW 或 NHWC。像结构体字段和对齐规则。
Fusion将多个连续算子合并为一次执行。像把多个小 DMA 事务合并以减少中断和搬运。
Tiling把大计算分块以适配寄存器或 cache。像用分块 buffer 处理长数据流。

承上:回顾与定位

上一章把浮点值映射到低比特表示;本章追踪这些值如何被算子、布局与 kernel 真正执行。

从源头看今天

历史发展脉络

算子的历史有两条交织路线:一条发明能表达任务的网络结构,另一条把这些数学结构变成可高效执行的 kernel。卷积网络从层级感受野走到端到端训练后,GPU 原语库把优化实现与框架分开,编译器又把融合、布局和调度自动化。现代 runtime 的职责正位于数学图与异构硬件之间。

1980

Neocognitron 展示层级局部感受野与位移鲁棒性

Fukushima 的 Neocognitron 以层级结构处理视觉模式,并追求位置变化下的识别。它不是今天以反向传播训练的 Conv kernel,却把局部连接、特征层级和空间复用带入了卷积网络谱系。

Neocognitron 原始论文 ↗
1998

LeNet 把卷积、下采样与梯度训练连成应用系统

LeCun 等人的文档识别工作系统化展示了卷积网络及端到端梯度学习。算子不再是孤立公式,而是与输入几何、权重共享和任务后处理共同构成可运行流水线。

LeNet 文档识别原始论文 ↗
2014

cuDNN 将深度学习原语做成可复用高性能库

cuDNN 提供面向 GPU 的卷积等优化原语,使框架不必随每代并行硬件重写全部 kernel。论文把深度学习算子库类比 BLAS,并展示算法选择、内存使用与硬件优化可以隐藏在稳定接口之后。

cuDNN 原始论文 ↗
2018

TVM 把图融合与低层调度纳入统一编译搜索

TVM 同时处理高层算子融合、硬件原语映射与内存延迟隐藏,并用成本模型搜索低层优化。kernel 选择从厂商手写库扩展到可针对 CPU、GPU、FPGA 和加速器生成的调度空间。

TVM OSDI 原始论文 ↗
2020s

Execution Provider 让同一图按能力切给异构后端

ONNX Runtime 以 Execution Provider 接入不同硬件实现,并把支持的节点或子图分配给相应后端。现代部署因此不只问“有没有 NPU”,还要检查领取了哪些节点、边界搬运多少数据以及哪些路径回退 CPU。

ONNX Runtime Execution Providers 官方文档 ↗
今天为什么仍然重要: 从结构发明到 kernel 库,再到图编译与异构分区,核心问题始终是保持算子语义的同时减少无效搬运。端侧优化应从具体 shape、layout、量化参数和支持矩阵出发;峰值 TOPS 只有在子图足够完整、数据已位于正确内存时才可能兑现。
借熟悉的系统建立直觉

类比图解

同一份菜谱如何落到一间拥挤的专业厨房

算子像菜谱中的“切丁、翻炒、收汁”,只规定输入、动作和成品;kernel 是某位厨师在特定灶台上的具体手法。食材按取用顺序摆盘是 layout,把切丁和腌制合在同一案板上是 fusion,把一大锅拆成刚好放进炒锅的小份则是 tiling。菜谱没变,出餐速度可以相差数倍。

标准菜谱 算子名称、属性、输入输出和数值语义
厨师与灶台 针对 CPU、GPU、NPU 的不同 kernel 实现
备菜托盘 NHWC/NCHW、连续性、对齐和 buffer 所在内存
分锅快炒 tiling 让工作集适配寄存器或 cache

类比的边界: 厨房类比不能表达并行线程、向量指令和浮点舍入,也容易让人误以为融合总是有利;真实 fusion 会受量化尺度、分支复用和 backend 支持限制,数值等价与性能收益都必须用目标硬件验证。

本章讲解

算子契约包含属性、边界与数值约定

Conv 不只是一条求和公式,还包括 stride、padding、dilation、groups、权重维度顺序和输出 shape 规则;Softmax 还必须指定归一化 axis 与稳定计算方式。两个 runtime 都声称支持同名算子,也可能只覆盖部分 dtype 或属性组合。模型接入时应从真实节点导出契约表,并用非对称 shape 与边界输入验证。

同一 Conv 可以对应多种算法与 workspace 交换

直接卷积、im2col+GEMM、Winograd 或硬件专用路径具有不同适用区间。im2col 便于复用成熟矩阵乘 kernel,却可能展开出大 buffer;Winograd 可减少部分乘法,但对尺寸、数值精度和变换开销敏感。backend 的算法选择必须连同实际 shape、可用 workspace 和量化模式测量,不能只比较理论 MAC。

Layout 决定相邻数据是谁,也决定向量单元吃得顺不顺

NCHW 与 NHWC 改变通道和空间维在内存中的邻接关系;即使维度名称一致,stride 不连续也可能触发隐式 copy。某个 kernel 偏好通道连续,另一个加速器却要求块化布局,边界转换便会整张读写激活。profile 时应把 transpose、reorder 和 memcpy 当作正式节点计时,而非归入无法解释的框架开销。

Tiling 的目标是让重复使用发生在最快的存储层

GEMM 将 M、N、K 分块后,把小块输入和权重装入寄存器或 cache,多次 MAC 后才写回;tile 过大会溢出工作集,过小又增加循环与边界开销。SIMD 还要求对齐,并为尾部元素处理 mask 或标量路径。在 ESP32 上应测试真实地址、对齐和 DMA 来源,因为桌面数组的理想连续性不会自动出现。

融合与加速器分区要用“少落地几次”来验收

Conv、Bias、ReLU 融合可让中间值留在寄存器或片上 SRAM,但若某输出还被旁路节点消费,或相邻算子的量化尺度不兼容,融合可能受限。NPU 子图两侧同样会产生同步、布局变化和 copy。验收报告应列出融合前后节点、分区边界、搬运字节与端到端时间,避免用单个 kernel 加速比替代系统收益。

让数据真正跑起来

动态过程演示

Conv–BN–ReLU 如何落成一次分块执行

动画从抽象图逐层下钻到内存:先核对算子契约,再选择融合与布局,最后让 tile 在片上缓冲区中循环装载、计算和写回。

步骤 1 / 6

展开算子契约 · Conv(stride,pad,groups) → BN → ReLU

属性卡附着到节点,输入输出 shape 同步变化

观察点

同名算子只有属性、axis 与 dtype 都匹配才算语义兼容

循环 / 返回条件: tile 沿输出空间循环直到完成;切换 layout、tile 大小或 backend 时,动画重置计数器并并排保留上一轮的字节数、workspace 与延迟。

查看静态全景图
Graph: Conv → BN → ReLU
Optimizer: Conv+BN+ReLU fusion
Kernel: tile → load → MAC → store

代码或命令示例

for (m_tile : M)
  for (n_tile : N)
    acc = 0
    for (k_tile : K) acc += A * B
    C = acc + bias

动手实验

分别计算一个 1x1 Conv 与 GEMM 的等价关系;记录转置、cache miss 和融合前后访存次数。
实验记录与导出

工程陷阱

避免误判: 把不支持的 NPU 子图与 CPU fallback 交错,会引入切分边界 copy;仅看 NPU 峰值 TOPS 无法预测端到端速度。

核心测试

完成 3 道单选题后提交;提交前不会显示答案。

1. 算子融合经常提速的主要原因是?
2. NCHW 到 NHWC 转换的风险是什么?
3. ONNX Runtime 多个 Execution Provider 的常见回退行为是?

一起把本章讲清楚

在 GitHub 上讨论本章

登录 GitHub 后提问、补充实测或分享你的实现;评论会保存在本课程的 GitHub Discussions 中。

评论区需要 JavaScript;也可以直接打开 GitHub 讨论区: 打开 GitHub 讨论区 ↗

延伸阅读

启下:下一章如何使用本章能力

下一章把数据、训练、转换、量化与固件 runtime 串成非 LLM 端侧部署闭环。

下一天: Day 5 · 端侧模型部署