
你手头正好有一张 Atlas 300V 24G想在它上面把 YOLO 跑起来结果刚开机就被驱动、CANN、ATC 这些概念绕得有点晕——这是大多数人第一次接触昇腾生态时的真实状态。我去年在一套边缘服务器上亲自踩了一遍这条链路最后把 YOLOv5s 稳稳当当跑在 Atlas 300V 24G 上精度没掉延迟也在预期范围里。这篇文章就把这条完整路径写清楚从这张卡到底算不算运算加速卡、CANN 软件栈是什么、ONNX 怎么转成 OM、推理代码怎么写一直讲到性能和常见坑位。不管你是第一次用 Atlas 的算法工程师还是做边缘部署的运维同学沿着这篇走一遍都能把流程跑通。1. Atlas 300V 24G 到底是什么1.1 一张卡先确认它是不是运算加速卡先回答那个热词问题Atlas 300V 24G 是运算加速卡吗答案是肯定的但准确说它是一张AI 推理加速卡不是通用计算卡。和 GPU 不一样它没法随便跑各种通用计算负载而是针对神经网络推理场景做了专门设计。卡的核心是昇腾 310P 处理器上面集成了专门用于矩阵运算的 AI Core还带了一组 ARM CPU 核用来做数据搬运和任务调度。这张卡在市场上的完整名称一般是 Atlas 300V24GB 版本属于华为昇腾推理卡里的中坚产品。它的规格里让我印象最深的几个点如下24GB HBM2e 高带宽显存比很多同级别推理卡的显存都充裕跑大模型或者大分辨率输入都不容易爆显存。支持 INT8 和 FP16 推理官方标称整数精度算力在百 TOPS 级别跑 YOLOv5s 这类检测模型完全够用。标准 PCIe 接口插到普通 x86 服务器上就能用不需要专用整机。无独立风扇被动散热最大功耗大概在 70W 上下所以对服务器机箱风道有一定要求。为什么这个组合适合做 YOLO 部署因为 YOLO 系列模型经过量化后用 INT8 精度推理精度损失通常可以控制在一个可接受范围内而推理速度能比 FP32 快好几倍。Atlas 300V 24G 这种推理卡本身就是冲着“把模型跑得快、跑得稳、功耗低”去的所以在边缘视频分析、工业检测、智慧安防这类场景里很常见。1.2 为什么 YOLO 部署场景会选它如果你在 AI 加速卡市场里比一圈会发现选择很多但 Atlas 300V 24G 有它独特的位置。我自己的判断是它最突出的三点是显存大、功耗低、生态固定。24GB 显存是它的一个明显优势。很多推理卡只有 8GB 或者 16GB 显存跑一个 batch 较大的 YOLO 模型或者同时跑多个模型实例时会很紧张。24GB 让操作空间大了不少我甚至在同一张卡上同时加载 YOLOv5s 和 YOLOv5m 两个模型做多路视频分析显存仍然没到瓶颈。功耗低则让它对服务器环境很友好。边缘机房或者一体机上散热和电源余量往往都很紧张一张 70W 级别的卡插上去不需要额外的供电线风道设计好就不会过热降频。这一点在实际部署中真的影响很大我之前在一个 2U 机箱里同时插了两张卡长时间满载跑也没有出现温度报警。至于生态昇腾有自己的一套 CANN 工具链虽然学习成本存在但一旦熟悉流程后面部署新模型基本都是重复同一套操作。这一点我在后面的步骤里会展开讲。2. 先搭好软件栈驱动与 CANN2.1 装驱动之前先确认三件事很多人拿到 Atlas 300V 24G 后第一件事就想赶紧跑模型结果卡在装环境这一步。我建议先花十分钟确认三件事能省下后面几天排查问题的时间。第一确认服务器系统版本。昇腾的驱动和 CANN 对操作系统版本有明确支持列表Ubuntu 20.04、Ubuntu 22.04、openEuler、CentOS 等都在支持范围内但不同的内核版本可能影响驱动安装。我自己用的是 Ubuntu 22.04整体兼容性不错。第二确认你的卡是不是被系统识别到了。插好卡后在终端执行lspci | grep -i ascend如果能看到一个华为设备说明 PCIe 层面没问题。这一步很重要因为有时候卡没插紧或者 PCIe 插槽供电不足系统层面根本看不到硬件。第三确认你已经注册了华为账号能下载到对应版本的驱动和 CANN。昇腾的软件包可以在华为昇腾社区下载注意要根据你的卡型号Atlas 300V 24G选择匹配的版本。这里有一个容易犯的错误直接下载最新版驱动但你的卡是 300V 系列而下载的驱动可能主要面向 300I 或 300F 系列。不同加速卡的驱动包和固件并不完全通用选错版本会导致安装成功后 npu-smi 依然看不到设备。所以下载时一定要看清楚固件包和驱动包适配的产品型号。2.2 安装驱动和 CANN Toolkit 的步骤确认完这三件事就可以开始安装了。昇腾的安装文档写得很详细但我这里用一个更贴近实战的顺序来梳理避免你在文档里绕晕。驱动安装一般会拿到一个.run文件比如Ascend-hdk-310P-npu-driver_xx.run直接执行chmod x Ascend-hdk-310P-npu-driver_xx.run ./Ascend-hdk-310P-npu-driver_xx.run --full安装过程中会有一堆日志输出看到提示安装成功即可。然后需要重启或者重新加载驱动具体以安装日志提示为准。安装后执行npu-smi info这时候如果能列出卡的信息驱动就正常了。我自己的经验是如果npu-smi info能看到一张 Atlas 300V 24G并且 Chip Count 和 Device Count 都对那硬件层面就已经通了。驱动装好后接下来是 CANN Toolkit。CANNCompute Architecture for Neural Networks是昇腾的异构计算架构可以理解成昇腾的“CUDA cuDNN”AI 应用跑在昇腾卡上底层都依赖它。安装命令类似chmod x Ascend-cann-toolkit_6.3.RC1_linux-aarch64.run ./Ascend-cann-toolkit_6.3.RC1_linux-aarch64.run --install需要注意Atlas 300V 24G 本身是 x86 服务器上用还是 arm 服务器上用决定了安装包架构。如果服务器是 x86 的下载linux-x86_64的包如果是鲲鹏服务器则下载linux-aarch64的包。用错架构安装时就会直接报错或者装完后命令找不到。装完 CANN Toolkit 后会生成一个环境变量脚本你需要 source 一下才能使用atc、npu-smi等命令source /usr/local/Ascend/ascend-toolkit/set_env.sh为了以后不用每次敲 source可以把这行加到~/.bashrc里。这也是我踩过的一个坑明明装了 CANN但执行atc --version却提示找不到命令原因就是环境变量没加载。2.3 环境验证npu-smi 是第一个朋友环境安装完成后除了npu-smi info我还会执行几条命令确认整条链路是通的npu-smi info atc --version python -c import acl; print(acl ok)npu-smi info看的是驱动和硬件状态atc --version确认模型转换工具可用import acl则是确认 Python 侧能调用 CANN 的 AscendCL 接口。这三条命令都能正常通过说明环境基本没有大问题。这里我要多说一句Atlas 的设备编号和npu-smi info里显示的不一定是你预想的那样有时候一张卡对应设备 0有时候对应设备 1取决于物理插槽。所以在写代码之前先执行npu-smi info看一下你要用的设备号能避免后面初始化设备时报错。3. 模型转换从 ONNX 到 OM3.1 把 YOLOv5 导出成 ONNX环境准备好之后就可以开始处理模型了。昇腾卡不能直接跑 PyTorch 的.pt模型需要先把模型转成 ONNX 格式再通过 ATC 工具转成昇腾自家的 OM 模型。YOLOv5 官方代码仓库里自带导出脚本export.py直接用就行python export.py --weights yolov5s.pt --include onnx --img-size 640 640如果你更习惯手动导出也可以写一段 PyTorch 导出代码import torch from models.experimental import attempt_load model attempt_load(yolov5s.pt, map_locationcpu) model.eval() dummy_input torch.randn(1, 3, 640, 640) torch.onnx.export( model, dummy_input, yolov5s.onnx, opset_version11, input_names[images], output_names[output0, output1, output2], dynamic_axesNone )这里有两个细节值得注意。第一个是dynamic_axes最好设成None也就是导出静态 shape。昇腾卡上跑静态 shape 模型性能和稳定性都更好而且静态 shape 的 ATC 转换参数也简单很多。第二个是 YOLOv5 导出时三个输出是不同尺度特征图上的预测结果如果要转换后方便解析可以先用 onnx-simplifier 简化一下模型。导出完成后强烈建议用 Netron 打开 ONNX 看一眼输入输出的具体名称和 shape因为每个版本的 YOLOv5 输出节点名都不太一样。不要凭记忆猜节点名这个习惯能帮你避免后面 ATC 转换和推理时反复踩坑。3.2 ATC 转换参数逐个解释拿到 ONNX 文件后下一步就是用 ATC 工具转成 OM 文件。ATCAscend Tensor Compiler是 CANN 自带的模型转换工具它的作用是把 ONNX、TensorFlow、Caffe 等格式的模型编译成昇腾卡能直接运行的 OM 模型。我最常用的转换命令是atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --input_formatNCHW \ --output_typeFP32让我逐个参数解释一下--model输入模型路径。--framework模型原始框架编号ONNX 对应 5。--output输出的 OM 文件名。--soc_version芯片型号版本。Atlas 300V 24G 对应的是Ascend310P3系列。怎么确认可以执行npu-smi info看芯片类型也可以在 CANN 安装目录下用工具查询或者在文档里查这个卡对应的 SoC 版本。不确定的时候填错会导致转换报错。--input_shape输入张量的静态形状格式是节点名:维度。这里的images要和 ONNX 里的输入节点名一致。--input_format输入数据排布方式YOLOv5 导出时默认是 NCHW所以这里写 NCHW。--output_type输出数据类型一般用 FP32保证后续解析精度。如果你导出 ONNX 时给三个输出分别起了名字转换时也可以指定输出节点避免保留一些多余的中间节点占用显存atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --out_nodesoutput0:0;output1:0;output2:0这里output0:0的意思是输出节点output0的第 0 个张量。如果你不想自己记节点名直接在 ATC 后面不加--out_nodes也是可以的ATC 会默认保留 ONNX 的所有输出节点。转换过程一般会打印一些日志如果最终出现success字样并且生成了.om文件那就成功了。转换时间取决于模型大小YOLOv5s 这种规模的模型通常在几十秒到一两分钟之间。3.3 转换报错的常见原因ATC 转换并不总是顺利我遇到过的报错集中在这么几类。第一类是--soc_version填错。比如把 300V 的芯片型号填成了 310P 系列里不存在的版本ATC 直接报找不到对应配置。解决方法是查清楚卡对应的具体 SoC 版本不要想当然地填一张卡的名称。第二类是算子不兼容。有些 ONNX 算子昇腾的 ATC 编译器不认识或者版本不支持。这时候报错信息里会有一个算子名你需要判断这个算子在模型里是干什么用的。如果是不重要的后处理算子可以尝试在导出 ONNX 时去掉或者用一个更底层的等价算子替换。我之前遇到过 YOLOv5 里某些版本导出的Resize算子参数不兼容换了一个导出方式就解决了。第三类是 shape 不匹配。--input_shape写错节点名或者维度不对ATC 会直接报错。为了避免这个转换前用 Netron 看清楚输入节点名是images还是别的别想当然。如果遇到 ATC 崩溃或者报错信息很含糊可以加上--logdebug重新执行让日志输出更详细定位到具体是哪一步失败。这个方法虽然看起来傻但真的比瞎猜高效得多。4. 推理代码AscendCL 从初始化到出结果4.1 一个能跑通的最小推理流程模型转换完成后推理代码就可以开始写了。昇腾提供的 AscendCLAscend Computing Language是底层推理接口用 Python 或者 C 都可以调用。我用 Python 举一个最小可运行的例子。先导入模块并初始化设备import numpy as np import acl # 相关常量 ACL_MEM_MALLOC_HUGE_FIRST 0 ACL_MEMCPY_HOST_TO_DEVICE 1 ACL_MEMCPY_DEVICE_TO_HOST 2 def runtime_init(device_id): ret acl.init() if ret ! 0: raise RuntimeError(acl.init failed, ret {}.format(ret)) ret acl.rt.set_device(device_id) if ret ! 0: raise RuntimeError(acl.rt.set_device failed, ret {}.format(ret)) context, ret acl.rt.create_context(device_id) if ret ! 0: raise RuntimeError(acl.rt.create_context failed, ret {}.format(ret))接着加载 OM 模型def load_model(model_path): model_id, ret acl.mdl.load_from_file(model_path) if ret ! 0: raise RuntimeError(acl.mdl.load_from_file failed, ret {}.format(ret)) model_desc acl.mdl.create_desc() ret acl.mdl.get_desc(model_desc, model_id) if ret ! 0: raise RuntimeError(acl.mdl.get_desc failed, ret {}.format(ret)) return model_id, model_desc然后准备输入数据。假设输入是 NCHW 的 640x640 RGB 图像float32 类型def prepare_input(model_id, model_desc, input_np): input_size acl.mdl.get_input_size_by_index(model_id, 0) input_np np.ascontiguousarray(input_np) input_ptr, ret acl.rt.malloc(input_size, ACL_MEM_MALLOC_HUGE_FIRST) if ret ! 0: raise RuntimeError(acl.rt.malloc failed, ret {}.format(ret)) ret acl.rt.memcpy(input_ptr, input_size, input_np.tobytes(), input_size, ACL_MEMCPY_HOST_TO_DEVICE) if ret ! 0: raise RuntimeError(acl.rt.memcpy failed, ret {}.format(ret)) return input_ptr, input_size执行推理并取回输出def run_inference(model_id, model_desc, input_ptr, input_size): output_size acl.mdl.get_output_size_by_index(model_id, 0) output_ptr, ret acl.rt.malloc(output_size, ACL_MEM_MALLOC_HUGE_FIRST) if ret ! 0: raise RuntimeError(acl.rt.malloc output failed, ret {}.format(ret)) ret acl.mdl.execute(model_id, input_ptr, input_size, output_ptr, output_size) if ret ! 0: raise RuntimeError(acl.mdl.execute failed, ret {}.format(ret)) output_np np.zeros(output_size, dtypenp.uint8) ret acl.rt.memcpy(output_np.tobytes(), output_size, output_ptr, output_size, ACL_MEMCPY_DEVICE_TO_HOST) if ret ! 0: raise RuntimeError(acl.rt.memcpy device to host failed, ret {}.format(ret)) return output_np这段代码就是我用来验证整个链路“能跑通”的最小集合。第一次跑通的时候看到能返回一个非空的输出数组心里的石头就算落地了。这里有个经验要分享acl.rt.malloc和acl.rt.memcpy的接口很底层实际项目里很多人会封装一层内存池避免频繁申请和释放内存。但第一次验证流程时不需要过度设计能跑通才是最重要的。4.2 输入输出的格式与内存管理到了收尾阶段你会发现一个容易被忽略的点acl.mdl.execute执行完后输出数据到底长什么样这取决于你的模型。如果你直接把 YOLOv5s 的 ONNX 转成了 OM那么输出通常也是一个包含三个检测头的张量组合Post Processing 需要你自己做。关于内存管理有一点我必须提一下昇腾的显存和主机内存是分离的用acl.rt.malloc申请的设备内存用完一定要用acl.rt.free释放否则多次推理后显存会慢慢耗尽。我在一次长时间跑视频流分析时因为没有及时释放中间结果跑了几个小时就 OOM 了最后加了一次完整的显存排查才找到泄漏点。一个实用的做法是在循环推理场景里预分配好输入输出内存每次推理只做 memcpy 和 execute不要在循环里频繁 malloc。这样既能提升性能也能避免显存碎片化。4.3 后处理YOLO 的输出不是坐标OM 模型直接输出的并不是最终的目标框坐标而是特征图上每个位置的预测结果需要经过解析才能得到可用的检测框。YOLOv5s 在 640 输入下有三个输出层特征图尺寸分别是 80x80、40x40、20x20。每个特征图上的每个位置输出 580 个值如果不做类别裁剪分别是 cx、cy、w、h、obj_conf 和各类别置信度。你需要先按置信度阈值过滤掉低置信度的框然后做解码把特征图坐标换算到原始图像坐标最后做 NMS非极大值抑制去掉重叠框。这一部分可以用 NumPy 实现很多开源项目已经写好了网上搜 “yolov5 numpy decode” 就能找到现成代码。我自己的建议是第一次跑通先不优化照着开源实现把结果画出来确认效果没有偏差再考虑把后处理挪到更高效的地方。如果你在部署中不想写这么多后处理代码还有一条更省事的路线使用 MindX SDK它提供了封装好的推理流程甚至可以直接用插件方式完成检测框后处理。不过这也意味着引入了新的依赖是否采用取决于你的项目灵活度。5. 性能调优实践5.1 先找瓶颈模型刚跑通时性能往往不尽如人意很多人第一反应是“卡不行”。但根据我的经验大部分情况下卡本身不是瓶颈瓶颈在数据流上。我在第一次做性能测试时用一段循环读图、预处理、推理、后处理的程序测帧率结果单路视频只有不到 20 FPS。当时第一反应是 Atlas 300V 24G 性能不行后来逐段打点一查发现推理本身只花了约 15ms但图像缩放和归一化在 CPU 上就花掉了 25ms后处理又占了不少时间。优化之后同样的模型和卡跑到了单路视频实时 50 FPS 以上。所以性能调优的第一步永远是打点测量不要靠感觉猜测。在预处理、拷贝、推理、后处理四个环节各记录一次耗时就能清楚知道时间花在哪了。5.2 静态 shape 与批量推理如果有条件尽量用静态 shape 的模型。动态 shape 在昇腾上实现起来复杂而且性能通常有折扣因为编译器无法做极致的算子优化。我在前面导出 ONNX 时就建议设dynamic_axesNone转换时用--input_shape固定输入大小就是为了这一步能稳定高效。批量推理则是提升吞吐量的常用手段。如果我同时处理多路视频与其对每帧单独执行一次推理不如把多帧拼成一个 batch 一次性推理。Atlas 300V 24G 这种推理卡在 batch 大一点的时候算力利用率会明显变高。比如 single batch 推理一次可能 15ms但 batch8 时推理一次可能只要 50ms平均到每帧只有 6ms 多吞吐量提升非常明显。当然batch 不是越大越好。增大 batch 会线性增加显存占用到临界点就会 OOM。所以要根据实际显存和模型大小慢慢调我的经验是先从 batch1 开始逐步翻倍找到最优值。5.3 AIPP 预处理上卡图像预处理通常是性能瓶颈之一。如果你在 CPU 上做 resize、归一化、通道转换那么 CPU 负载一上来整个流水线就会被拖慢。昇腾提供了一种叫 AIPPAI Preprocessing的机制可以把这些预处理步骤放到 AI 卡上完成。在 ATC 转换模型时可以传入一个 AIPP 配置文件{ aipp_op: { aipp_mode: static, input_format: RGB, src_image_size_w: 1280, src_image_size_h: 720, crop: false, resize: true, resize_w: 640, resize_h: 640, mean: [0, 0, 0], min: [0, 0, 0], var: [255, 255, 255] } }使用 AIPP 后输入给模型的原始图像数据不需要在 CPU 上做过多的格式转换NPU 算子会直接得 resize 和归一化后的结果。这样 CPU 侧就完全腾出来了。有一个容易踩的小坑input_format是RGB还是BGR必须和你上送原始数据的通道顺序一致。YOLOv5 训练时一般用的是 RGB但 OpenCV 读出来的图像不是 RGB 而是 BGR。如果你不想手动转换就把input_format写成BGR。如果你在代码里已经cv2.cvtColor转成了 RGB那就写RGB。这个顺序搞反模型会学到的内容完全错位推理效果会极度变差。5.4 多线程与多 Stream多路视频场景下我一般还会用多线程配合多 Stream 来提升并发能力。昇腾的 AscendCL 支持创建多个推理流Stream不同的流可以在同一个设备上并行执行任务提高硬件利用率。把一个视频源分配给一个线程线程内部创建独立的 Stream在线程里循环读取、预处理、推理、后处理这样多路视频之间就不会互相阻塞。但要注意多个 Stream 并发时显存占用会一起增长需要做好显存规划。我遇到过一次因为线程开多了导致显存耗尽的问题最后通过限制并发路数和控制 batch 大小解决了。这里还有一个实践技巧后处理放在单独的线程池里做不要把前后处理和推理串在同一个循环里。因为 YOLO 的 NMS 在 CPU 上是比较耗时的如果放在推理循环里下一帧的输入就没法及时送上。用生产者-消费者模型把“读图-预处理”和“推理-后处理”解耦吞吐量会明显上升。6. 常见问题排查与避坑6.1 一张速查表部署过程中会遇到各种奇奇怪怪的问题很难把所有细节都写全所以我整理了一张速查表记录我实际遇到过的问题和对应的排查思路。现象可能原因排查与解决方法npu-smi info 看不到设备驱动安装错误或未加载检查是否重启加载驱动执行 lspciatc 命令找不到CANN 环境变量未生效source /usr/local/Ascend/ascend-toolkit/set_env.shATC 转换报错 E20001算子不支持或不兼容使用 onnx-simplifier 简化模型或升级 CANN 版本推理输出全 0输入数据格式错误检查 NCHW / NHWC、RGB / BGR、归一化参数推理过程中 OOMbatch 过大或内存泄漏减小 batch检查是否频繁 malloc 未 free多路视频帧率不稳定后处理阻塞推理循环后处理移入独立线程使用多 Stream这张表不一定覆盖所有情况但绝大多数刚上手 Atlas 300V 24G 的部署问题都能在里面找到排查方向。6.2 几个容易踩的“隐形坑”如果你看完了整张表还是没解决问题那可能需要检查一些不那么明显的地方。这里分享三个我印象特别深的坑。第一个是src_image_size_w和src_image_size_h的配置错误。AIPP 配置里这两个参数表示输入原始图像的尺寸但如果你实际上送的是已经 resize 到 640x640 的图像而配置里写的是原图大小NPU 层的 resize 就会出错或者推理结果错乱。我的经验是AIPP 模式下最好直接上送原始分辨率图像让 AIPP 来做 resize这样配置才能对上。第二个是 batch 维度不匹配导致的隐性错误。静态 shape 模型一旦转换时--input_shape写的是1,3,640,640推理时你上送 2 张图拼成的 batchAscendCL 会直接报错或者读取错误内存。这个错误和我们平时的“显式检查”不一样它是运行时才暴露的而且报错信息可能很隐晦。所以拼 batch 之前一定要确认模型输入维度和实际数据维度完全一致。第三个是精度问题。YOLOv5 导出 ONNX 时如果选了不合适的量化和数据格式推理结果可能和 PyTorch 原模型有明显差距。最简单的排查方法是先在 CPU 上用 ONNXRuntime 跑同一个 ONNX再和 OM 模型的推理结果对比。如果 ONNXRuntime 的结果是对的而 OM 的不对问题基本出在 ATC 参数配置上如果 ONNXRuntime 和 OM 的结果差不多但都和 PyTorch 有差距那问题就出在导出 ONNX 的环节。6.3 一个值得养成的调试习惯最后说一个调试习惯保持“逐步输出”的思路。很多人一上来就直接跑整个完整链路出了问题不知道从哪排查。我的习惯是先跑通一条最小链路再逐步加功能。具体顺序是先验证输入数据能不能正常拷贝到 NPU再验证模型能不能加载然后验证裸推理能不能返回非空结果接着用一张已知的测试图验证推理结果是否正确最后才接入图片流和完整后处理。每一步都要有明确的验证标准和日志输出不要跳步。这个习惯帮我节省了非常多的排查时间。部署 AI 加速卡和写普通代码不太一样它涉及硬件、驱动、模型、数据流多个环节任何一环出问题后面的业务逻辑都没法正常运行。7. 写在最后个人体会与建议整套流程走下来我最大的感受是Atlas 300V 24G 部署 YOLO 的过程并不神秘它和在其他推理卡上部署模型的逻辑是一致的——先搞定驱动和工具链再把模型转换到硬件支持的格式最后写推理代码并做性能调优。难点主要集中在前两步只要过了这两个坎后面的开发体验就很接近常规的推理工程了。如果你刚拿到卡我的建议是别急着在真实业务里追求高并发先把一篇最小可运行的示例跑通。跑通之后再一步一步加 AIPP、加批量、加多路并发。这个“先简单后复杂”的节奏能让你在每一步都清楚地知道性能变化和问题来源在哪里。最后分享一个小技巧在 Atlas 300V 24G 上做 YOLO 部署时多保留几份不同版本的 CANN 和驱动安装包。有时候升级 CANN 之后模型转换行为会发生变化同样的命令在新版本上可能就有不同表现。我遇到过 CANN 版本升级后以前能转换成功的 ONNX 突然报算子错误的情况。手边有旧版本安装包就意味着你能快速回退到稳定环境不至于被一个升级卡住整个项目。