犀牛鸟 2026 研究笔记 estelledc.github.io

MNN 与 ncnn 对照:学完 MNN 再读 ncnn 的桥梁

MNN 精读见 精读: mnn(用户正在学习) ncnn 精读见 精读: ncnn ncnn 贡献指南见 竞赛指南: ncnn

调研元信息

日期 2026-06-22
环境 macOS / Apple Silicon
实测状态 未实测,以已有精读 + 源码为准
流水线段 Deploy/Run(两引擎内部机制对照)

一句话定位

为正在学 MNN 的你架一座桥——把 MNN 里学到的概念一一映射到 ncnn 的对应设计,让你「学一个等于学两个」。

日常类比

MNN 是一辆「全功能房车」(能住能做饭能开),ncnn 是一辆「赛车」(极致轻量极致快,但只能开不能住)。两辆车的引擎原理相通(内燃机/SIMD),但设计哲学截然不同——理解房车的人再看赛车会觉得「原来可以这么简单」。


核心对照表

维度 ncnn MNN 关键差异
内存布局 elempack 动态打包(NEON=4, AVX=8, AVX-512=16) NC4HW4 固定按 4 打包 ncnn 按 SIMD 宽度自适应;MNN 固定 4,AVX-512 浪费 75%
调度模型 按需递归(Lazy Eval),从输出反向触发 Pipeline 四步(onResize + onExecute),正向全图调度 ncnn 不用的层完全不执行;MNN 全图统一优化
GPU 后端 Vulkan Compute Shader 一套 GLSL OpenCL + Metal + Vulkan + CUDA ncnn 一套代码全平台;MNN 每平台最优但代码量大
模型转换 PNNX(保留 PyTorch 语义)+ onnx2ncnn MNNConvert(ONNX/TF/Caffe/TorchScript) PNNX 更精确;MNNConvert 输入格式更多
图优化 极简(层融合为主,无独立 pass 系统) Geometry Compiler(Op 降级为 Region 描述 + Raster 合并) MNN 优化更深但复杂度更高
LLM 推理 无(社区实验) 内建 MNN-LLM(KV-Cache + 分词 + 采样) MNN 独有优势
端侧训练 不支持 支持 MNN 独有
代码量 约500 文件 约2000 文件 ncnn 4x 更精简
C++ 标准 不用 C++11 C++14+ ncnn 更保守
依赖 零第三方 protobuf + flatbuffers 等 ncnn 可嵌入任何环境
许可证 BSD 3-Clause Apache 2.0 均商业友好

概念映射详解

1. 内存布局:elempack vs NC4HW4

graph LR
    subgraph ncnn[ncnn: elempack 动态]
        A[检测 SIMD 宽度] --> B{ARM NEON?}
        B -->|是| C[elempack=4]
        B -->|否| D{AVX2?}
        D -->|是| E[elempack=8]
        D -->|否| F{AVX-512?}
        F -->|是| G[elempack=16]
    end
    
    subgraph MNN[MNN: NC4HW4 固定]
        H[始终 pack=4] --> I[NEON 刚好用满]
        H --> J[AVX2 只用一半]
        H --> K[AVX-512 只用1/4]
    end

MNN 学习收获映射到 ncnn:你在 MNN 理解了「为什么要通道打包」(SIMD 一次处理多通道),再看 ncnn 时会发现它更进一步——运行时动态适配硬件宽度,但代价是内存管理更复杂。

2. 调度模型:Lazy Eval vs Pipeline

MNN Pipeline 四步 ncnn 对应
onResize():分配内存 无对应,按需分配
onExecute():执行计算 Layer::forward():计算+分配一体
Buffer 复用优化 Light Mode:blob 消费即释放
全图正向调度 从 output blob 反向递归

MNN 学习收获:你理解了「分离内存分配和计算的好处」(onResize 提前规划内存复用)。ncnn 走另一条路——lazy eval 根本不给不需要的层分配内存。trade-off:MNN 全图可全局最优化内存复用;ncnn 更简单但可能局部次优。

3. GPU 后端:统一 vs 分治

MNN 做法 ncnn 做法
OpenCL(安卓主力) Vulkan(安卓 + macOS + Windows)
Metal(iOS 专属) Vulkan 覆盖 iOS(有限支持)
CUDA(服务端扩展) 无 CUDA
每平台最优实现 一套 GLSL 全平台

MNN 学习收获:你理解了「为什么 GPU 编程要处理内存布局转换、命令队列同步」。ncnn 的 Vulkan 后端让你看到「如何用一套 Compute Shader 抽象跨所有 GPU」——但代价是某些平台可能不如 MNN 的 Metal/OpenCL 专属实现。

4. 模型转换:MNNConvert vs PNNX

MNNConvert PNNX
输入:ONNX/TF/Caffe/TorchScript 输入:TorchScript(优先),可出 ONNX
输出:.mnn 单文件 输出:.param + .bin + Python 可读 .py
特色:集成量化选项 特色:保留 PyTorch nn.Module 语义
可读性:二进制,需 viewer 可读性:.param 人类可读文本

5. 图优化深度对比

graph TD
    subgraph MNN[MNN Geometry Compiler]
        M1[原始 Op 图] --> M2[非计算 Op 降级为 Region]
        M2 --> M3[Region 合并为 Raster Op]
        M3 --> M4[核心 Op 保留原生实现]
        M4 --> M5[新后端只需实现核心 Op]
    end
    
    subgraph ncnn[ncnn 图优化]
        N1[原始 Layer 图] --> N2[层融合: Conv+BN+ReLU]
        N2 --> N3[直接执行]
    end

MNN 的 Geometry Compiler 是「编译器级」优化——新增后端的工程量从 O(全部 Op) 降为 O(核心 Op)。ncnn 则采取「够用就好」——层融合解决 90% 性能问题,剩下的靠手写 SIMD/GLSL。


学完 MNN 再读 ncnn 的推荐路线

顺序 ncnn 文件/目录 对应 MNN 知识 阅读目标
1 src/mat.h + src/mat.cpp MNN Tensor/Buffer 理解 elempack 动态打包
2 src/layer.h MNN Op 基类 对比 forward vs onExecute
3 src/net.cpp (Extractor) MNN Session/Pipeline 理解 Lazy Eval 调度
4 src/layer/convolution.cpp MNN CPUConvolution 对比 SIMD 优化实现
5 src/gpu.h + layer/vulkan/ MNN OpenCL/MetalBackend 对比 GPU 抽象层
6 tools/pnnx/src/ MNN tools/converter/ 对比转换链实现

预计每步 1-2 小时,总计 1 周可完成 ncnn 源码初览。


何时选 ncnn、何时选 MNN?

场景 推荐 理由
安卓 App 嵌入,追求最小体积 ncnn 约1MB,零依赖
iOS App,追求 Metal 最优性能 MNN Metal 后端成熟
端侧 LLM / 大模型推理 MNN 内建 MNN-LLM
犀牛鸟竞赛贡献(ncnn 赛道) ncnn 直接相关
需要端侧训练/fine-tune MNN 唯一支持者
跨平台 GPU 加速(含 Windows) ncnn Vulkan 全覆盖
纯 CPU 推理,YOLO 检测 两者皆可 性能接近,看熟悉度

证据等级

标签 来源
[已有] deep-dive-ncnn.md(elempack + Vulkan + Lazy Eval), deep-dive-mnn.md(Geometry + NC4HW4 + Pipeline)
[源码] /tmp/ncnn src/, /tmp/MNN source/
[文档] ncnn wiki, MNN 官方文档