尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Atlas 300V 24G实战:YOLOv5模型从ONNX到OM部署全攻略

Atlas 300V 24G实战:YOLOv5模型从ONNX到OM部署全攻略 1. 先搞清楚Atlas 300V 24G到底是什么1.1 一张卡解决三件事聊到Atlas 300V 24G很多第一次接触昇腾生态的朋友第一反应是这到底是显卡还是运算卡答案很明确它是华为昇腾系列里专门做AI推理的运算加速卡不是用来打游戏或者做渲染的GPU。它的核心芯片是昇腾310P系列板卡形态是半高半长的PCIe卡功耗大概在72W左右不需要外接供电插上就能用。我最早接触Atlas 300V 24G是在一个安防项目里客户要求把已有的YOLOv5检测模型从GPU服务器迁到国产化服务器上。当时对比了好几款卡最终选它的原因很简单24GB显存、支持PCIe Gen4 x16接口、单卡INT8算力能到140TOPS左右关键是它不需要改服务器电源普通工作站插上就能跑。这张卡面向的场景非常明确视频流目标检测、OCR识别、图像分类、语义分割这类推理负载。和训练卡不同它不追求大算力去反向传播而是把精力放在低延迟、高吞吐的推理上。24GB这个显存在推理卡里属于大容量了意味着你可以同时加载多个模型或者把一个大模型完整塞进去不用像以前那样切来切去。从运维角度讲Atlas 300V 24G还有一个很实在的优势被动散热。它靠服务器风道散热没有风扇意味着在机房部署的时候少了一个噪声源和故障点。我见过不少GPU卡因为风扇轴承磨损导致温度飙升昇腾这个设计虽然朴素但确实省心。1.2 和GPU方案对比为什么要选它很多团队在选型时会习惯性拿它和NVIDIA的T4、A10去做对比。这里我先给一个中肯的结论如果只看单卡绝对性能Atlas 300V 24G在FP16下大约是T4的水平INT8下会稍微强一些但它的价值点根本不在这。选它的核心原因有三点。第一如果你所在的行业有国产化要求昇腾是少数能形成完整生态的国产AI芯片方案。第二功耗比确实优秀72W的板卡功耗配合24GB显存在边缘机房或者改造过的旧机房里部署非常舒服。第三华为昇腾的CANN工具链在推理场景已经打磨得比较成熟至少我遇到的绝大多数问题都能在官方文档里找到答案。当然它也有明显的局限性。如果你指望拿它去做大模型训练那基本是走错方向了。它的强项是推理尤其是CV类的模型。另外它和TensorRT的生态差距客观存在NVIDIA的开源社区资源多、踩坑记录全昇腾这边很多东西需要自己去翻文档、跑实验。我做了一张简单的对比表供选型时参考对比项Atlas 300V 24GNVIDIA T4NVIDIA A10显存24GB HBM2E16GB GDDR624GB GDDR6功耗72W70W150W接口PCIe Gen4 x16PCIe Gen3 x16PCIe Gen4 x16INT8算力约140TOPS约130TOPS约250TOPS推理软件栈CANN/ MindIETensorRTTensorRT生态成熟度中等正在追赶非常成熟非常成熟如果你对生态兼容性要求极高或者团队里全是CUDA工程师那昇腾的学习曲线是真实存在的。但如果你愿意花一周时间熟悉CANN工具链后面收益会很明显。2. 部署YOLO前先摸清软硬件底细2.1 硬件安装与驱动初始化Atlas 300V 24G的硬件安装和显卡一样插PCIe槽、固定挡板即可。需要注意两点一是确认主板支持PCIe Gen4否则会跑到Gen3带宽对视频流多路并发有一定影响二是注意供电和散热空间虽然卡本身功耗只有72W但它旁边不能塞得太满进风量不足等于是慢性自杀。驱动安装这块我建议不要拿官网最新版本直接装。昇腾的驱动和固件通常是配套发布的用交叉版本很容易出现npu-smi能看到卡但跑推理报错的情况。我的习惯是先确定CANN版本再根据CANN版本去匹配驱动和固件的版本号。安装完成后用npu-smi info命令验证npu-smi info如果能看到类似以下输出说明驱动和固件正常------------------------------------------------------------------------------------------- | NPU Name Health Power HBM usage Temp | ------------------------------------------------------------------------------------------- | 0 310P OK 28W 0% / 24GB 45C | -------------------------------------------------------------------------------------------这里重点说一下驱动装完后不要急着跑模型先跑一下官方自带的ascend_install.log检查或者直接用npu-smi info连续看几次温度。如果温度稳定在40到50摄氏度之间说明散热没问题硬件环境基本过关。如果温度动不动就飙到70度以上先检查机箱风道再说别盲目调优软件。2.2 CANN工具链为什么绕不开昇腾生态和NVIDIA最大的区别在于它有一套自己的软件栈叫CANN全称是Compute Architecture for Neural Networks。可以把它等价理解为CUDA加cuDNN加TensorRT的集合体。你的PyTorch模型要跑在Atlas卡上要么通过CANN提供的适配层直接调用NPU要么先把模型转成OM格式再推理。CANN的安装分两个部分一是runtime包包含运行时库和驱动二是toolkit包包含ATC模型转换工具、推理引擎、算子库等。很多新手在安装时只装了toolkit忘记装runtime或者装反了导致atc命令找不到、推理程序链接库失败。我的建议是严格按官方顺序装先驱动再固件再CANN toolkit最后配置环境变量。环境变量是一个很容易踩坑的地方。我见过同事把NPU相关的环境变量写进/etc/profile里导致其他服务也受影响。正确做法是写一个单独的环境变量文件比如/usr/local/Ascend/ascend-toolkit/set_env.sh每次切环境时手动source。如果你用的是conda虚拟环境有两条路可以走一是把CANN的环境变量加到conda环境的activate脚本里二是每次手动source。前者更省心我实际用下来没有出现冲突。CANN的版本迭代非常快每个大版本之间算子支持和接口变化都不小。如果项目周期长建议在需求文档里就锁定一个CANN版本避免后期因为升级导致回归问题。我自己在项目里用的是CANN 7.0.RC1比较稳定和PyTorch 2.0.1的适配也正常。2.3 Python环境与PyTorch的昇腾适配昇腾推理最推荐的路线不是把PyTorch整个跑在NPU上而是用ONNX作为中间格式再转成OM格式。这样做的原因很直接昇腾的PyTorch适配层虽然能用但它的算子覆盖和编译速度仍然不如ONNX链路成熟。尤其在ONNX转OM时CANN提供的OP支持已经覆盖了大部分CV模型。如果你的项目确实需要在Python里直接调用NPU可以用torch_npu这个插件。安装方式如下pip install torch-npu然后PyTorch代码里加一行import torch import torch_npu之后你就可以用.npu()来替代.cuda()了。比如model model.npu() input_tensor input_tensor.npu()但说实话如果目标是部署YOLO我不推荐用这套方案做线上推理。原因是动态shape支持仍然不够顺手而且调试报错信息不直观。我的建议是开发阶段用PyTorch调试模型本身部署阶段用ONNX经历转换后到OM格式推理直接用纯C或者Python的ACL接口调用。有一点要注意昇腾的Python推理接口有两种一种是旧版的pyACL一种是从CANN 6.0开始逐步强推的AscendCL接口。两者都叫ACL但API风格完全不同。新项目直接用AscendCL就好pyACL虽然教程多但很多接口已经标记为废弃没必要在旧路线上重复投入。3. YOLO模型从PyTorch到OM的完整落地3.1 ONNX导出最容易出问题的一步整个部署链路里最容易被低估的就是导出ONNX这一步。很多人以为只要代码能跑通导出就顺理成章实际恰恰相反。YOLOv5系列的模型中包含一些在ONNX导出时特别敏感的算子比如Focus层在部分版本中会展开成多个Slice和Concat操作导致后续ATC转换时出现维度推导失败。我的经验是导出前先把模型放到eval模式并固定所有随机种子然后输入一个固定尺寸的虚拟张量确保模型整个计算图能走一遍。具体代码如下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], dynamic_axesNone ) print(ONNX export done)这里有几个细节值得展开说。第一个是opsert_versionYOLOv5官方默认用的是11或12如果你用太新的opset比如15或16ATC转换时反而可能因为算子版本不匹配报错。第二个是dynamic_axes在部署场景下我更建议先把模型固定成640x640输入导出动态shape的模型等ATC转换时会更麻烦。如果后续确实需要多分辨率推理可以导出多个不同固定尺寸的模型或者用ATC支持的动态维度配置但那是进阶话题了。导出后建议用netron查看一下网络结构确认输出节点名称。YOLOv5的原始输出是一个1x25200x85的张量包含anchor、类别概率和box坐标但ONNX导出后这个张量会被拆分成三个输出一个1x25200x85、一个1x25200x80、还有一个类似1x...的尺寸。这也意味着后续在代码里做后处理时需要自己把这三个输出拼接回来做NMS等操作。很多人在这个过程里踩坑后处理的输入格式和ONNX输出不一致检测框全乱。3.2 ATC转换参数就是坑的集中地ONNX模型导出成功后下一步就是用ATC工具把它转成OM离线模型。ATC的全称是Ascend Tensor Compiler作用相当于NVIDIA的TensorRT。转换命令的常用模板如下atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --insert_op_confaipp.cfg \ --output_typeFP16 \ --loginfo逐个参数解释一下。--framework5表示输入是ONNX模型这个数字不能记错很多报错都源于框架编号填错。--soc_version要根据你的卡来填Atlas 300V 24G对应的是Ascend310P3不同版本的卡对应的soc_version不一样填错了会直接报不支持。--insert_op_conf是插入AIPP配置文件用于图像预处理它可以直接把图像缩放、归一化、颜色转换都塞进模型里省去在推理代码里做前处理的开销。AIPP配置文件的格式如下{ aipp_op: { input_format: RGB, src_image_size_h: 640, src_image_size_w: 640, crop: false, mean: [0, 0, 0], min: [0, 0, 0], var: [255.0, 255.0, 255.0] } }这段配置的意思是输入图像按RGB顺序进来高和宽都是640每个像素除以255归一化到0到1。如果你在PyTorch里训练时用了ImageNet的mean和std那么这里也要改成对应的值不要照抄网上模板。我需要提醒一个关键的坑AIPP的均值方差是乘性还是加性的实现方式和PyTorch不完全一致。PyTorch里是(x / 255 - mean) / std而AIPP配置里的mean和var是直接对输入像素做(pixel - mean) * var。如果你在PyTorch代码里用了mean[0.485,0.456,0.406], std[0.229,0.224,0.225]那么转成AIPP时要反过来换算成var[1/std*255, ...]否则归一化就乱了检测精度会掉得离谱。3.3 推理代码的两种写法OM模型生成之后接下来的问题是怎么调用。这里有两条路一是用Python的AscendCL接口适合快速验证二是用C的AscendCL接口适合生产环境。Python版本的推理代码大概长这样import acl import numpy as np # 初始化 acl.init() ret acl.rt.set_device(0) # 加载模型 model_path b./yolov5s_bs1.om model_id 0 ret acl.mdl.load_from_file(model_path, model_id) # 获取模型输入输出信息 input_desc acl.mdl.get_input_desc(model_id) output_desc acl.mdl.get_output_desc(model_id) input_size acl.mdl.get_input_size_by_index(model_id, 0) output_size acl.mdl.get_output_size_by_index(model_id, 0) # 准备内存 input_data np.random.randn(1, 3, 640, 640).astype(np.float32) input_ptr acl.util.np_to_ptr(input_data) output_ptr acl.util.np_to_ptr(np.zeros(output_size, dtypenp.uint8)) # 推理 ret acl.mdl.execute(model_id, [input_ptr], [input_data.size * 4], [output_ptr], [output_size], 0)这段代码看起来逻辑很直接但实际部署时要考虑内存释放的问题。CANN的ACL接口里输入输出内存必须用acl.rt.malloc分配用普通numpy数组转换过来的指针有可能会导致内存管理异常。我踩过一次这样的坑推理几万次后进程崩溃排查了很久才发现是内存没有按规范走。C版本的优势是资源控制更精确典型调用流程差不多aclInit初始化aclrtSetDevice指定设备aclmdlLoadFromFile加载模型然后循环读取输入、执行推理、后处理。生产环境建议直接走C把模型加载和推理封装成一个服务再通过gRPC和上层通信。3.4 性能验证与调优别被第一版数据骗了模型第一次跑通后先不要急着写报告因为默认配置下的性能数据基本不能反映真实能力。第一版推理速度通常都比较差原因包括没有开AIPP、没有用多线程、没有开启CANN的内存复用。我习惯的调优步骤是先跑一个纯粹的模型延迟测试不加预处理和后处理使用多batch输入。然后逐步加上IO操作定位瓶颈。300V 24G这张卡上YOLOv5s在640x640输入下的单帧推理延迟纯模型部分大约在4到7毫秒之间。如果高于10毫秒说明格式转换或者内存拷贝存在明显问题。另一个容易被忽视的性能优化点是CANN提供的昇腾推理引擎叫做MindIE它可以自动做模型并行、动态分档和推理调度相当于自家生态的高性能部署框架。如果你的并发场景复杂比如同时要处理多路视频流MindIE比手动管理ACL要轻松很多。4. 部署过程中最常见的坑与排查实录4.1 动态shape问题几乎人人会遇到用固定640x640导出ONNX时一切看起来都很正常但一旦你希望支持不同分辨率输入就会在ATC转换或推理阶段遇到维度推导失败的报错。昇腾的模型转换机制和TensorRT类似它需要你在转换时声明输入shape的具体范围。如果你的使用场景确实需要动态分辨率建议对照CANN的ATC文档配置dynamic_dims参数或者用--dynamic_shape模式。这两种方式各有取舍动态dims模式需要你预先定义若干个可选的分辨率档位比如640x640、960x960、1280x1280推理时选择最接近的一档兼顾灵活性和性能完全动态模式灵活度最高但性能和内存占用都会变差。我个人的建议是如果可能尽量用固定shape。视频流场景下可以把输入裁剪或缩放到固定尺寸你损失的只是很小一部分检测精度但换来的却是代码简单、性能稳定、排查问题容易。4.2 精度掉点先怀疑预处理很多团队在GPU上跑YOLO效果很好迁移到Atlas上之后发现mAP掉了好几个点。第一反应往往是算子精度有问题但实际上大部分情况出在图像预处理上。我接手过一个项目目标检测AP从0.82掉到0.71当时排查了大半天最后发现是AIPP配置里把RGB通道的顺序写成了BGR。YOLOv5在训练时用的是RGB顺序但AIPP默认可能是按BGR来处理的如果不显式设置input_format就会导致颜色通道错位检测效果自然崩溃。还有一个隐蔽的坑是letterbox和缩放方式不一致。YOLOv5做推理前会把图像等比缩放到640x640周围补灰边如果AIPP配置里的缩放方式和训练时不一致比如没有保留宽高比直接拉成正方形那么目标物体的形变会导致检测性能明显下降。正确的做法是仿照YOLOv5的letterbox逻辑在AIPP里只指定目标尺寸而缩放比例由AIPP自动根据源图和目标图计算不够的部分填充固定值。4.3 显存不足与内存泄漏24GB显存看起来大但如果你的服务是7x24小时运行内存管理就会变成一个持续的隐患。我在一次长时间压测中发现推理进程的RSS内存一直在缓慢增长直到机器挂了。后来定位到是Python版本的ACL接口在使用numpy数组时没有及时用acl.rt.free释放显存。这个问题的排查思路很简单在一个循环里做推理记录每次推理前后进程的内存和NPU显存占用。如果数值单调递增说明有资源泄漏。解决办法是尽量用ACL提供的内存管理接口分配内存避免频繁创建和销毁numpy数组。还有一个容易被忽视的点Atlas 300V 24G虽然显存有24GB但NPU的可用内存还和你加载的模型数量有关。如果同时加载多个OM模型每个模型固定占用一部分显存内存碎片会越来越严重。建议在模型初始化阶段就把所有需要用的模型全部加载完毕运行期间不再动态加载最大程度避免碎片问题。4.4 多路视频流并发调度Atlas 300V 24G在安防场景里最常见的用法是接多个RTSP视频流用YOLO检测每个画面里的目标。如果你对每一路视频流都起一个独立的推理线程很快你会发现算力并没有跑满但延迟却上来了原因是线程切换开销太大。正确的姿势是做一个推理队列把多路视频帧统一送进队列由几个固定的推理工作线程去消费。卡本身的多路并行能力远超你的单路延迟预期合理调度才能把卡的吞吐量榨干。我实际测试过用8路720p视频流做YOLOv5s推理在300V 24G上可以做到每路实时25帧以上CPU占用也控制在比较低的水平。另外建议在队列层就做好弃帧策略。当程序响应不过来时优先丢旧帧而不是排队等待这样能保证视频画面的实时性避免累积延迟。5. 一些绕不开的经验教训5.1 环境隔离比什么都重要如果你在同一个服务器上既要跑CUDA程序又要跑CANN程序一定要做好环境隔离。我见过一台机器同时装了TensorRT和昇腾CANN结果两个工具的so库版本互相干扰导致运行时报符号找不到的错误。解决办法有两种一是用Docker容器隔离nvidia-docker和ascend-docker各自跑各自的互不影响二是在裸机环境里用module或自定义脚本严格切换环境变量。我更推荐Docker方案还可以顺便固定版本环境方便迁移。5.2 排查故障时先看日志昇腾的日志系统比CUDA生态要更集中一些默认输出在~/ascend/log目录运行出错时别急着搜代码问题先看看日志里有没有明确的错误码。我对三次严重故障的排查中有两次都是通过日志直接定位到问题节省了大量时间。日志级别可以通过环境变量控制生产环境建议设置为INFO级别调试时再调成DEBUG。DEBUG日志信息很详细但量也很大跑一个视频流都能刷出几百MB日志别在生产环境开。5.3 模型转换不是一劳永逸ONNX转OM的过程不是纯机械的格式转换它涉及算子融合、图优化、量化等很多环节。同一个ONNX文件不同的CANN版本转换结果和性能差异都很大。如果你的CANN版本今年升了一级建议把关键模型的转换和验证全部重跑一遍不要只升级软件栈不验证模型。此外CANN的算子支持列表一直有更新。如果你的YOLO版本比较新里面的一些算子可能在旧版本ATC里还不支持这时候不要硬着头皮去改算子直接升级CANN版本往往更有效。我个人在维护一个多模型推理平台时会为每个模型建立单独的转换记录卡片记录CANN版本、ATC参数、输入shape、精度指标和性能指标。任何环境变更都要重跑基准测试确保改动的影响有数据支撑。这也是整个部署体系中最容易长期获益的习惯。
返回列表