Ch02: 阅读路线图——三条路径任你选
Part 1: 导读总纲 前置章节:Ch01: 为什么需要这本导读 后续章节:Ch03: 前置知识检查清单
1. 三条路径说明
这本导读内容不少,但你不需要从头读到尾。根据你的目标和可用时间,我设计了三条路径。每条路径像一条登山步道——起点不同、长度不同、终点也不同,但都能让你看到有价值的风景。
先说结论:
- 如果你的目标是参加犀牛鸟竞赛、给 ncnn 贡献代码,走竞赛路径,大约 2 周
- 如果你想系统理解移动端推理引擎的设计空间,走深度学习路径,大约 1 个月
- 如果你已经学过 MNN 想快速理解 ncnn 有何不同,走 MNN→ncnn 桥接路径,大约 3 天
三条路径不是互斥的。你完全可以先走竞赛路径拿到参赛所需的最低知识,然后在竞赛过程中按需切换到深度学习路径补充理解。桥接路径则是给有 MNN 基础的同学提供的快车道。
下面逐一展开。
2. 竞赛路径(2 周):目标理解 ncnn 做开源贡献
适用人群:准备参加犀牛鸟竞赛或想给 ncnn 提第一个 PR 的同学。
核心思路:只读和 ncnn 直接相关的章节,跳过横向对比,快速建立对 ncnn 代码库的工作理解。
时间分配(共约 80 小时 / 2 周全职):
第一阶段:建立背景(2 天)
- 读 Part 1 全部三章(Ch01-Ch03),建立宏观认知
- 完成前置知识自检,补齐短板
第二阶段:理解通用架构(3 天)
- 读 Part 2 中”计算图表示”和”内存管理”两章
- 读 Part 2 中”算子与调度”章节
- 重点理解:什么是计算图、为什么需要内存复用、算子是什么
第三阶段:深入 ncnn(5 天)
- 读 Part 3 中 ncnn 专题的全部内容
- 重点章节:ncnn 的模型格式(.param/.bin)、Mat 数据结构、算子注册机制、ARM NEON 优化
- 对照 ncnn 源码阅读,跑通至少一个 example
第四阶段:实战准备(4 天)
- 读 Part 6 中”开源贡献实践”相关内容
- 浏览 ncnn 的 issue 列表,找到标记为 “good first issue” 的任务
- 尝试在本地修改并编译 ncnn,跑通测试
- 写一个小 PR(哪怕只是修个文档 typo 或补个注释)
路径流程图:
graph TD
A["Part 1: 背景建立 (2天)"] --> B["Part 2: 通用架构 (3天)"]
B --> C["Part 3: ncnn 深入 (5天)"]
C --> D["Part 6: 实战贡献 (4天)"]
A --> |"自检不通过"| E["补前置知识"]
E --> B
C --> |"遇到不理解的优化"| F["回看 Part 2 对应章节"]
F --> C
D --> |"PR 方向不确定"| G["回看 ncnn 设计哲学"]
G --> D
关键提醒:竞赛路径的目标不是”读完所有内容”,而是”能写出合格的贡献”。如果在第三阶段读 ncnn 源码时遇到某个优化技巧看不懂(比如 pack4 是什么),可以暂时跳过细节,先建立整体理解,后续按需回补。
3. 深度学习路径(1 个月):系统理解六个框架设计取舍
适用人群:想系统理解移动端推理引擎设计空间的同学,可能未来要做框架开发、硬件适配或技术选型。
核心思路:按照 Part 的顺序完整阅读,每个框架都了解,重点理解不同框架在相同问题上的不同选择。
时间分配(共约 160 小时 / 1 个月全职或 2 个月兼职):
第一周:基础层
- Part 1 全部(3 天)——宏观认知 + 前置准备
- Part 2 的前半部分(4 天)——计算图、内存管理、算子调度
第二周:核心概念层
- Part 2 的后半部分(3 天)——量化、多后端架构、模型格式
- Part 3 开始:ncnn + TNN(4 天)——理解”极简派”和”架构升级派”
第三周:框架对比层
- Part 3 续:MNN + ORT(4 天)——理解”全栈派”和”标准化派”
- Part 3 续:Paddle-Lite + MACE(3 天)——理解”广覆盖派”和”深度优化派”
第四周:高级主题 + 实战层
- Part 4:硬件适配深入(3 天)——ARM/GPU/DSP/NPU 各自的编程模型
- Part 5:高级优化(2 天)——编译优化、自动调优
- Part 6:综合实战(2 天)——选型指南、贡献实践
学习方法建议:每读完一个框架的章节,写一段 200 字的”设计决策摘要”——用自己的话说清楚这个框架做了什么选择、为什么这样选、代价是什么。四周下来你会积累 6 份这样的摘要,它们合在一起就是一份有价值的横向对比文档。
路径流程图:
graph TD
A["Week 1: Part 1 + Part 2 前半"] --> B["Week 2: Part 2 后半 + ncnn/TNN"]
B --> C["Week 3: MNN/ORT + Paddle-Lite/MACE"]
C --> D["Week 4: Part 4-5-6 高级主题"]
B --> |"每个框架写摘要"| E["设计决策摘要 x6"]
C --> |"每个框架写摘要"| E
D --> F["横向对比总结"]
E --> F
4. MNN→ncnn 桥接路径(3 天):已学 MNN 快速迁移
适用人群:已经读过 MNN 源码或用过 MNN 的同学,想快速理解 ncnn 和 MNN 的差异。
核心思路:利用你对 MNN 的已有理解作为参照系,通过对比来快速定位 ncnn 的设计特点。
时间分配(共约 24 小时 / 3 天全职):
Day 1:宏观对比(8 小时)
- 快速浏览 Part 1 Ch01 的框架一句话介绍(跳过你已知的背景知识)
- 读 Part 2 中关于”设计哲学谱系”的章节——理解 ncnn 和 MNN 在谱系中的位置
- 重点理解核心差异:MNN 有几何计算中间层,ncnn 没有;MNN 做端侧训练,ncnn 只做推理;MNN 用 flatbuffers,ncnn 用自定义文本格式
Day 2:深入差异点(8 小时)
- 读 Part 3 ncnn 专题中的”模型格式”——对比 MNN 的 flatbuffers 方案,理解 ncnn 的 .param 文本格式为什么选择可读性优先
- 读”内存管理”——对比 MNN 的内存池方案,理解 ncnn 的 Allocator 设计
- 读”算子实现”——对比 MNN 的几何计算 + 后端分发,理解 ncnn 的”直接写汇编”风格
Day 3:代码级验证(8 小时)
- 克隆 ncnn 仓库,对照你熟悉的 MNN 目录结构,映射关键文件的对应关系
- 跑通一个 ncnn example,体会从 API 使用层面的差异
- 读一个相同算子(如 Convolution)在两个框架中的实现,体会风格差异
MNN vs ncnn 核心概念映射表:
| 维度 | MNN | ncnn | 关键差异 |
|---|---|---|---|
| 设计哲学 | 全栈运行时 | 极简推理库 | ncnn 只做推理,没有训练 |
| 模型格式 | .mnn(flatbuffers) | .param(文本)+ .bin(二进制) | ncnn 的 param 人眼可读 |
| 计算图 | 图+几何计算中间表示 | 只有原始算子图 | MNN 多一层抽象 |
| 内存管理 | 统一内存池 | Allocator 接口 + 引用计数 | ncnn 更轻量 |
| 后端适配 | Backend 抽象层 | 直接在算子里写各后端代码 | ncnn 耦合度更高但更直接 |
| 优化风格 | 几何计算自动拆分 + 手写 | 纯手写汇编 / intrinsics | ncnn 对程序员要求更高 |
| 依赖 | OpenCL/Vulkan/Metal 可选 | 零第三方依赖 | ncnn 编译极简 |
5. 每条路径的检查点自测问题
学习最怕的是”感觉懂了但其实没懂”。每条路径设置了检查点,到达检查点时用这些问题自测。能清楚回答说明可以继续往下走;答不上来说明需要回头补。
竞赛路径检查点
检查点 1(Part 1 完成后):
- 推理引擎和训练框架的本质区别是什么?
- 移动端推理面临的四个核心约束分别是什么?各约束和服务器的差距大约多少倍?
- ncnn 的一句话定位是什么?它和 MNN 最本质的区别是什么?
检查点 2(Part 2 核心章节完成后):
- 什么是计算图?为什么推理引擎需要计算图而不是直接执行代码?
- 内存复用解决什么问题?常见策略有哪些?
- 算子的输入输出是什么?算子和层(Layer)有什么关系?
检查点 3(ncnn 专题完成后):
- ncnn 的 .param 文件格式长什么样?为什么选择文本格式?
- Mat 的内存布局是什么?为什么用 elempack?
- ncnn 如何注册一个新算子?写一个新算子的最少步骤是什么?
- ncnn 的 ARM NEON 优化采用什么策略?pack4 是什么意思?
检查点 4(准备提 PR 前):
- ncnn 的编码风格有什么特点?(缩进、命名、注释风格)
- ncnn 的 CI 跑哪些测试?你的 PR 需要通过什么?
- 你选择的 issue 属于哪个模块?改动会影响哪些文件?
深度学习路径检查点
检查点 1(Week 1 完成后):
- 能画出一个推理引擎从模型加载到推理完成的通用流水线吗?
- 计算图优化有哪几大类?每类解决什么问题?
- 静态内存规划和动态内存分配各自的适用场景是什么?
检查点 2(Week 2 完成后):
- 量化的本质是什么?对称量化和非对称量化有何区别?
- ncnn 和 TNN 的架构差异是什么?TNN 的双层抽象解决了 ncnn 的什么问题?
- 给一个新芯片写 ncnn 后端 vs 写 TNN 后端,工作量差异在哪?
检查点 3(Week 3 完成后):
- MNN 的几何计算是什么?它试图解决什么问题?为什么 ncnn 不需要?
- ORT 的 Execution Provider 机制是什么?和 MNN 的 Backend 有什么异同?
- Paddle-Lite 如何做到支持 13+ 后端?它的子图分割策略是什么?
- MACE 对 Hexagon DSP 的优化深入到什么程度?
检查点 4(Week 4 完成后):
- ARM CPU、移动 GPU、DSP、NPU 各自擅长什么类型的计算?
- 如果让你给一个新场景选推理引擎,你的决策框架是什么?
- 给开源推理引擎贡献代码,最重要的三个注意事项是什么?
MNN→ncnn 桥接路径检查点
检查点 1(Day 1 完成后):
- ncnn 和 MNN 在设计谱系中的位置差异是什么?
- ncnn 不做端侧训练这个选择带来了哪些简化?
- ncnn 零依赖的设计如何影响它的编译和部署?
检查点 2(Day 2 完成后):
- MNN 的几何计算层在 ncnn 中由什么替代?这意味着什么?
- ncnn 的 .param 文本格式和 MNN 的 flatbuffers 各自的优劣是什么?
- 同一个 Convolution 算子,MNN 的实现路径和 ncnn 的实现路径有何不同?
检查点 3(Day 3 完成后):
- 你能在 ncnn 代码库中快速定位到某个算子的实现文件吗?
- ncnn 的 API 使用和 MNN 的 API 使用,开发者体验有何不同?
- 基于你对两个框架的理解,ncnn 更适合什么场景,MNN 更适合什么场景?
6. 时间管理建议
不管走哪条路径,有几个时间管理原则值得注意。
原则一:阅读和实践穿插进行。不要连续读三天理论再开始写代码。最好的节奏是:读一个概念,马上去代码里找到对应实现看一看,哪怕只是用 grep 搜一下关键词确认”确实存在这个东西”。理论和代码交替进行,理解会更扎实。
原则二:设置硬性截止时间。尤其是竞赛路径,2 周是上限不是下限。如果某个章节花了超过预期 50% 的时间还没读完,可能不是你理解力的问题——可能是你陷入了不必要的细节。跳过继续往下走,很多问题会在后续章节中自然解决。
原则三:优先广度再深度。先把整条路径快速走一遍(每章只读开头和小结),建立全景地图;然后再回来深入读具体章节。人类的学习不是线性的——先有框架再填细节,比从第一页开始逐字读效率高得多。
原则四:利用碎片时间复习。每天开始学习前,花 5 分钟回忆昨天学了什么。能回忆起来说明记住了;回忆不起来的地方就是今天需要复习的起点。这个简单的习惯能显著提高长期记忆的效果。
原则五:遇到卡点及时标记。读不懂的地方不要死磕超过 30 分钟。标记一下(在旁边写”TODO:不理解 xxx”),继续往下走。很多时候后面的内容会回过头来解释前面的概念。如果走完整条路径后卡点仍然存在,再针对性地去找其他资料补充。
原则六:对竞赛路径同学的特别提醒。犀牛鸟竞赛的评审周期有截止日期。你的时间规划必须留出至少 3 天的缓冲。因为第一次给开源项目提 PR,几乎一定会遇到意想不到的问题:CI 挂了、maintainer 要求改动、代码风格不符合要求。这些都是正常的学习过程,但需要时间去处理。
7. 本章小结
回顾本章的核心要点:
- 本导读提供三条阅读路径:竞赛路径(2 周)、深度学习路径(1 月)、MNN→ncnn 桥接路径(3 天)
- 竞赛路径聚焦 ncnn 一个框架,目标是能写出合格的开源贡献
- 深度学习路径覆盖六个框架,目标是理解设计空间中的不同选择和权衡
- 桥接路径利用 MNN 已有知识,通过对比快速理解 ncnn 的设计特点
- 每条路径都有检查点自测问题,能答上来才继续往下走
- 时间管理六原则:理论实践穿插、设硬截止、先广后深、碎片复习、卡点标记、留缓冲
下一章我们检查前置知识——确认你在开始正式阅读之前需要准备什么。
导读目录:README.md 上一章:Ch01: 为什么需要这本导读 下一章:Ch03: 前置知识检查清单