
干了几年嵌入式裸机、RTOS、Linux 驱动、应用层都摸过一遍后我开始频繁接触到端侧 AI、模型部署这些词。一开始我以为是营销话术直到某次项目评审会上硬件平台负责人提出要在我们的设备上跑一个视觉检测模型我才意识到这不是什么趋势口号而是甲方真的在往这个方向投钱。于是我开始认真考虑转型这件事。当时很多同行给我的建议是直接学大模型部署现在外面都招懂大模型落地的人。我也确实花了两个晚上去看大模型的量化、剪枝资料看完之后反而冷静了。我决定从 CNN 重新开始——不是觉得自己聪明而是因为我在嵌入式行业待久了养成了一个习惯要让一个东西在资源受限的设备上稳定跑起来我得先把它的每一层原理弄清楚。这篇文章就是我这段时间从嵌入式过渡到端侧 AI 的真实经历。我会把为什么要从 CNN 入手的判断过程、CNN 核心原理的重新理解、以及把模型真正部署进单片机的完整过程都写下来。如果你也是个嵌入式开发者正在犹豫要不要转端侧 AI或者已经在转了但总觉得基础不牢这篇应该能给你一些参考。1. 端侧 AI 不是嵌入式换个名字但嵌入式经验确实能吃香先说结论端侧 AI 和嵌入式确实有大量重叠但两者思考问题的起点不同。嵌入式关注的是在资源受限的条件下保证功能稳定端侧 AI 关注的是在资源受限的条件下保证模型精度与推理速度的平衡。后者比前者多了一个精度维度而处理精度问题光靠硬件的功夫是不够的。1.1 一样的硬件平台不一样的核心矛盾我最初以为搞端侧 AI 就是把训练好的模型固化成代码烧进设备本质上和我之前把一段 DSP 算法烧进单片机没区别。真正动手后发现问题远不止烧进去这么简单。传统嵌入式开发中只要程序逻辑正确、时序满足就算完成交付但端侧 AI 项目里即使模型输出完全正确如果推理时间超出预期或者内存占用把其他功能模块挤爆了整个方案依然无法落地。举一个最直观的例子。我在某个项目里接触过一个视觉检测的需求需要在设备端实时判断画面中是否有目标物体。硬件平台的主频只有几百 MHzRAM 也只有几百 KB。传统嵌入式开发面对这种需求只需要写一个图像处理算法但在 AI 方案里你得考虑输入图像要缩放成多大才能兼顾精度和速度模型的参数文件压缩到多少 KB 才能塞进片内 Flash每一层计算产生的中间结果放在哪里会不会和协议栈缓冲区冲突量化后的精度损失是否能被业务接受这些问题是传统嵌入式开发很少考虑的。但反过来看正是因为嵌入式背景让我习惯性地先想资源够不够而非先想模型精度多高我在做方案选型时反而比纯做算法的同事更快锁定了适合的模型规模。在端侧 AI 里资源边界是先决条件精度是后置指标这和嵌入式开发硬件优先的思维高度一致。1.2 端侧 AI 的典型落点基本都在嵌入式设备附近从应用场景来看端侧 AI 的落点几乎全部围绕嵌入式设备展开摄像头模组、穿戴设备、工业传感器、车载控制器、智能家居终端。这些设备共同的特点是有物理体积限制、有功耗限制、有实时性要求而且往往需要断网运行。这也意味着端侧 AI 团队里最缺的人才是既能看懂模型结构又能读懂芯片手册还能写底层驱动的复合角色。纯算法工程师对内存布局、DMA 传输、外设时序往往不太敏感而嵌入式工程师天然具备这些技能。所以我很确定嵌入式出身的人做端侧 AI不是从零开始而是平移 补课。补课补什么呢核心就两块第一块是深度学习的理论基础尤其是 CNN 这类结构化模型的工作方式第二块是模型压缩与部署工具链的使用。我的计划是先啃第一块也就是从 CNN 开始。2. 为什么绕开了大模型决定老老实实从 CNN 啃起说实话2024 年之后讨论端侧 AI所有人第一反应是大模型。我也试过直接接触大模型的端侧部署但很快就发现一个问题大模型的技术栈里量化和推理框架的复杂性远高于模型本身的可解释性如果底层卷积、激活、池化这些概念都是模模糊糊的遇到问题根本不知道怎么定位。2.1 大模型由 Transformer 堆成而 Transformer 里到处是 CNN 的影子我决定从 CNN 开始不是因为 CNN 比大模型低级而是因为CNN 是理解所有现代模型的基础积木。大模型的核心是 TransformerTransformer 的核心组件包括 Embedding、多头注意力、前馈网络、LayerNorm。看起来跟 CNN 没啥关系但细抠下去会发现多头注意力的计算本质是一系列矩阵乘法和加权求和而 CNN 的卷积计算本质上也是矩阵乘法视觉领域的模型包括很多多模态大模型在提取图像特征时依然会用到卷积结构大模型的部署优化手段——量化、剪枝、算子融合——在 CNN 时代就已经成熟很多工具链最初就是为 CNN 设计的换句话说把 CNN 吃透后面学 Transformer、学注意力机制时至少计算图特征图量化误差这些底层概念不会发虚。我从嵌入式转过来最怕的不是学不会而是概念理解得虚实难辨导致调起 BUG 来无从下手。2.2 我学习过程中纠正的三个关键认知重新学 CNN最大的收获不是会用了而是把几个以前模模糊糊的概念真正想通了。这里分享三个对我影响最大的认知转变第一个认知是卷积核到底在干什么。以前只知道卷积核是一个小矩阵扫过图像做乘加运算但不知道为什么它能提取特征。后来拿边缘检测举例才真正理解了如果一个卷积核中间是正数、两侧是负数那么它在图像上扫过时对颜色剧烈变化的区域响应强对颜色平缓的区域响应弱这就天然成了一个边缘响应器。多个卷积核叠加就能响应不同类型的局部模式。这解释了为什么卷积层越深提取的特征越抽象——浅层卷积核响应边缘、纹理深层卷积核在浅层特征的基础上组合出更复杂的语义模式。第二个认知是感受野为什么重要。在做模型结构设计时如果感受野太小模型只能看到局部识别大物体时容易只见树木不见森林如果感受野太大又会增加参数量和计算量。算感受野的公式并不复杂从最后一层往前递推每一层的感受野 上一层的感受野 当前层卷积核尺寸 - 1× 前面各层的步长乘积。实际设计网络时我通常先在纸上把各层感受野算一遍确保最后一层能看到输入图像的主要区域再考虑层数。第三个认知是参数量与计算量的区别。参数量决定模型文件多大、要占多少 Flash计算量决定推理时间长短、功耗高低。一个 3×3 卷积输出通道为 C、输入通道为 K、特征图尺寸为 H×W那么参数量是 K×C×9计算量约等于 K×C×9×H×W。很多教程只强调参数量但嵌入式设备更关心计算量因为计算量直接换算成 CPU 周期和功耗。我后来做方案评估时第一件事就是估算模型的计算量这比争论模型文件大小更有意义。2.3 我给你建议的学习顺序如果你也想从嵌入式视角进入端侧 AI我的建议顺序是先学 CNN 的结构和训练流程再学模型导出与量化最后才碰推理框架和硬件加速库。不要一上来就折腾大模型的部署工具那会让你迷失在环境配置里。具体到资料选择我个人的经验是理论部分看经典的深度学习入门书或公开课只看前几章卷积网络部分就够了实操部分用 PyTorch 加一个公开的小型图像分类数据集从零搭一个两层卷积的模型跑通训练、导出、部署的全流程。这个流程走通你对模型是怎么变成设备里的一段代码这件事就有完整的体感了。3. 从零手写一个两层 CNN完整训练流程与参数详解这一章我按实操顺序记录我跑通第一个 CNN 的完整过程包括模型结构设计、训练参数设置和容易被忽视的细节。3.1 实验环境与数据准备我用的训练框架是 PyTorch配合 CUDA 加速没有 GPU 用 CPU 也能跑只是慢一些。数据集选的是公开的小型图像分类数据集大概上万张图片分成 10 个类别左右。数据规模不需要太大重点是流程完整。数据准备阶段我踩过一个坑忘了做归一化。图像像素值范围是 0 到 255如果不先缩放到 0 到 1 之间模型的初值会很难收敛。原因在于输入值过大导致加权和的值域偏大经过激活函数后容易出现饱和区梯度消失。正确的做法是计算数据集的均值和标准差然后做标准化new_value (value - mean) / std。这是所有图像模型的第一步也是最容易被新手忽略的一步。3.2 模型结构设计一个参数一个参数算出来我设计的模型结构如下针对 32×32 的输入图像第一层3×3 卷积输入通道 3输出通道 16padding 1第二层ReLU 激活第三层2×2 最大池化步长 2第四层3×3 卷积输入通道 16输出通道 32padding 1第五层ReLU 激活第六层2×2 最大池化步长 2第七层展平成向量第八层全连接层输出维度为类别数我算一下这个模型的参数量和特征图尺寸变化。输入 32×32×3经过第一层卷积后特征图尺寸不变padding1 保持宽度变成 32×32×16经过池化后变成 16×16×16经过第二层卷积后变成 16×16×32再池化变成 8×8×32展平后是 8×8×32 2048 个元素全连接层参数量就是 2048×10假设 10 类≈ 2 万。整体参数量大约 2.5 万左右模型文件极小。这个模型结构很简单但它包含了 CNN 最核心的四个组成部分卷积、激活、池化、全连接。每一层的作用分别是卷积提取局部特征激活引入非线性池化降低分辨率以增大感受野并减少计算量全连接做最终分类决策。3.3 训练过程超参数怎么定才合理训练时我用的损失函数是交叉熵损失CrossEntropyLoss优化器是 Adam学习率初始为 0.001batch size 为 64训练 30 个 epoch。这套超参数是图像分类任务里比较通用的起点但如果你数据集大小和模型结构变化较大需要相应调整。几个关键的调参经验学习率如果设得太大loss 会震荡不降设得太小收敛会非常慢。我用 0.001 起步每 10 个 epoch 如果 loss 没有明显下降就适当下调学习率。训练日志里如果看到 loss 持续波动但整体趋势向下通常说明学习率略偏大可以减半。batch size 影响梯度估计的稳定性。batch size 越大每个 batch 的梯度估计越稳定收敛更平滑但会占用更多内存。在端侧场景里训练时的 batch size 和推理时的单次输入大小没关系不要混在一起。数据处理里必须做随机增强。我用了随机水平翻转和随机裁剪这两个操作显著降低了过拟合程度。因为模型参数量虽小但训练数据量也不算大如果不做增强训练集准确率能到 90% 以上而验证集只能到 70% 左右典型过拟合。训练完成后我在验证集上测了准确率大约 80% 左右。这个精度对于生产任务来说不算高但对于第一次亲手训练并发部署到嵌入式设备的目标来说已经够用——关键是先把工具链跑通精度优化是后续的事。3.4 导出与中间层可视化确认模型真的学对了训练完之后我额外做了两步验证第一步是把模型导出成中间表示格式。PyTorch 提供了方便的方式导出计算图这一步是为了后续转到端侧部署格式做准备。导出时要注意输入尺寸必须与实际推理时一致否则部署端会报维度错误。第二步是提取第一层卷积核的可视化结果。我把训练好的第一层 16 个 3×3 卷积核打印出来看了看发现其中一些卷积核确实出现了边缘响应模式说明模型学到了一些基础视觉特征。这种内视对建立直觉非常重要——你知道模型不是黑盒它确实在按预期方式工作。4. 真正把模型塞进单片机一次端侧部署的完整记录训练在 PC 上跑通只是第一步真正考验人的是把模型部署到嵌入式设备。这一章我记录部署过程中的每个步骤和踩坑点包括模型转换、量化、内存估算和实际运行性能。4.1 模型转换从训练框架到部署格式我选择的端侧部署路径是把 PyTorch 模型导出成中间表示再转换为嵌入式推理库需要的格式。具体来说中间表示格式负责保存计算图结构和权重参数部署格式则根据目标硬件的指令集做进一步优化。这里最容易踩的坑是算子兼容性。训练框架支持的算子集合远大于嵌入式推理库支持的算子集合。比如有些训练时的算子比较新但嵌入式推理库的版本还没适配导致转换直接失败。我的处理方法是模型设计阶段就只使用基础算子——卷积、ReLU、最大池化、全连接——这些算子在所有推理库中都有完善支持。如果你用了 GELU、SiLU 等较新的激活函数部署时大概率要手写算子或者降级非常麻烦。另外模型转换时要注意输入输出的格式。PyTorch 的默认张量布局是通道在前的格式但很多嵌入式推理库期望的是通道在后的格式。如果这两个格式对不上部署后推理结果就会乱套。我当时花了整整一天排查这个问题经验是拿到部署库的第一时间就把接口文档的 layout 说明截图保存别嫌啰嗦。4.2 量化精度和体积的博弈部署端的模型文件如果直接用 32 位浮点存储在单片机上跑会有两个问题一是体积过大一个 2.5 万参数的模型浮点格式要约 100KB对 Flash 有限的设备偏大二是浮点运算在无 FPU 的 MCU 上极慢。解决办法是量化把权重从浮点数转换为 8 位整数。我采用的是训练后量化方式不需要重新训练但需要准备一小部分校准数据统计激活值的范围。量化后的模型体积直接缩小到原来的四分之一大约 25KB 左右计算速度也明显提升。量化最大的坑是精度下降。我的模型量化前准确率 80%量化后掉到了 72%这个损失对某些业务可能不可接受。原因主要是激活值的分布不均匀有些层在量化时信息损失较大。如果遇到这种情况建议优先改用量化感知训练在训练过程中模拟量化误差让模型主动适应低精度表示。我后来在另一个模型上试过量化感知训练精度损失从 8% 缩小到 2% 以内代价是训练时间变长、代码复杂度增加。4.3 在单片机上跑起来的实测数据我选的测试平台是一块主频 200MHz 左右、RAM 512KB、Flash 1MB 的常规 MCU这也是工业领域最常见的配置。测试输入是一张 32×32 的灰度图转三通道实际部署中摄像机输入的彩色图需要先在代码里缩放到目标尺寸。实测结果如下项目数值卷积层总量2 层16 通道 32 通道模型文件大小约 25KB8 位量化后内存占用含中间缓冲区约 42KB单次推理时间约 420ms功耗增量通过 GPIO 测量约 18mA420ms 的推理时间对实时性要求不高的场景比如每隔一秒做一次检测可以接受但对视频流级别的场景远远不够。这个性能符合预期因为我选的本身就是入门级 MCU跑两层卷积就花四百多毫秒说明要么换更强的芯片要么进一步压缩模型结构比如把第一层卷积的通道数从 16 减到 8推理时间能再降一半。4.4 部署过程中遇到的三个具体问题与解法第一个问题是模型的中间特征图占内存比模型文件还大。模型文件 25KB但第一层卷积的输出特征图就有 32×32×16 个浮点数据如果全部按浮点存着光这一层就超过 64KB。后来我做了两点优化第一中间特征图用 8 位整数存储量化的不仅是权重也包括激活值第二采用算子融合和内存复用上一个卷积的输出缓冲区直接作为下一个池化操作的输入缓冲区不额外分配新内存。优化后内存占用从 100KB 级别降到了 42KB。第二个问题是循环展开的效果远大于我预期。小尺寸卷积如果直接按两层循环遍历卷积核 两层循环遍历特征图的方式实现产生的循环开销非常大。我把 3×3 卷积的内层循环手动展开后推理时间缩短了约 25%。这说明在小算力平台上微架构优化比算法层面的提升更容易见到效果。第三个问题是堆栈深度。我的推理函数里嵌套调用层数较多导致栈空间溢出。排查方法简单粗暴把任务栈从 4KB 加到 8KB问题消失。但后来我还是把函数拆成了几个独立的阶段让每一层计算的局部变量在退出作用域后及时释放栈从 8KB 降回到 5KB给其他功能模块留出了余量。5. 嵌入式开发者转端侧 AI 的避坑清单与学习路线建议走到这一步我已经完整经历了一个 CNN 从训练到部署的全过程。回头看有几个坑特别想分享给同样背景的人因为这些问题几乎都会遇到但很少有人系统性地总结。5.1 避坑清单最容易浪费时间的五个点第一不要在模型结构设计阶段贪多求深。嵌入式背景的人容易有个错觉——觉得自己学 AI 起步晚得用更复杂的模型证明自己。实际上在端侧设备上模型规模永远受硬件限制用超大模型跑不动不如用紧凑模型跑得又快又稳。我后来看了一些工业落地项目很多产品的核心模型就是两层到五层卷积真正复杂的部分在数据增强和业务逻辑里。第二不要忽略算子版本兼容性。我在设计模型时如果用了某个训练框架独有的新算子部署时就需要额外适配。最稳妥的做法是动手前先查目标部署库支持哪些算子然后只在这份清单内设计模型。如果清单不全就用保守策略只用卷积、池化、全连接、ReLU 和 Softmax 这几个经典算子。第三不要低估数据预处理带来的开销。模型推理只消耗 420ms但图像缩放的插值计算、格式转换、归一化运算加起来又占了 100 多毫秒。在端侧设备上数据预处理往往比推理本身更耗时特别是当你用的图像缩放算法不够优化时。建议提前把每个环节的耗时都测算一下瓶颈往往不在你预期的地方。第四不要迷信训练精度高 部署效果好。训练集上的 99% 准确率在真实硬件上可能一塌糊涂因为摄像头输入的图像亮度、噪声与训练数据分布差异很大。我现在评估模型时会刻意加入不同光照、模糊、遮挡的测试集样本观察模型的泛化边界而不是只看验证集指标。第五不要忽略量化的细节差异。不同厂家的量化规则可能不一样比如有的用对称量化有的用非对称量化有的量化权重也量化激活有的只量化权重。我在部署时发现同一模型在两个不同推理库中的输出有细微偏差排查后确认是量化规则不同。5.2 学习路线你的嵌入式经验应该怎么衔接 AI我回顾了自己这段过渡期的时间投入觉得最有效的顺序是先用一周理清 CNN 的核心原理重点理解卷积、池化、感受野、参数量计算再用两周跑通一个训练到部署的 Demo最后用两个月做一个相对完整的项目比如识别工业设备指示灯状态或者质检图像中的缺陷。其中做一个完整项目这一步至关重要。因为只有到真实需求场景里你才会被迫面对嵌入式与 AI 结合的所有细节摄像头怎么接入、图像怎么同步、缓存怎么管理、模型跑完结果怎么与业务逻辑联动。这些是教程里不会写但实际项目里必考的环节。5.3 面试官会怎么问从嵌入式转端侧 AI 的必考点既然热搜词里有嵌入式面试题嵌入式八股文这些条目我顺便结合自己转方向后接触到的面试题目总结几个高频考点第一个必考点是手算卷积输出尺寸。给定输入尺寸、卷积核大小、padding、步长要求输出特征图尺寸。公式是(输入尺寸 2×padding - 卷积核尺寸) / 步长 1。这个必须熟。第二个必考点是参数量和计算量估算。面试官会给一个网络结构参数让你算这个模型要多少 Flash、推理一次大约多少次乘加运算。这个直接用我在 2.2 里说的公式就能算出来。第三个必考点是精度与速度的取舍逻辑。给你一个嵌入式设备规格问你怎么判断某个模型能不能跑。答案是先算参数量与内存再算计算量与推理时间最后对比业务需求中的实时性要求。第四个必考点是量化的基本原理。比如 8 位量化的公式real_value scale × int_value zero_point。确认对称量化和非对称量化的区别。这一块在部署场景中几乎必问。我觉得嵌入式背景的人回答这些问题有个天然优势你讲量化、讲内存、讲推理耗时的时候比纯算法背景的人更具体、更有真实案例支撑。关键是先把这些基础概念用面试会怎么考的方式复习一遍不至于一问三不知。写在最后关于转方向的一点体会从嵌入式往端侧 AI 转这条路我已经走了半年多最大的感受是难度不在学不会而在容易学偏。市面上关于大模型、Transformer 的教程扎堆看得人眼花缭乱但如果你没有扎实的 CNN 基础学那些东西就像在一个没有地基的房子里装修——表面看着不错风一吹就散。我现在看问题的方式也变了。以前做嵌入式我拿到需求先想用什么芯片、什么外设、什么协议现在我会先想这个需求能不能抽象成分类、检测、分割问题模型的输入输出是什么精度要求允许多大的错误率。这种思维转变比单纯学会某个模型结构更重要。最后给同样想转方向的朋友一个具体建议别急着买一堆课先花一个周末用你手头的开发板跑通一个最小 Demo。哪怕只是让板子上的 LED 灯根据摄像头画面中是否有特定物体亮起这一步走通了后面的路你自己就知道该怎么走了。