他把YOLO26n搬进ARM64汇编

一名开发者用ARM64汇编与C从零实现YOLO26n推理,在树莓派4上加入NEON、Winograd、缓存分块和算子融合。项目跑通了检测链路,却也证明手写汇编不等于自动获得高性能。
YOLO26n被拆成了一套ARM64底层指令
一名开发者近日公开了自己的本科毕业项目:不依赖现成推理框架,使用ARM64汇编语言与C从零实现YOLO26n目标检测模型的推理,并把它部署到树莓派4上运行。
这不是把模型导出成ONNX,再交给现成Runtime执行的常规部署。开发者自己处理了权重提取、二进制格式设计、张量内存布局、卷积与矩阵乘内核、注意力机制、检测头,以及最终输出等完整链路。项目还加入ARM NEON SIMD、Winograd卷积、缓存感知分块、自定义微内核和算子融合等优化手段。
更准确地说,这个项目并非“整套模型全部由汇编编写”,而是一套由ARM64汇编与C共同组成的无框架推理引擎。汇编负责适合手工优化的计算热点,C负责调度、数据组织和部分算子逻辑,这也是现实中的高性能计算程序更常见的结构。
截至2026年7月26日,开发者已经确认这套实现能够给出正确的目标检测结果。不过,他也坦率承认,最终性能提升低于最初预期。原帖尚未提供足够完整的延迟、吞吐量、功耗、编译参数和基线数据,因此目前无法用具体数字判断它相对官方运行时或其他端侧框架究竟快了多少。

