
做嵌入式五年我一直有个错觉AI部署就是把训练好的模型换成另一个推理引擎在板子上加几行代码调用。直到被安排去做端侧AI项目在嵌入式Linux板卡上调一个手势识别模型连着加了两周班最后发现瓶颈根本不是推理代码而是我连CNN的卷积层为什么会在NPU上产生数据搬运瓶颈都说不清楚。我决定重新从CNN开始把之前“跳过去”的基础课一门门补回来。这篇文章想把这段转型和补课的经历写下来尤其是那些文档里查不到、实际项目里又一定会遇到的细节供同样从嵌入式转端侧AI的同行参考。如果你也正准备走这条路或者已经在端侧AI项目里被模型折腾得够呛这篇干货应该能帮你少踩几个坑。1. 为什么端侧AI让我回头补CNN的课1.1 嵌入式开发者转型端侧AI的三个“错位感”从传统嵌入式转到端侧AI最先冲击我的不是代码而是思维方式。做单片机或者嵌入式Linux的时候我们的思维模型是确定的一个中断来了一个事件发生我写一个处理函数数据是确定的链路是线性的时序是可以掐着手指算出来的。但是到了AI模型这里一切都变成了“概率”和“统计”同一个输入可能得到不同的输出权重模型的中间过程是一个黑盒出了问题你想靠断点调试去定位基本无从下手。第二个错位感是性能指标。嵌入式里我们习惯说“这个中断响应时间是10微秒”、“这个串口波特率是115200”都是确定值。端侧AI里面我们说的是“帧率”、“FPS”、“模型延迟”、“内存占用”而且这些数字不是固定的同一个模型在不同平台、不同量化精度、不同输入尺寸下会疯狂变化。我在板卡上第一次跑通一个CNN模型的时候FPS只有2.5我当时以为是自己代码写得烂后来发现是卷积层的计算量本来就在那里跟代码好坏关系不大。第三个错位感更隐蔽系统的边界。传统嵌入式里CPU负责逻辑外设负责输入输出边界清晰。端侧AI系统里CPU要跑预处理、后处理NPU或者GPU要跑卷积算子内存要兼顾模型权重、中间特征图、输入输出缓冲区还有DMA搬运调度。边界在哪里、数据的生命线是怎么走的这些问题必须重新建立认知。这三个错位感叠加在一起让我意识到如果不补CNN的基础后面每一个性能问题都会变成一个玄学问题。1.2 端侧AI部署不是“调接口”是三个层次很多嵌入式工程师接触端侧AI的第一反应是我已经会用NCNN调模型了我已经用TensorFlow Lite转换过模型了那就算掌握端侧AI了。说实话我一开始也是这个状态。但这个状态在真实项目里撑不过三轮追问。第一轮追问模型为什么在板子上精度掉这么多答不上来。第二轮追问这个算子在NPU上没跑起来回退到CPU了你能从模型结构上解释为什么吗答不上来。第三轮追问模型显存占用为什么是这么大你大概能答上来“因为模型参数多”但你再问一句“哪些层占用的显存最多”你就得去看逐层分析这就逼你一定要懂CNN的特征图尺寸是怎么算出来的。我把端侧AI部署的能力拆成三个层次。最表层是框架层你会用NCNN、RKNN、TFLite、ONNX Runtime这些推理引擎知道怎么加载模型、喂数据、取输出这相当于你会用API中间是算子层你理解模型结构里的卷积、池化、全连接、激活函数这些算子在硬件上怎么执行哪些算子适合NPU加速、哪些只能CPU硬扛这相当于你懂编译原理最底层是算法层你理解CNN的特征提取机制、感受野、权重共享、量化原理这相当于你理解程序语言本身的语义。如果只停留在第一层你在端侧AI项目里的角色就是一个调包侠遇到问题只能上网搜搜不到就卡死。我决心从第三层开始补先把CNN吃透。1.3 为什么我选择从CNN重新开始而不是先啃Transformer当时我也犹豫过四五年过去Transformer已经席卷了AI领域图像任务里ViT也表现强势直接学Transformer会不会“一步到位”但我最终还是决定先从CNN开始原因是三个很现实的因素。第一端侧硬件生态对CNN的支持成熟度远高于Transformer。NPU、DSP、GPU上的卷积算子优化已经做了五六年几乎所有端侧AI框架都对CNN做了深度优化而Transformer里的矩阵乘法和注意力机制在很多嵌入式NPU上还没有高效实现要么算子不支持要么内存带宽根本喂不饱。你在端侧落地一个项目八成落地的是CNN。第二CNN的计算模式跟嵌入式硬件结构有天然的契合度。卷积是典型的“规则数据复用”计算非常适合用硬件流水线来加速这也正是NPU存在的意义。理解CNN之后你对NPU架构的一堆概念比如数据复用、片上缓存、卷积加速器都能对上号。第三CNN的模型更小、量化更稳、调试更容易。我当时的项目目标是在一块嵌入式Linux板卡上跑实时视频分析内存只有2GBFlash空间有限模型必须压到几兆以内。CNN在INT8量化下精度损失通常在可控范围内而Transformer模型动不动几十兆上百兆量化之后精度波动更大管理起来的复杂度完全不同。事实证明这个选择是对的半年后回头看CNN给我建立的“计算量、内存、精度”三者之间的直觉成了我做任何端侧AI方案评估的最底层工具。2. CNN核心概念用嵌入式工程师听得懂的方式重讲一遍2.1 卷积到底在算什么如果只看数学定义CNN的卷积是一堆乘加运算但对做嵌入式的来说更好的理解方式是把卷积看成“模板匹配”的滑动窗口扫描。想象你在一个流水线上用一套模板去检查每一小块零件模板和零件对应位置的匹配度越高输出的值就越大。CNN的卷积核就是这个模板卷积核在输入图像上从左到右、从上到下地滑动每滑到一个位置就做一次点积运算得到的结果填到输出特征图的对应位置。一个卷积核的尺寸通常是3x3或1x1深度跟输入通道数一致。比如输入是一张224x224x3的彩色图片一个3x3x3的卷积核扫完整张图之后会得到一张224x224的“响应图”——我们可以把它想象成一张地图标记出这个模板在原图中哪些地方最“像”。用多个卷积核去扫就能得到多张响应图也就是多通道的特征图。有一件事我在补课之前一直没想通卷积核的“权重”到底是谁定的答案是训练出来的。初始值是随机数训练过程通过反向传播不断调整卷积核里的数值让网络输出的结果跟真实标签更接近。这个理解一旦建立部署时你就不难理解为什么模型文件里存的主要就是这些卷积核权重——模型大小约等于所有权重参数的数量总和。理解卷积的时候我建议从计算复杂度入手。一个标准的3x3卷积输出特征图尺寸是HxWxC_out输入通道是C_in那么总乘法次数大约是 H×W×C_out×C_in×3×3。这个公式特别重要因为它直接决定了你的模型在NPU上的推理延迟。我踩过的坑就是一开始只看模型文件大小没估算计算量结果选了一个看似轻巧的模型在板卡上跑起来慢到无法接受。2.2 Padding、Stride与池化三个参数决定模型大小这三个词在部署阶段决定了两件大事特征图的尺寸变化以及模型的总计算量。很多嵌入式工程师看到模型结构图就头大其实只要掌握特征图尺寸计算公式一切就明朗了。特征图输出尺寸的基本公式是输出尺寸 (输入尺寸 - 卷积核尺寸 2×Padding) / Stride 1。这里面每个参数的含义用流水线来类比最好懂。Stride就像是扫描探头的步进距离步进越大扫出来的特征图越小计算量越小但可能会丢失细节Padding就是给图片边缘补一圈“空白”让边缘像素也能被卷积核采到同时可以在不缩小特征图的前提下控制输出尺寸。池化层则是另一种降采样手段最常见的是最大池化和平均池化。它的作用跟卷积降采样不一样它没有可训练参数只是在一个小窗口内取最大值或平均值。池化带来的实际好处有两个一是降低特征图尺寸从而降低后续层的计算量二是提取局部区域的显著特征让网络对小范围的位置变化不那么敏感。在端侧部署时池化层通常很好优化因为它就是简单的窗口取最大值在NPU上几乎零成本。这套东西在配置模型时你必须心里有数。比如你有一个224x224的输入连续经过两层Stride2的卷积特征图就变成56x56。到了全连接层之前特征图尺寸会决定全连接权重矩阵的规模这个矩阵分分钟能占掉模型一半以上的空间。我用MobileNet的时候特别注意过这个问题好在MobileNet用全局平均池化替代了全连接层模型体积一下小了一个数量级。2.3 激活函数与感受野CNN里还有一个不能跳过的角色激活函数。激活函数的作用如果只背定义就是“为网络引入非线性”但对做工程的人必须理解它为什么不能省。如果没有非线性激活函数卷积层和全连接层无论叠加多少层本质上都等价于一层线性变换模型的表达力会坍塌到最底层。通俗说没有激活函数的神经网络就是一个“没脾气”的线性公式拟合不了复杂的曲线。端侧部署中最常见的激活函数是ReLU因为它计算极其简单硬件实现只要做一次“比较后取大值”的操作在NPU上甚至可以直接融合进卷积算子没有任何额外开销。反观一些新潮激活函数比如SiLU、GELU虽然训练时效果好但部署时在NPU上要么不支持要么需要拆成多个基础算子来计算性能和内存都会有影响。所以你在选择模型结构时一定要考虑激活函数的硬件友好性这个我在第4章会详细展开排查方法。感受野是理解CNN层次结构的最关键概念它的通俗解释就是输出特征图上的一个点对应输入图片上多大一个区域。浅层卷积的感受野小看到的是局部细节深层卷积通过不断堆叠感受野变大能看到更大的语义区域。做嵌入式的人有一个直觉特别好用可以类比一个传感器网络越靠近一线数据源每个传感器只管局部越往上层汇总每个节点掌握的信息范围越大。端侧项目的目标往往是“轻量化”轻量化技术本质上就是在“保持足够大的感受野”和“控制计算量”之间做平衡。我在补课过程中反复手推过一个例子两个3x3卷积堆叠的有效感受野等于一个5x5卷积但参数量从25降到了18计算量也下降不少。这个推导让我彻底理解了为什么现代网络都喜欢堆小卷积核而不是用大卷积核。这个结论在做模型选型时特别实用——看到别人用两层小卷积核替代大卷积核我心里就知道该怎么评估这个替换的实际收益了。2.4 经典网络选型参考从LeNet到MobileNet既然要从CNN补起最简单的方式就是把经典的几个网络结构各跑一遍感受一下不同结构的性格。这里我按计算量和部署友好度从低到高列一下我实际跑过的几个网络以及它们在端侧场景下的参考定位。LeNet是最经典的CNN结构很简单卷积、池化、卷积、池化、全连接。早期用来做手写数字识别在今天看来计算量很小但它证明了一件大事——卷积神经网络可以用层级的特征提取来识别图像。我在板卡上跑LeNet模型小到只有几十KB但精度已经不够应付真实场景了所以它更适合入门理解网络结构。ResNet的看家本领是残差连接通俗来说就是给网络装上“高速公路”让数据在深层网络中不容易“迷路”从根本上缓解了深层网络难训练的问题。在端侧部署中残差连接也有实际影响跳跃连接会让NPU上的数据流不再是严格的逐层流水而是涉及跨层的数据搬运这个看似不起眼的结构在硬件上可能成为存储访问的额外开销。做端侧选型时我倾向于选ResNet精修过的小型版本或者后续的变体而不是原版的101层大模型。MobileNet真正为移动和嵌入式端侧而生。它的核心创新叫深度可分离卷积将标准卷积拆成两步先对每个通道单独做空间卷积再用1x1卷积跨通道融合。对比标准卷积计算量可以降一个数量级。我在板卡上部署过一个MobileNetV2模型224x224输入INT8量化后模型大小只有几MB在NPU上跑到了接近实时的速度。如果你是第一次做端侧AI项目MobileNet系列是一个不敢说最优但绝对稳妥的起点。3. 从训练到部署一个最小CNN在嵌入式Linux上的完整实操3.1 硬件选型与工具链环境原则上来讲任何带Linux系统的板卡都能做端侧AI部署但体验天差地别。我手头做实验的平台是一块RK3588的嵌入式Linux板卡选它的原因很直接自带6TOPS的NPU支持INT8量化加速又跑完整的Ubuntu系统调试体验跟开发机接近踩坑的时候不会把系统问题跟AI问题混在一起。工具链方面各个芯片厂商的思路差不多。我用的RKNN-Toolkit2负责把训练好的模型转换成RKNN格式并做量化精度分析板卡端用RKNN Runtime做推理。如果你是其他平台比如树莓派用TFLite或者海思用NNIE方式大同小异但工具链的具体限制要提前查清楚。有一个经验值得说选平台不是看AI算力多高而是看你手上的团队对哪个平台的工具链最熟悉。工具链的坑往往比算力瓶颈更耽误项目进度。开发流程上我建议先在PC上把一整套流程跑通再上板卡。我的工作目录结构很简单models目录放原始模型和转换后的模型rknntoolkit2在PC上跑转换板卡上只做推理。这样拆开的好处是出问题时你能快速定位是PC端转换问题还是板卡端运行问题。3.2 训练、导出与量化每一步都有要注意的坑很多人以为训练是AI工程师的事嵌入式工程师拿到模型直接部署就行。但如果你做端侧AI不碰训练你的能力边界永远会被别人卡住。我当时的做法是选了一个公开的垃圾分类数据集用PyTorch训练了一个8层的CNN。模型结构不复杂但这个过程让我知道了模型从诞生到落地的完整链路。训练完成之后关键一步是导出为ONNX格式。ONNX是模型的“通用语言”几乎所有端侧推理引擎都支持从ONNX转换代码很简单import torch dummy_input torch.randn(1, 3, 224, 224) model torch.load(best_model.pt) torch.onnx.export( model, dummy_input, model.onnx, input_names[input], output_names[output], opset_version11, dynamic_axes{input: {0: batch_size}, output: {0: batch_size}} )}import torchdummy_input torch.randn(1, 3, 224, 224) model torch.load(best_model.pt)torch.onnx.export( model, dummy_input, model.onnx, input_names[input], output_names[output], opset_version11, dynamic_axes{input: {0: batch_size}, output: {0: batch_size}} )这里有个细节必须强调dummy_input的尺寸要跟以后推理时的输入尺寸一致不要为了省事随便写。你可以固定输入为1x3x224x224不要随便打开dynamic_axes因为动态输入在端侧推理引擎上往往要付出额外的性能代价而且可能直接导致算子转换失败。 导出ONNX之后紧接着是模型简化。ONNX里有很多训练框架特有的冗余结构比如多余的Reshape、Transpose这些在PC上运行没问题但转到端侧推理引擎时可能变成不支持的算子。我用onnx-simplifier在PC上做了一遍简化再去掉没意义的节点才把转换成功率提上来。 量化的坑更隐蔽。我把FP32模型直接转成INT8第一次推理后发现精度从91%掉到了72%当时的我差点以为INT8量化不可用。后来仔细排查发现是量化校准集选得有问题——我随手取了10张验证集图片做校准数量太少校准数据和真实业务场景分布差别又大导致量化后的权重和激活值范围估计不准。换用几百张覆盖了各个类别、包含各种背景干扰的训练集图片做校准之后精度回到了87%跟FP32的差距缩小到了几个百分点。一个原则要记牢量化校准集必须能代表真实部署时的输入分布不是你随便选几张好看的图就完事。 ### 3.3 嵌入式端推理NPU转换与联调 模型转换是端侧部署最麻烦的一段。我用的RKNN-Toolkit2在PC上做转换命令和配置大概是这样一个基本流程 python from rknn.api import RKNN rknn RKNN() rknn.load_onnx(modelmodel_sim.onnx, input_size_list[[1, 3, 224, 224]]) rknn.config(mean_values[[0, 0, 0]], std_values[[1, 1, 1]], target_platformrk3588) rknn.build(do_quantizationTrue, datasetcalib.txt) rknn.export_rknn(model.rknn) expresscaptionrknn.config里的mean_values和std_values是预处理参数必须跟训练时的均值/方差对齐。第一次转的时候我在这里吃了个大亏训练时用了ImageNet的均值和方差做归一化但部署时忘了填模型输出直接变成乱码。转换完成后把model.rknn拷贝到板卡上写一个推理脚本做验证。我的建议是先从Python接口跑通不要一上来就写C。Python接口调试快能快速确认模型转换和输入预处理的问题等Python全通了再平移成C效率高得多。在板卡上第一次跑推理时延迟和内存数据都不要急着优化。先验证一件事输出结果与PC上是否一致。如果不一致优先检查预处理尤其是图像缩放、归一化、通道顺序。RGB和BGR的顺序问题是最常见也最好笑的问题之一。我在一个项目里花了整整一个下午最后发现就是把OpenCV的BGR图像直接喂给了训练时用RGB图像训练的模型。3.4 实测数据FP32与INT8的精度和性能对照部署完成后我在同一块RK3588板卡上分别跑了FP32和INT8精度的模型记录了这样一组数据包括模型大小、内存占用、推理延迟和Top-1精度。指标FP32模型INT8量化模型模型大小148.6 MB37.6 MB单张推理延迟84 ms32 ms内存峰值占用312 MB96 MBTop-1精度92.8%88.9%这组数据背后有几个值得展开的信息。模型大小从148MB降到37MB压缩到四分之一原因是INT8每个权重只占1字节而FP32占4字节理论上参数量相同的模型体积就应该降到四分之一左右。延迟从84ms降到32ms加速约2.6倍除了INT8计算比FP32快之外更关键的是模型变小之后片上缓存能装进更多权重减少了外部存储的访问次数。内存峰值从312MB降到96MB这个在端侧场景往往比模型大小更重要因为板卡内存是硬约束。精度从92.8%掉到88.9%损失了约4个百分点对于垃圾分类这个任务来说可以接受但对于人脸识别这种高精度敏感场景就要重新评估了。我的经验是量化精度损失如果超过5个百分点优先排查量化校准集质量和模型结构里是否有对量化敏感的层而不是盲目回到FP32。完全抛弃量化回到FP32就意味着失去2倍以上的性能和4倍的体积优势在端侧项目里通常是不可接受的妥协。4. 端侧AI部署中的常见坑与排查笔记4.1 算子兼容性问题端侧AI项目里遇到最多的问题不是模型训练不出来而是模型在训练框架里能跑转到推理引擎后各种算子不支持或低效执行。先说结论算子不兼容几乎都是因为模型结构里出现了推理引擎不支持的自定义算子、高阶算子或者特定框架自己的特殊实现。举一个我实际遇到过的例子。一个开源的CNN模型里用了SiLU激活函数这个函数在PyTorch里就是一行代码但转成RKNN的时候支持不好查询工具链文档发现这个版本的RKNN对SiLU还没有直接映射只能通过拆解的Sigmoid和乘法组合来模拟。拆解之后的模型虽然也能跑但多出了额外算子延迟明显增加而且量化精度也跟着波动。最后解决方案很简单在训练时就把SiLU换成了ReLU重新训练一个版本部署效率立刻上去。算子兼容性排查的思路我总结成三步。第一步转换时一定开启详细的日志输出工具会明确告诉你哪个算子不支持或回退到CPU第二步对不支持的算子查推理引擎的算子支持文档看有没有替代方案第三步如果确认是模型结构的原因回到训练阶段调整网络结构尽量不要在部署阶段硬扛。很多时候模型是为了学术榜单设计的算子选择对新硬件并不友好部署工程师要有决心对模型做“手术”。4.2 量化精度损失到底是谁的锅量化精度损失是这个领域永恒的话题。很多人一遇到量化掉点就怪量化技术不行但实际项目里七成的量化问题都出在量化之前的环节。第一个隐藏因素是模型本身的冗余空间不够。如果一个模型在FP32下精度就不高比如刚过80%量化之后掉3个点可能就到77%以下体感很严重。反过来一个FP32下有95%精度的强模型量化到INT8之后通常还能留在在92%以上。所以做端侧AI的模型宁可选择精度余量大一点的也别选那种刚好够用的弱模型。第二个因素是前面提到过的校准集问题。我用RKNN-Toolkit2做量化的时候第一次用手头的验证集图片做校准结果精度掉得离谱。后来把校准集扩到500张覆盖各个类别、光照条件、拍摄角度量化精度就稳定了。校准图片太少或者太单一模型统计出的权重范围就不准量化噪声会被放大。第三个因素是特定层对量化敏感。通常第一层和最后一层的精度对量化最敏感因为第一层的输入是整个图像数据范围差异大最后一层的输出直接关联分类结果。我遇到过一次情况是检测输出层的量化精度损失特别严重后来做法是对最后一层单独保留FP32其他层用INT8这种混合精度方案在端侧工具链里是支持得越来越好了。4.3 嵌入式环境特有的几个坑如果说前两类问题在PC上也会遇到那这一类是嵌入式开发者专属的体验。首先是根文件系统和调试文件传输问题。我在板卡上开发时为了方便直接用NFS把开发机的目录挂载到板卡上作为根文件系统这样文件不用一遍遍拷贝但NFS挂载的稳定性受网络环境影响很大。踩过的一个经典坑是板卡在NFS文件系统上跑到一半突然I/O报错排查了半天发现是网线松了导致网络闪断。后来我学到一个习惯把模型文件和推理库直接放在板卡的本地Flash上只有代码开发阶段才用NFS避免运行时依赖网络。其次是内存对齐和缓存一致性。NPU搬运数据时对内存对齐有要求一般要求16字节对齐而DMA引擎更苛刻。我有一个项目里输入图像从摄像头采集后是裸的YUV420数据直接塞给NPU偶尔会出现输出错乱后来在分配缓冲区时用了对齐分配并确保数据写入后做了缓存刷新操作问题才消失。这在嵌入式里是基本功但在AI部署时特别容易被忽略因为PC上的内存管理帮你把脏活都干了。最后是系统负载问题。板卡上的NPU虽然负责算卷积但预处理、后处理、显示输出全部由CPU完成CPU占用率太高的直接后果是推理线程被抢占导致画面卡顿和延迟波动。我调优时先把CPU的几个核心分开一个核心专门跑推理线程其他核心跑采集和渲染再设置线程优先级。这一套做下来画面稳定度提升很明显。4.4 常见问题速查表问题现象可能原因排查方向板卡输出乱码或全零输入数据没有归一化均值方差没对齐检查预处理参数是否与训练一致精度下降严重超过5%量化校准集代表性不足扩大量化校准集覆盖真实场景分布模型转换失败报不支持的算子模型包含自定义或高阶算子简化模型替换激活函数或特殊结构单帧延迟高卷积计算量大或者算子回退到CPU查看逐层耗时统计定位耗时瓶颈层推理结果偶发错误内存未对齐或缓存未清理调整缓冲区对齐加入内存屏障操作板卡运行一段时间后变慢NPU/CPU温度过高触发降频添加散热或者限制连续推理负载这张速查表里我列的都是自己实际遇到过的类型没有一条是凭空臆想。排查的时候建议按顺序来先确认输入输出再查算子日志最后盯硬件资源层次推进比乱碰运气高效得多。5. 给想转端侧AI的嵌入式工程师的学习路线建议5.1 先补数学还是先动手很多人问转端侧AI要不要先把线性代数、概率论啃完我的答案是不用但不能完全不碰。端侧AI部署的核心是对模型和计算的理解不是推导训练算法所以你的数学要求比算法工程师低得多。你需要掌握的知识点其实很收敛矩阵乘法是什么、卷积运算怎么算、权重和特征图的维度变换这些基本上是有线性代数常识就能入手的。我的建议是先动手在动手过程中遇到卡壳的地方再去补数学。比如你搞不懂为什么卷积层的参数量是3x3xC_inxC_out那就去翻一下权重矩阵的形状说明看一行就懂了。你搞不懂为什么量化之后精度会掉那就去查一下数值表示范围和精度损失的来源概率统计的基本概念够用就行。真没有必要抱着西瓜书啃两月才动手那是学院派的做法对做工程的性价比太低。不过有一个数学知识值得早点补张量的维度。CNN里的数据全是高维张量而且每个框架的内存排布方式还不一样比如PyTorch是NCHWTensorFlow是NHWC两种排布在硬件上的缓存访问效率完全不同。我在RK3588上测过同一个模型在NCHW和NHWC两种排布下的推理延迟差距能达到20%以上。理解维度排布是嵌入式工程师能把AI工程化的重要分水岭。5.2 我推荐的半年学习路线如果让我重新走一遍从嵌入式到端侧AI的转型路径我会把学习过程拆成四个阶段每个阶段大概一个半月左右。第一阶段是Python和PyTorch入门。很多嵌入式工程师对C/C很熟但看到Python的写法会觉得不踏实。这个阶段先放下偏见Python在AI生态里就像嵌入式里的C绕不过去。我不建议一上来就搞复杂网络先学会加载数据集、训练一个全连接网络、看loss下降建立对训练流程的整体感知就够了。第二阶段是手动实现一个小型CNN并在PC上完整训练。我当时用PyTorch从零定义了一个包含两个卷积层、两个池化层、一个全连接层的网络在MNIST上训练到99%的精度。这个阶段的关键是亲眼看清楚每一层的特征图形状和参数量打印出来对着网络结构图核对。你不需要发明新结构只需要能把已有结构一字不差地实现出来。第三阶段是部署一个现成的开源模型到开发板上。把训练好的MobileNet或类似模型导出ONNX转换到端侧推理引擎在板卡上跑通。这个阶段的目标不是追求性能而是打通全流程链路把转换、量化、部署、推理的各个环节都玩一遍。我第一次部署用了接近半个月后来熟练了只需要半天。第四阶段是性能优化和精度调优。针对一个已跑通的模型尝试INT8量化、算子替换、输入尺寸调整记录每次修改对延迟和精度的影响。这个阶段要养成随手记实验数据的习惯形成自己的性能优化checklist。走到这一步你已经不是“用AI”的嵌入式工程师而是“做端侧AI”的工程师了。5.3 选开源项目练手时要注意什么开源项目是练手的好素材但选项目本身有门道。我见过很多人一上来就clone一个目标检测项目模型几百MB依赖一大堆结果在板卡上跑了三天没跑通自信心直接被打击没。初学者的练手项目应该满足三个条件模型小、任务简单、部署链路短。我推荐的方向有三个手势识别、图像分类、关键词唤醒。这三个任务的共同点是模型结构简单、公开资料多、输入输出容易理解、也能用摄像头或麦克风做实时演示。相比之下目标检测、语义分割、姿态估计这些任务虽然炫酷但要处理锚框、NMS、坐标解码等后处理逻辑这些附加复杂度会喧宾夺主把你本该花在CNN理解上的精力全引流走了。选开源项目时还要注意代码质量和依赖锁定。我吃过一次亏clone了一个三年前的项目PyTorch版本不兼容、依赖库缺失、数据集下载链接还失效了最后光修环境修了两天。现在我的习惯是优先选最近一年仍有更新、依赖清晰、并且带Dockerfile或者requirements.txt的项目。哪怕它的结构稍微复杂一点能跑通并理解完整链路的价值远大于在垃圾代码里浪费时间。做完这些课程之后我最大的收获其实是心态的变化。从一个“遇事不决查文档”的嵌入式工程师变成一个“先估算计算量、再推断性能瓶颈”的端侧AI工程师这个转变比多会几个工具重要得多。最后再分享一个小技巧在板卡上调试模型时先用随机噪声数据跑通全流程再替换成真实数据。这样能把“环境没配好”和“数据有问题”两类错误隔离开排查效率立竿见影。这条路不长也不短希望我这半年踩过的坑能让你走得更快一点。