
1. 问题背景与解决思路先说结论在 ST Edge AI Developer Cloud 上拿自己训练的 YOLOv8n 模型生成 NBG 文件失败这问题我前前后后折腾了差不多两周。最后真正解决后回头看根因其实并不复杂问题几乎都出在“模型导出”和“输入输出规范”这两个环节上跟 ST 服务端本身的关系反而不大。顺便说一句如果你还没接触过 NBG 文件这里先交代一下。NBGNeural Network Based Graph是 ST Edge AI 工具链的模型压缩包格式里面保存了经过量化、优化、映射之后的神经网络结构描述和权重数据后续要生成 STM32 工程代码或者用 ST Edge AI Core 在板端推理都得靠这个 NBG 文件作为中间输入。换句话说NBG 是整个部署链路里从“AI 模型”到“MCU 可执行代码”之间的关键桥梁。我手上这个项目的硬件目标是一块 STM32H747 开发板MCU 侧资源相对有限所以模型选型时直接挑了 YOLOv8n也就是 YOLOv8 系列里最轻量的版本参数量大约 3.2M计算量在 8.7 GFLOPs 左右。项目场景是在嵌入式设备上做轻量目标检测输入分辨率用 640x640检测类别是自定义的 5 类。模型训练用的框架是 Ultralytics YOLOv8 官方源码训练完成后本地推理一切正常最终走到 ST Edge AI Developer Cloud 上传模型、尝试生成 NBG 时就开始各种报错典型的现象是上传成功、模型分析也显示出模型结构但点击生成 NBG 后直接失败云平台提示信息非常模糊基本只告诉你 an error occurred while generating the NBG file具体原因全靠自己猜。这篇文章就把整个排查过程、关键原理、最终可行的操作路径完整记录下来给后面要踩同一条路的人省点时间。需要说明的是文章中涉及的完整方案是我基于实际项目经验总结整理的不同版本的 ST Edge AI 工具链和 Ultralytics 源码之间可能有一些小差异但核心思路是通用的。2. YOLOv8n 自定义模型部署到 ST Edge AI 的完整链路拆解2.1 从 PyTorch 到 NBG中间到底经过了几道工序很多新手最大的误区是以为只要把训练好的 .pt 文件传到 ST Edge AI Developer Cloud 就能直接生成 NBG。实际上ST Edge AI 工具链支持的模型格式是有限的主要是 ONNX、TensorFlow Lite、Keras 等标准格式PyTorch 的 .pt 权重文件基本不在直接支持列表里。所以要跑通这条链路至少需要经过这么几步用 Ultralytics 官方源码把训练好的 YOLOv8n 模型导出为 ONNX 格式。将导出的 .onnx 文件上传到 ST Edge AI Developer Cloud。云平台对模型进行解析、验证、量化分析然后生成 NBG 文件。下载 NBG 文件在 STM32 工程里通过 ST Edge AI Core 的 API 加载运行。整个过程中第 3 步是黑盒我们控制不了服务端的逻辑能控制的就是第 1 步导出时各项参数的设置。而我在实战中遇到的所有问题全部出在这第 1 步和第 2 步的衔接之间。对于这种黑盒服务我的建议是优先自查能控制的部分本地先把模型在 ONNX Runtime 里跑通确保 ONNX 文件本身没问题再去跟云端折腾。道理很简单云端平台的报错信息本来就少如果本地这一侧不能保证输入模型是可靠的那排查起来就像在伸手不见五指的房间里找一根针纯靠运气。2.2 自定义训练带来的模型结构差异为什么成了云端的拦路虎直接使用 Ultralytics 官方提供的 yolov8n.pt 预训练模型导出 ONNX 再上传到 ST Edge AI Developer Cloud大概率能顺利生成 NBG。但我这类自定义训练过的模型问题就来了。原因在哪里官方预训练模型默认是 COCO 80 类模型结构是标准配置。而自定义训练可能改动的东西就多了类别数变化。我训练的时候把类别从 80 类改成了 5 类那你模型最后的检测头Detection Head输出形状就变了原来输出的是 1x84x8400 的张量现在变成了 1x9x8400。输入尺寸变化。有些人会用 320x320 或 416x416 训练有些人用 640x640输入尺寸不固定也会影响导出。模型结构本身的改动。比如有人会在 YOLOv8n 的 backbone 或 neck 上做一些轻量化改造比如替换 C2f 模块、去掉某些层这些改动都可能导致导出的 ONNX 结构跟 ST Edge AI 工具链预期的标准 YOLO 结构不一致进而导致后续的分析或代码生成失败。训练时开启的一些附加模块比如数据增强、EMA、Batch Norm 融合等如果没有在导出时正确关闭或处理也可能在 ONNX 里留下一些奇怪的算子。这是“我训练出来的模型”和“工具链认知里的标准模型”之间的结构差异问题。ST 的工具链为了性能优化会去尝试识别模型里的特定模式比如 YOLO 的输出层结构、anchor 或者 anchor-free 的处理方式。一旦你的模型结构跟它内置的识别模板不匹配或者包含它不支持的算子生成过程就可能直接失败。另外还有一个很关键的隐含点ST Edge AI 在做模型分析时通常需要知道模型的输入尺寸和输出张量结构。如果你导出的 ONNX 里输入尺寸是动态的有可能在云平台的静态分析阶段就没法确定模型的确切形状后续的量化、优化和代码生成都会因此中断。这一点是 YOLOv8n 导出时最容易踩的坑之一后面会详细讲。2.3 ST Edge AI 工具链是黑盒但它的预期是可以逆向推断的要搞明白 ST Edge AI 需要什么最直接的方法就是拿一个能成功的模型作为参照然后反向摸清它的预期。我当时做了个对照实验先用官方的 yolov8n.pt 通过 Ultralytics 的 export 导出 ONNX上传到 ST Edge AI Developer Cloud它确实能正常生成 NBG。那我就拿这个成功的 ONNX 和我自己导出失败的 ONNX 做对比从输入输出张量的形状、算子集合、图的拓扑结构三个层面逐一比对很快就锁定了差异点。所以如果你也被这个报错卡住了我强烈建议你也先做这个对照实验。它能帮你判断问题到底出在导出参数上还是出在模型结构自定义的复杂度上。3. 核心细节解析YOLOv8n 导出 ONNX 的关键参数与原理3.1 固定输入尺寸这件事为什么这么重要我在第一次导出 ONNX 时用的是 Ultralytics 默认的导出命令只指定了 opset 版本。结果模型导出来后输入张量是动态的dynamic axes比如形状为 [1, 3, -1, -1]也就是说模型可以接受任意分辨率输入。本地跑推理没问题因为 ONNX Runtime 能根据实际输入重塑图。但到了 ST Edge AI 那头问题立刻凸现。ST Edge AI 在做模型分析时需要确定模型的精确输入形状才能继续后续的量化校准和内存规划。你把一个动态形状的模型丢给云端就等于告诉它“这个模型长什么样取决于你输入什么”它在静态分析阶段就卡住了。解决办法是导出的时候把动态轴固定下来直接把输入 shape 设置为训练时的尺寸。在 Ultralytics 里export 函数的参数中imgsz 就是控制这个的注意一定要传入一个固定的尺寸值。如果你的训练分辨率就是 640那就传 imgsz640。我用具体命令说明yolo export modelbest.pt formatonnx imgsz640 opset11注意我这里指定了 opset11。为什么是 11 而不是默认的更高版本因为 ST 的工具链对 ONNX opset 版本的支持是有上限的我在实际测试中opset 11 是最稳妥的。你可能会问那用 opset 12 或 13 行不行我的建议是除非官方文档明确说明支持某个更高版本否则不要冒险opset 越高用到的算子版本越新ST 端不认识的概率也越大。在我自己这个项目里最初就是因为没有固定 imgsz导致导出的 ONNX 输入是动态的上传到 ST Edge AI Developer Cloud 后模型分析虽然能完成但一进入到生成 NBG 的环节就直接失败错误信息没有任何可读性。后来我固定 imgsz 后重新导出这个问题马上消失。这里有个操作小技巧导出完成后用 Netron 打开 ONNX 文件直接看输入节点。如果输入 shape 显示为 [1, 3, 640, 640]说明已经固定了如果显示为 [1, 3, batch, -1] 或者带 dynamic 字样说明还是有动态轴没去掉。3.2 输入输出张量规范ST 工具链对 YOLO 系列的预期ST Edge AI 工具链内部对 YOLO 系列模型是做过专门适配的理论上它能识别 YOLOv8n 的模型结构并自动做输出层的解析。但前提是你的模型输出张量结构必须符合它的预期。以 YOLOv8n 为例它的输出是一个扁平的二维张量形状为 [1, 4class_num, 8400]其中 8400 是不同尺度特征图上的预测框总数。对于 COCO 80 类输出就是 [1, 84, 8400]对于我的 5 类自定义模型输出就是 [1, 9, 8400]。这个形状信息 ST 端在分析时是需要的它要据此确定输出层怎么解析、后处理怎么做。如果你的模型在导出时输出结构变了比如把 8400 这个维度拆了或者增加了一些额外的后处理算子ST 工具链可能就没法正确识别输出节点NBG 的生成过程也会失败。有一个跟输出结构相关的高频问题导出时是否包含 NMS 层。Ultralytics 的 export 函数里有个参数 nms我明确建议这里不要开启。原因主要有两个第一ST Edge AI 工具链自己在后续的代码生成里会在 MCU 端生成 NMS 相关的后处理代码如果你在 ONNX 里嵌入了 NMS 层可能会形成重复处理也可能因为 NMS 算子不被 ST 端支持而直接导致分析失败。第二从性能角度讲NMS 这种非极大值抑制的逻辑在 MCU 上用 CPU 循环实现比依赖模型里的自定义算子要高效得多。模型里只要输出原始的预测张量剩下的交给后处理代码去处理是标准的做法。所以导出命令应该是yolo export modelbest.pt formatonnx imgsz640 opset11 nmsFalse3.3 量化支持Float32 还是 Float16直接影响生成成功率ST Edge AI 工具链一个核心能力是模型量化它可以把浮点模型量化为 8-bit 整数从而大幅减小模型大小和推理耗时这是它在 MCU 上部署的关键价值。但量化过程对模型中的算子和层类型是有要求的不是所有算子都能被量化器正确处理。默认情况下Ultralytics 导出 ONNX 时权重是 Float32 的。在 ST Edge AI Developer Cloud 上你可以在生成 NBG 的选项里选择 Float32、Float16 或 Int8 量化。我的经验是Float32 模式基本不会出问题而 Float16 和 Int8 对模型中的算子支持更苛刻如果你的模型里有某些特殊算子比如一些自定义激活函数、上采样方式等量化过程可能直接失败。所以如果你一开始只是想把 NBG 文件跑通我的建议是直接在云端选择 Float32 或 Float16 选项先不碰 Int8。等生成 NBG 成功后再尝试 Int8如果 Int8 失败就要回头去看模型里有没有不支持的算子。不过这里有个更微妙的点。即使你选择 Float32ST 工具链在分析时也可能会对模型做预处理比如 BN 层融合、算子折叠等。如果模型结构有某些异常这层优化也可能触发错误。这时候你需要在本地预先处理一下 ONNX把模型简化一下比如用 onnx-simplifier 工具做一次简化去掉一些冗余算子再上传就顺了。我的经验是很多自定义 YOLOv8n 模型导出的 ONNX 中会包含一些形状计算、常量折叠等辅助算子这些算子对推理本身没有影响但 ST 工具链的解析器会在它们上面卡住。用 onnx-simplifier 简化一次往往能解决一批莫名其妙的问题。3.4 算子兼容性你的模型里有没有 ST 不认识的算子这是自定义模型最容易触发的问题也是排查起来最麻烦的一类。ST Edge AI 工具链支持的算子集合是有限的它针对 MCU 平台做了裁剪很多在 PC 上很常见的算子它不一定支持。YOLOv8n 的基础结构相对简单主要由 Conv、BatchNorm、SiLU、Concat、Upsample、Split、MaxPool 等基础算子组成。官方预训练模型能够顺利通过说明这套算子集合本身是被支持的。但自定义训练过程中如果你改动了激活函数比如把 SiLU 换成了 GELU 或者 LeakyReLU需要确认 ST 端是否支持。如果你在 neck 里加了注意力机制比如 SE Block、CBAM 之类的这些模块会引入新的算子比如 GlobalAveragePool、Sigmoid、Mul 等要逐个确认。如果训练代码或模型结构导出的 ONNX 里包含一些训练阶段特有的算子比如 Dropout虽然在 YOLOv8 里推理时会被去掉但保险起见还是要查一下也可能导致问题。有一个比较实用的检查方法先拿到一个官方 yolov8n 导出并能成功生成 NBG 的 ONNX 文件再拿你自定义模型导出的 ONNX 文件用 netron 或者 onnx 的 API 去列出这两个模型的算子集合然后做差集。差集里的算子就是你需要重点排查的对象。可以写一个简单的 Python 脚本来对比算子集合这里提供一个参考实现import onnx def get_ops(model_path): model onnx.load(model_path) ops set() for node in model.graph.node: ops.add(node.op_type) return ops official_ops get_ops(yolov8n_official.onnx) custom_ops get_ops(yolov8n_custom.onnx) extra_ops custom_ops - official_ops print(Custom model has extra ops:, extra_ops)这一步做完你对“ST 会不会因为算子问题失败”就有了一个比较清晰的预判。能精简的算子尽量在导出阶段或者模型定义阶段就去掉省得后续反复试错。4. 实操过程从 YOLOv8n 自定义模型到 NBG 的完整走通路径4.1 环境准备与工具选型建议本地环境这部分我用的是 Ubuntu 20.04Python 3.8PyTorch 1.13Ultralytics 源码版本是当时最新的 8.x。建议你尽可能用官方源码而不是 pip 安装的集成包因为源码里能直接看到 export 相关逻辑排查问题时方便很多。关于模型训练我默认你已经完成了 YOLOv8n 的自定义训练拿到了 best.pt。如果还没有训练建议先用官方 COCO 预训练权重做一次完整的全流程演练把 ST Edge AI Developer Cloud 上生成 NBG 的流程跑通再上自己的自定义模型。这样能避免把“训练问题”和“部署问题”混在一起排查否则到时候出了问题你都不知道该查哪一头。工具链方面ST 官方也提供了 ST Edge AI Core 命令行工具可以在本地做模型分析和代码生成但我这篇文章主要还是以 ST Edge AI Developer Cloud 为主线。如果你更习惯本地操作思路是完全一样的核心还是把 ONNX 准备好。4.2 导出 ONNX 的正确姿势附我踩过的坑我用的是 Ultralytics 官方命令行工具在项目根目录下执行如下命令yolo export modelruns/train/exp/weights/best.pt formatonnx imgsz640 opset11 nmsFalse这里有几个参数我要重点展开一下第一个是 imgsz。默认情况下 YOLOv8 源码训练用的 imgsz 是 640如果你训练时用了别的尺寸导出时也要保持一致。官方文档里说 imgsz 可以是一个整数也可以是 [height, width] 的列表。如果有场景需要非正方形输入比如 640x384可以传 imgsz[384, 640]注意是 [高, 宽]不要搞反否则模型推理时输入 tensor 的维度就对不上了。第二个是 opset。我指定了 11。为什么不用默认的 12 或者更高因为 ST Edge AI 工具链的很多版本在解析 ONNX 时对 opset 的支持上限就是 11。虽然有些格式能用更高版本导出但为了稳定性我建议一律用 11。在某些 Ultralytics 版本里如果传 opset11 导出报错可能是源码里有个默认值覆盖了你的设置这时候你需要直接进源码里修改 export 函数的默认 opset 参数。第三个是 nmsFalse。这个上面已经讲过了核心是不要让 ONNX 里带 NMS 后处理算子把后处理留给 MCU 端代码。第四个是 simplify。Ultralytics 的 export 参数里有一个 simplify 选项设置为 True 会在导出后自动调用 onnx-simplifier 做简化。如果它可用的话这确实能省去单独跑一次 simplifier 的步骤。但我遇到过 simplify 本身跑挂的情况所以我更倾向于自己手动执行导出后用命令python -m onnxsim best.onnx best_simplified.onnx --overwrite-input-shape [1,3,640,640]这样能更加明确地控制简化过程而且你可以在这一步固定输入 shape一步到位。简化完成后把 best_simplified.onnx 重新命名为 best.onnx 或者其他自定义的名字再上传。这一步做完之后我还建议你做一个本地验证用 ONNX Runtime 加载导出的 ONNX输入一张测试图片的预处理张量看看输出形状是否为 [1, 9, 8400]以 5 类为例推理是否正常。这个验证能提前暴露 80% 的模型导出问题。4.3 上传 ST Edge AI Developer Cloud 与生成 NBG 的关键操作登录 ST Edge AI Developer Cloud一路点击进入 Model Zoo 或相关的工具页面。上传你导出的 ONNX 文件平台会自动开始模型分析和特征提取。这里有个细节上传后平台会先做一次模型解析显示模型的输入输出信息。你需要在这里仔细核对一下输入节点的名称、形状是否正确例如 input 节点的形状是 [1, 3, 640, 640]。输出节点的形状是否合理例如 [1, 9, 8400]。平台是否能正确识别出模型类型YOLOv8n 或 YOLO 系列。如果模型解析阶段就出问题后面就不用继续了回头检查导出参数。如果解析正常你就可以点击生成 NBG 的按钮。在弹出的选项里注意选择合适的数值表示格式。我的建议流程是第一次先用 Float32 跑通确认整个链路没问题后再尝试 Float16 或 Int8。这个顺序能避免“量化兼容性”和“模型结构错误”这两种问题搅在一起加大排查难度。点击生成后平台会进入异步处理队列通常需要几分钟到十几分钟。如果生成失败界面会给出错误提示。我遇到的最常见情况就是模型解析成功但 NBG 生成失败错误提示非常模糊没有任何可读的日志。这就要靠上面说的对照实验来定位问题了。4.4 NBG 生成成功后的部署与验证流程NBG 文件生成成功后它会给出对应的 C 代码或项目文件下载这个 NBG 文件本身是个二进制格式你后续需要把它放到 STM32 的工程目录里配合 ST Edge AI Core 的运行时库来加载推理。如果你用的是 STM32CubeMX 或 STM32CubeIDE可以在工程配置里直接加入 X-CUBE-AI 扩展包然后把 NBG 放进去生成初始化代码。关键 API 调用大致如下ai_network_create_and_init(network, network_data); ai_input_initialize(network, input_tensor[0]); ai_output_initialize(network, output_tensor[0]); ai_run(network, input_tensor[0], output_tensor[0]);这些 API 的基本调用流程在 ST 的官方例程里都有照着做就行。需要注意的是由于 YOLO 的输出是 [1, 9, 8400] 的结构你在 MCU 端拿到输出张量后还需要自己做解码、置信度阈值过滤、NMS 等后处理步骤。ST 的 X-CUBE-AI 会自动生成一部分后处理相关的代码但 YOLO 的任务特定逻辑比如锚框解码和 NMS通常不会完整包含进去这部分需要你在应用层自己写。我在这里用的是常规的 YOLOv8 后处理流程大致是把输出张量按 5 类目标拆解对每个预测框计算 confidence 分数低于阈值的直接丢弃剩下的框做类别内的 NMS。如果你用的是其他目标检测模型后处理逻辑的差异会很大需要单独适配。5. 常见问题与排查技巧实录5.1 模型解析通过但生成 NBG 失败先查这四件事这个问题在社区里非常高频我总结一下我排查时的优先级顺序第一检查 ONNX 输入是否为动态形状。这个是第一嫌疑。用 onnx 库或 Netron 查看输入节点的 shape如果有 -1 或者动态维度立即用 onnxsim 固定 shape 后重新导出。第二检查是否有 NMS 算子或端到端后处理算子。如果导出的 ONNX 里包含 NonMaxSuppression、ImageDecoder 之类的算子ST 端很可能不支持。用 onnx 库的 node op_type 列表里搜一下有的话重新导出不要带 nms。第三检查自定义结构是否引入了 ST 不支持的算子。这个用算子差集方法来查前面已经讲过了。一旦发现差集里的算子要么去掉、要么换用标准算子重写模块。第四检查 opset 版本。如果导出的 ONNX 是 opset 13 甚至更高ST 端可能会有解析问题。建议统一降到 opset 11。5.2 同一个模型有时能生成有时失败多半是平台侧波动我也遇到过上午上传同一个 ONNX 能生成 NBG下午同样的文件再传一次就失败的情况。这种概率性的失败我判断大概率是平台侧的资源波动或者服务状态问题不是模型本身的问题。如果你确认本地 ONNX 已经经过了验证算子、shape 都没问题那可以稍等一段时间再试一次或者换个时间段重新上传大概率能通过。这里有个小技巧把上传用的 ONNX 文件在本地保存好不要每次重新导出保证复现时用的是同一个文件。这样能排除导出过程的随机性专门验证平台侧的稳定性。5.3 输入尺寸不一致导致的“隐藏失败”解码端踩坑实录还有一个很隐蔽的问题不是发生在 NBG 生成阶段而是发生在后续 MCU 端推理阶段。你训练时用的是 640x640但导出时不小心用了 416x416或者训练时用的是 640x640导出时传了 640但训练代码里实际做了 Mosaic 增强或者 padding导致模型实际学到的输入分布和导出的输入尺寸不一致。这种不一致在 PC 端 ONNX Runtime 里往往能正常跑出结果因为模型会自动 resize 拉伸但到了 MCU 端结果会很差检测精度大幅下降。为了避免这个问题标准做法是保证训练、验证、导出、部署四个环节使用完全一致的输入分辨率并且预处理逻辑保持一致比如归一化方式、BGR/RGB 顺序、letterbox 填充方式。尤其是 RGB 和 BGR 的顺序问题我见过很多人在这里栽跟头训练时用的 OpenCV 读图是 BGR但导出或部署时代码用的是 PIL 读图是 RGB输入通道顺序就反了模型输出直接废掉。5.4 常见问题速查表下面这个表格是我在实际排查中整理的不一定覆盖所有情况但能覆盖我见过的绝大多数问题先按这个顺序过一遍能解决掉 80% 的报错。现象可能原因解决方案模型解析失败ONNX 文件损坏或格式不正确用 onnx.checker.check_model 检查文件或用 ONNX Runtime 本地跑一次验证模型解析成功生成 NBG 失败输入动态形状或包含不支持的算子固定 imgsz、用 onnxsim 简化、检查算子差集生成 NBG 时提示量化失败某些算子不支持浮点转定点选择 Float32 或 Float16 模式绕过量化或替换不支持的算子生成成功后 MCU 端结果全乱输入预处理不一致或输出解码逻辑错误统一 RGB/BGR、归一化方式、letterbox 参数核对输出张量形状同一文件多次上传结果不一致平台侧服务波动更换时段重试本地保存同一份 ONNX 保证可复现性图片尺寸变了之后 NBG 生成失败输入 shape 被动态推导或模型重训练过用 onnxsim 重写输入 shape确保训练尺寸和导出尺寸一致5.5 我的几个亲测有效的排查顺序建议在实际操作中我发现很多人一遇到报错就开始乱试一会儿改这个参数一会儿改那个参数时间浪费了不少但问题原地踏步。这里我按优先级整理一条清晰的排查路径按顺序执行最快能定位到根因。第一步本地验证 ONNX 文件的有效性。用 onnx.checker.check_model 检查模型结构是否完整用 ONNX Runtime 加载并跑一次推理确认输出形状符合预期。这一步能发现问题就先解决问题不用急着上传。第二步查看模型的输入输出节点信息确认输入 shape 是固定的输出 shape 符合 YOLOv8n 的结构[1, 4classes, 8400]。如果输入 shape 是动态的就用 onnxsim 固定如果输出结构异常重新导出。第三步导出模型时去掉 NMS固定 opset11。这两个参数是我在实际操作中踩过最多坑的地方先用最保守的设置生成一个“最朴素”的 ONNX确认这条路能走通再逐步优化。第四步用官方 yolov8n 预训练权重导出的 ONNX 作为对照上传到云端生成 NBG。如果官方模型能成功自定义模型失败那就是模型结构差异的问题从算子差集和结构改动入手排查如果官方模型也失败那就是工具链版本或者平台服务的问题可以换一个工具链版本试试。第五步如果实在没法从报错信息定位问题可以试着把模型结构简化。比如先导出一个只包含 backbone 的 ONNX上传看看能否生成 NBG逐步增加模块用二分法定位到具体是哪一层哪一块导致失败。这个方法针对复杂自定义结构特别有效虽然麻烦一点但能精确定位问题源。这些步骤看起来基础但每一条的背后都有具体的失败案例来武装。把这个顺序跑一遍大部分 NBG 生成问题都能解决。6. 工具链选型与版本兼容性补充说明关于 ST Edge AI Developer Cloud 和本地工具链的选择我在这过程中也做了一些对比这里补充一些经验。ST 目前提供了两条部署路径一条是在线的 ST Edge AI Developer Cloud另一条是本地安装的 ST Edge AI Core即 X-CUBE-AI 的独立命令行工具。两者底层逻辑一样都是做模型分析、量化、代码生成但表现上有一些差异。在线云平台的优势是免安装、方便适合快速验证模型能不能被支持。但缺点是报错信息非常有限生成过程是黑盒很难拿到详细日志。本地工具链则可以在命令行里输出更详细的 log对定位问题有很大帮助。如果你在云平台反复失败我建议你安装本地 ST Edge AI Core用相同的 ONNX 文件在本地跑一次分析stedgeai generate --model best.onnx --type nbg --output ./output --valinput input.bin本地分析会输出详细的错误日志通常能直接告诉你哪个算子不支持、哪个节点出问题了比在云平台瞎猜强得多。版本兼容性这块我需要特别提醒一句ST Edge AI 工具链的版本和 Ultralytics 源码的版本是有匹配关系的。我在项目里用的是当时最新的 Ultralytics 8.x但 ST Edge AI 工具链的版本更新可能没有跟上所以两者之间偶尔会出现兼容性差异。如果你手头的 Ultralytics 版本导出的 ONNX 在 ST 工具链上反复失败可以考虑把 Ultralytics 源码切到稍早一些的稳定版本比如 8.0.x 系列通常能获得更好的兼容性。我的实际经验是有一批模型在 8.1.x 版本下导出的 ONNX 在本地 ST Edge AI Core 里报奇怪的算子错误但切到 8.0.x 后重新导出就没问题了。这类问题排查起来非常耗时建议从一开始就锁定一套经过验证的版本组合不要随便升级。7. 从这次踩坑中总结的经验以及可以继续扩展的方向这次折腾下来我最大的体会是在嵌入式 AI 部署这条链路上模型训练只占三分之一的工作量模型导出和格式适配才是真正的大头。很多人花两周时间训练模型到了部署阶段一遇到模型转换问题就卡住本质上是太轻视了模型导出这个环节的技术含量。我建议如果你是做嵌入式 AI 的最好从第一天就建立一个“部署导向”的训练习惯训练时就想清楚目标平台的算子支持范围优先使用标准算子导出前先做一次本地 ONNX 验证模型图和预期结构正确了再去碰工具链遇到黑盒报错就用对照实验和二分法把问题边界逐步缩小而不是盲目乱试参数。这个项目目前的成果是 NBG 文件已经能在 STM32H747 上正常跑起来目标检测的推理延迟在 Float32 模式下大约是 300ms 左右每帧后面计划做 Int8 量化目标是把推理耗时压到 150ms 以内。量化的过程中如果遇到算子的兼容性问题我还打算通过修改模型结构来规避比如把一些不支持的模块替换成等价的基础算子组合。最后再分享一个小技巧这是我踩过很多次坑之后总结的不管用什么工具链模型导出的 ONNX 文件一定要在本地用 Netron 打开看一遍确认输入输出节点、shape、算子结构都符合预期之后再上传到云端。这一步只需要花费五分钟但能帮你省掉无数次“上传-等待-失败-再上传”的循环强烈建议大家都养成这个习惯。