这项工作的重点不是再造一个YOLO应用
YOLO26n是YOLO26系列中面向轻量化和边缘部署的Nano规格目标检测模型。它接收图像张量,在单次网络前向传播中完成特征提取、特征融合和目标预测,适合摄像头、机器人和嵌入式设备等对实时性敏感的场景。
YOLO26的一项关键变化是原生端到端推理。所谓端到端推理,是模型可以直接生成最终检测结果,并在网络内部处理重复预测,而不必像传统检测器那样额外执行独立的非极大值抑制步骤。
非极大值抑制,即NMS,是根据置信度和边界框重叠程度删除重复检测框的后处理算法。NMS本身并不一定是桌面GPU上的主要瓶颈,但在移动端和嵌入式部署中,它会增加控制逻辑、内存访问和平台适配成本;将其从独立后处理链路中移除,有利于形成更统一的执行图。
这个毕业项目的真正价值,是把通常隐藏在PyTorch、ONNX Runtime、TensorRT或厂商SDK内部的过程全部摊开。开发者面对的不再是“调用模型”这一层抽象,而是每一个张量存放在哪里、每个循环如何访问缓存、每条向量指令一次处理多少数据,以及相邻算子能否共享中间结果。
从学习价值看,这比实现一个调用现成框架的目标检测Demo难得多,也更接近推理引擎工程师实际处理的问题。它未必会成为树莓派上最快的YOLO26n运行方案,却是一份相当完整的端侧推理引擎解剖案例。
从模型文件到检测结果,执行链被重新做了一遍
无框架推理的第一步不是写卷积,而是把训练框架中的模型转换成运行时能够稳定读取的数据。训练框架保存的权重通常包含参数名称、维度、数据类型和序列化元数据,但低开销推理更关心连续存储、对齐方式、读取顺序和计算内核需要的排列格式。
开发者从YOLO26n中提取参数,并重新设计了自定义二进制格式。自定义权重格式是针对特定推理流水线重新排列模型参数的文件结构,它可以减少启动阶段的解析、转置和临时内存操作,但也会牺牲通用性与生态兼容性。
这一步看似只是“换个文件格式”,实际会直接影响后续性能。如果卷积核权重的排列顺序与微内核的读取顺序一致,处理器可以连续加载数据;如果布局不匹配,程序就需要在推理前重新打包,或者在计算过程中进行跨步访问,两种方式都会付出额外成本。
项目随后实现了YOLO26n所需的多类模块,覆盖Conv、C3K2、SPPF、C2PSA、PSA、BottleNeck和Detect。它们并不是几个孤立函数,而是构成主干网络、特征融合、注意力处理和检测输出的完整组件。
| YOLO26n组件 | 在推理链中的作用 | 底层实现的主要难点 | |---|---|---| | Conv | 完成卷积、通道变换与局部特征提取 | 数据布局、边界处理、向量化和缓存复用 | | BottleNeck | 通过较短路径组合多层特征变换 | 残差数据的保存、相加与内存生命周期 | | C3K2 | 组织多分支卷积与瓶颈结构,提升特征表达 | 分支调度、中间张量复用和算子融合 | | SPPF | 以连续池化扩大感受野 | 池化窗口滑动、边界判断和重复读取 | | C2PSA | 将部分通道处理与注意力模块结合 | 张量切分、重排以及注意力计算开销 | | PSA | 根据特征关系重新分配信息权重 | 矩阵运算、归一化和数值稳定性 | | Detect | 把多尺度特征转换成类别、位置等预测 | 多输出解码、张量遍历和结果整理 |
注意力机制是根据特征之间的相关性动态调整信息权重的计算结构。它对提升模型表达能力有帮助,但对手写端侧引擎不算友好,因为其执行过程通常包含矩阵乘、张量变形、归一化和逐元素运算,计算形态比连续的大卷积更碎。
检测头则是目标检测网络把特征图转换成最终预测的输出模块。对于从零实现的引擎,得到一组浮点张量还不算完成任务,开发者还必须正确解释各维度含义、恢复边界框坐标、处理类别分数,并确保输出与参考实现一致。
NEON、Winograd和GEMM都上了,但汇编不是魔法
ARM NEON是ARM处理器上的128位SIMD向量指令扩展。SIMD允许一条指令同时处理多组整数或浮点数据,因此特别适合卷积、矩阵乘和逐元素运算这类重复计算。
树莓派4使用基于ARM Cortex-A72的64位处理器平台,支持ARMv8-A和NEON。以FP32为例,一个128位向量寄存器可以容纳4个32位浮点数;理论上,向量化能够显著减少标量循环的指令数量,但实际速度仍取决于加载、存储、流水线调度和缓存命中率。
Winograd卷积是通过额外的数据变换减少小尺寸卷积乘法次数的算法。它通常适合步幅为1的3×3卷积,但输入变换、权重变换和输出变换本身也有成本,因此并非所有张量尺寸都能获益。
GEMM是通用矩阵乘法,即计算矩阵乘积的基础内核。很多卷积可以通过数据重排或隐式映射转化为GEMM,但视觉模型中的矩阵形状并不总是规整;当矩阵过小、通道数不利于向量分块,或者重排成本过高时,峰值算力很难真正转化为端到端速度。
缓存感知分块是把大张量切成能够尽量留在CPU缓存中的小块。它的目标不是减少数学运算量,而是降低处理器等待主内存数据的时间,因为在现代CPU上,从内存取数据往往比执行一次乘加更昂贵。
自定义微内核是针对固定数据类型、寄存器数量和分块尺寸编写的最内层计算循环。一个优秀的ARM64微内核需要平衡向量寄存器占用、循环展开、加载延迟、乘加吞吐和结果回写,任何一项处理不当,都可能让手写汇编输给成熟编译器或经过长期调优的计算库。
算子融合是把相邻算子合并到同一执行过程,以减少中间张量写回内存的优化方式。例如,卷积之后的偏置处理和激活函数如果能够在寄存器中直接完成,就不必先把卷积结果完整写入内存,再重新读出进行下一步处理。
这些技术名词放在一起很有“性能拉满”的感觉,但它们不会自动叠加成线性加速。Winograd减少了乘法,却增加了变换;分块改善了缓存,却可能引入更多边界循环;融合减少了内存访问,却会让内核复杂度和寄存器压力上升。端到端优化的本质,是在这些成本之间找平衡,而不是把优化清单逐项勾完。
为什么写了汇编,速度仍可能没有想象中快
手写汇编不等于比框架更快,是这个项目给端侧开发者最有价值的提醒。成熟推理框架的“通用”并不意味着“没有优化”,其底层往往已经使用架构专用内核、预打包权重、线程池、图优化和算子融合,并针对大量张量形状做过选择策略。
第一个限制来自工作负载的碎片化。YOLO26n是轻量模型,单个算子的计算规模可能不足以让深度优化的微内核长时间保持高利用率,函数调度、张量切换、边界处理和数据重排反而会占据更高比例。
第二个限制来自内存带宽和缓存容量。CPU可能很快完成寄存器里的乘加,但权重、输入特征和输出特征必须不断在内存层级之间移动;只要数据布局或分块尺寸没有贴合实际缓存行为,算术内核再快也会在等待数据。
第三个限制来自Winograd的适用范围。Winograd更像一把专门处理特定卷积形状的刀,而不是通吃全模型的万能优化;对于1×1卷积、步幅变化、较小特征图和特殊通道数,它可能无法发挥优势。
第四个限制来自注意力与非卷积算子。卷积和GEMM容易形成规则的密集计算,而切分、拼接、池化、归一化、激活和检测结果整理的算术密度更低,它们会让整体速度受到Amdahl定律约束:即使主卷积被加速数倍,未优化部分仍会限制端到端收益。
第五个限制来自多线程调度。树莓派4拥有4个Cortex-A72 CPU核心,但单核微内核跑得快,不代表四核扩展效率同样理想;线程切分、共享缓存竞争、任务粒度和同步成本都会影响最终延迟。
第六个限制来自测量方法。单个GEMM内核的微基准、纯模型前向延迟、包含图像预处理的检测延迟,以及包含摄像头采集和结果绘制的应用延迟,是四组不同指标。如果不统一线程数、输入尺寸、精度、预热次数和计时范围,“快了多少”几乎没有可比性。
原作者只表示性能提升低于预期,而没有在现有材料中给出可复核的具体数字。对这类项目最合理的评价不是猜测加速比例,而是等待它补充基准环境、各算子耗时、峰值内存、功耗和对比对象。
它与常见部署方案的差别有多大
这套实现选择了最难维护、但最能暴露底层问题的一条路。对多数产品团队而言,使用成熟运行时仍是更务实的方案;对希望理解推理引擎的人而言,从零实现则能提供框架无法替代的训练。
| 路线 | 开发成本 | 可移植性 | 性能上限 | 调试与维护 | 更适合的目标 | |---|---:|---:|---:|---:|---| | PyTorch等训练框架直接运行 | 低 | 高 | 通常不是端侧最优 | 容易 | 快速验证模型 | | 通用端侧推理运行时 | 中 | 较高 | 较高 | 较成熟 | 产品部署与跨设备适配 | | 厂商专用SDK或加速器 | 中到高 | 低 | 特定硬件上较高 | 受平台约束 | 量产设备 | | ARM64汇编与C自研引擎 | 极高 | 很低 | 理论上可深度定制 | 困难 | 研究、教学和固定硬件极限优化 |
自研引擎最大的优势是控制权。开发者可以为YOLO26n的固定张量形状设计内存池,为特定卷积尺寸准备微内核,并删除所有不需要的通用逻辑,最终得到体积小、依赖少、执行路径清晰的程序。
自研引擎最大的代价是持续维护。模型结构一旦变化,算子和权重转换器就可能跟着修改;处理器从Cortex-A72换成其他ARM核心后,最佳分块、预取距离和指令调度也未必继续成立;如果后续加入FP16、INT8或其他量化格式,内核、校准和数值验证还要重新进行。
因此,这个项目目前更像一台透明的“推理发动机教学模型”,而不是可以直接替代成熟运行时的成品。它把发动机拆开,让开发者看到活塞如何运动,但真正量产还要考虑稳定性、兼容性、工具链和维护成本。
下一步最值得补的不是更多汇编
完整的性能剖析是这个项目下一阶段最需要补齐的内容。与其继续增加汇编代码,不如先把总延迟拆成卷积、注意力、池化、张量重排、检测头和内存复制等部分,找出真实热点。
可复现基准至少应公开以下信息:
- 树莓派4的具体内存版本、系统版本、CPU频率和散热条件;
- 模型输入分辨率、权重精度和输出一致性标准;
- 单线程与四线程的平均延迟、P50和P95延迟;
- 预热次数、测试轮数,以及是否包含图像预处理;
- 与同硬件、同精度、同输入尺寸运行时的对比;
- 峰值内存、二进制体积、CPU占用和整机功耗;
- 每类算子的耗时占比与缓存未命中情况。
量化也可能比继续打磨FP32汇编带来更大的系统收益。量化是把模型权重和激活从高精度浮点数转换为较低位宽数值的技术,它可以减少模型体积、内存带宽和计算成本,但必须重新验证检测精度与算子支持情况。
不过,量化并非简单地把FP32换成INT8。比例因子、零点、累加精度、溢出处理和重新量化都会进入执行链,而不同ARM核心对点积类指令的支持也不完全相同;树莓派4的Cortex-A72并不具备后来部分ARM核心上的全部整数点积加速能力,因此收益仍需实测。
真正稀缺的是理解边界,而不是重复造轮子
这项工作最值得肯定的地方,是开发者没有把“成功运行”包装成“全面超越框架”。他在实现NEON、Winograd、GEMM、缓存分块、微内核和融合之后,仍然公开承认性能收益不及预期,这比只展示一张检测截图更有工程价值。
端侧AI优化的难点也由此变得清楚:模型算力只是问题的一部分,数据移动、缓存、线程、张量形状、算子覆盖率和工具链成熟度共同决定最终体验。一个微内核的漂亮跑分,不能直接代表整套视觉系统的延迟。
对普通应用开发者而言,没有必要照着这个项目重写一遍YOLO26n。对编译器、推理引擎、芯片软件栈和嵌入式AI方向的开发者而言,这却是一条很好的学习路线:先实现正确结果,再建立逐层对齐测试,随后做性能剖析,最后只对真正的热点下手。
这个项目最终证明的不是“汇编一定更快”,而是“性能必须被测量”。当一个模型脱离框架之后,所有曾被抽象层隐藏的成本都会重新出现;能把这些成本逐项解释清楚,本身就比一次缺少基线的速度领先更有价值。
参考来源
- Reddit:开发者介绍用ARM64汇编与C从零实现YOLO26n推理:本项目的一手说明,列出了树莓派4部署、NEON、Winograd、GEMM、缓存分块、算子融合及已实现的YOLO26组件。
- 知乎:YOLO26发布与原生端到端推理介绍:用于了解YOLO26将重复预测过滤整合进网络、减少独立NMS后处理的架构背景。



