1. 城市交通的算力焦虑:为什么偏偏是现在谈昇腾
智能交通这个概念喊了快十年,早期落地的东西其实很朴素——路口装几个摄像头,后台跑个车牌识别,再把信号灯配时调一调,基本就撑起了“智慧交通”的门面。但这两年情况变了,路上的车没少多少,摄像头倒是从200万像素一路卷到800万,卡口、电警、雷视一体机、毫米波雷达、激光雷达,一个路口恨不得塞进去十几种传感器。数据量翻着跟头往上涨,后端那套老架构开始扛不住了。
我去年跟过一个地级市的交通大脑项目,甲方最头疼的不是算法准不准,而是算力不够用。白天高峰期,几百路视频流同时往中心推,GPU池化资源被抢得干干净净,一些非实时的分析任务只能排到凌晨跑。更麻烦的是,很多AI推理任务对时延极其敏感——比如事故检测,从事件发生到系统告警,超过3秒基本就失去实战意义了。这种场景下,传统“视频回传—中心分析—指令下发”的链路,光网络传输就吃掉一大半时间。
所以行业里慢慢形成一个共识:智能交通的下一程,拼的不是算法有多花哨,而是算力底座够不够扎实、够不够靠近现场。这也是为什么“昇腾”这个词最近在交通圈被反复提起。它不是简单换一块芯片的事,而是整套从芯片、算子库、推理框架到行业应用使能的全栈体系。对于做交通AI的团队来说,这意味着你可以在同一个技术栈里完成模型训练、压缩、部署和推理,不用再像以前那样在英伟达、高通、寒武纪之间来回倒腾,适配成本高得吓人。
这篇文章我想聊的,就是围绕“昇腾+智能交通”这条线,把我在实际项目里踩过的坑、验证过的方案、以及那些文档里不会写的细节,尽量摊开来讲清楚。不管你是刚接触昇腾的算法工程师,还是正在做交通智能化改造的方案架构师,或者只是对这个方向感兴趣的产品经理,下面这些内容应该都能帮你少走一些弯路。
2. 昇腾到底给智能交通带来了什么:从芯片到场景的完整拆解
2.1 昇腾系列芯片的定位与交通场景的匹配逻辑
昇腾系列目前主力是昇腾310和昇腾910两个方向。310主打推理,功耗低、体积小,适合放在边缘侧;910主打训练,算力密度高,一般放在中心机房。交通场景恰好是“云边端”三层结构,跟昇腾的产品线匹配度很高。
我拿一个典型的城市级交通项目举例。路口侧,一台边缘计算单元(通常基于昇腾310)负责实时处理4到8路视频,跑车牌识别、车型分类、违停检测这些轻量模型。区级分控中心放几台昇腾推理服务器,做多路口数据融合、轨迹拼接、信号配时优化。市级中心则用昇腾910集群训练更复杂的模型,比如全城交通流预测、OD矩阵推算。三层各司其职,数据不用全部往上传,带宽省了,时延也降下来了。
这里有个关键点很多人会忽略:昇腾310的算力不是无限的。单芯片INT8算力大概在16TOPS左右,如果你把一路1080P视频的所有分析任务都压上去,跑两三个模型就到顶了。所以实际部署时,一定要做任务分级——哪些必须在边缘做,哪些可以回传中心,哪些可以降帧率处理。我见过一个项目,甲方要求所有路口都做全量结构化,结果边缘盒子过热降频,反而把实时性拖垮了。后来改成“边缘只做检测和跟踪,属性识别回传中心”,整体吞吐量翻了一倍多。
2.2 CANN与MindSpore:软件栈才是真正的护城河
硬件参数是明面上的东西,真正决定开发效率的是软件栈。昇腾的CANN(Compute Architecture for Neural Networks)相当于CUDA的角色,负责算子调度、内存管理、图优化。MindSpore则是华为自家的深度学习框架,跟CANN深度绑定。
我刚开始从PyTorch迁到MindSpore的时候,确实有点不适应。最大的坑是动态图转静态图。PyTorch写惯了,随手一个if-else分支,MindSpore的图编译模式直接报错。后来学乖了,所有条件判断尽量用MindSpore提供的算子替代,或者把动态逻辑抽到图外面用Python控制。这个转换过程大概花了我两周时间,但一旦跑通,推理性能确实比PyTorch原生部署要好,尤其是batch size比较大的时候,CANN的图优化能省下不少显存。
另一个值得说的是ATC模型转换工具。你训练好的模型,不管是MindSpore还是ONNX格式,都要通过ATC转成昇腾专用的.om文件才能上板推理。这个转换过程有几个参数特别关键:--input_shape必须跟实际输入严格一致,--soc_version要跟目标芯片匹配,--precision_mode决定了量化策略。我一般建议先用allow_fp32_to_fp16跑一遍精度测试,如果掉点超过1%,再考虑用must_keep_origin_dtype保精度但牺牲性能。这个取舍在交通场景里很现实——车牌识别掉一个点,可能就意味着每天多几百条误报。
2.3 智能交通的四大核心场景与昇腾的切入点
交通AI的场景看起来很散,但归纳下来无非四类:感知、预测、优化、服务。
感知层是最成熟的,车牌、车型、颜色、人脸、行为,这些在昇腾上都有现成的参考实现。我重点说预测和优化。交通流预测以前用传统时序模型,ARIMA、卡尔曼滤波,现在慢慢被Transformer类模型替代。但Transformer参数量大,推理时延高,放在边缘不现实。昇腾的做法是在中心用910训练大模型,然后通过知识蒸馏压到310能跑的尺寸。我们做过一个实验,一个12层的时空Transformer,蒸馏到4层后,预测精度只掉了0.8%,但推理速度提升了3倍多,完全满足5分钟粒度预测的实时性要求。
信号配时优化是另一个昇腾发挥价值的地方。传统配时方案是离线算好的,一天几个时段切换。现在可以用强化学习做在线优化,但强化学习对环境交互频率要求很高,如果每个路口都独立训练,算力根本不够。昇腾的方案是集中训练、分布推理——中心用910集群跑PPO或者SAC,学出一个通用策略网络,然后下发到各路口的310上做在线微调。这样既保证了策略的全局最优性,又保留了局部适应性。
3. 从零搭建一个昇腾交通AI原型:完整实操流程
3.1 环境准备与工具链安装
先说硬件。如果你只是想验证方案,最经济的做法是买一块Atlas 200 DK开发者套件,大概一千多块钱,昇腾310芯片,4GB内存,跑一些轻量模型足够了。如果要模拟边缘服务器,可以用Atlas 500或者Atlas 800推理服务器。中心训练侧,如果预算有限,可以先租云上的昇腾实例,按小时计费,跑通流程再考虑自建集群。
软件环境我推荐用Ubuntu 18.04或20.04,这是CANN官方支持最好的版本。安装步骤大致如下:
# 下载CANN工具包,注意版本要和固件匹配 wget https://ascend-repo.obs.cn-east-2.myhuaweicloud.com/CANN/6.0.RC1/... # 安装依赖 sudo apt-get install python3.7 python3-pip pip3 install numpy decorator sympy cffi pyyaml pathlib2 psutil protobuf scipy requests # 执行安装脚本 ./Ascend-cann-toolkit_6.0.RC1_linux-x86_64.run --install # 配置环境变量 source ~/Ascend/ascend-toolkit/set_env.sh装完之后用npu-smi info检查芯片状态,能看到310或者910的信息就说明驱动没问题了。这里有个小坑:不同批次的开发板固件版本可能不一样,如果CANN版本和固件不匹配,跑模型的时候会报“device not ready”。解决办法是去官网查对应关系表,或者直接用npu-smi upgrade刷固件。
3.2 模型选型与训练策略
交通场景的模型选型,我的原则是不追新,追稳。检测任务YOLOv5或者YOLOv7就够用,分割任务用DeepLabv3+或者SegFormer,识别任务CRNN或者Transformer-based的OCR模型。关键不是模型多先进,而是能不能顺利转成昇腾能跑的格式。
训练阶段我建议在GPU上做,因为昇腾的训练生态还在完善中,有些自定义算子可能不支持。训练完之后导出ONNX,再用ATC转om。这里有个细节:ONNX的opset版本不要太高,我一般用opset 11,兼容性最好。如果遇到不支持的算子,可以用CANN提供的自定义算子开发工具包自己写一个,但工作量不小,能避开就避开。
数据方面,交通场景最缺的不是数据量,而是标注质量。我见过太多项目,模型在测试集上指标很好看,一上真实路口就崩,根本原因是训练数据跟实际场景分布不一致。我的做法是:先用公开数据集(比如UA-DETRAC、BDD100K)预训练,然后用项目现场采集的数据做fine-tune,最后再用现场数据做一轮hard negative mining,把误报多的样本挑出来重新标。这个过程很枯燥,但效果立竿见影。
3.3 ATC模型转换与精度调优
ATC转换是昇腾开发里最容易出问题的环节。我整理了一个转换命令的模板:
atc --model=yolov5s.onnx \ --framework=5 \ --output=yolov5s_ascend \ --input_format=NCHW \ --input_shape="images:1,3,640,640" \ --soc_version=Ascend310 \ --precision_mode=allow_fp32_to_fp16 \ --op_select_implmode=high_precision \ --output_type=FP32几个参数解释一下:--framework=5表示ONNX,--soc_version根据你的目标芯片填Ascend310或Ascend910,--precision_mode控制量化策略。如果转换失败,先看日志里的“E”开头错误,最常见的是算子不支持。这时候可以加--op_select_implmode=high_precision试试,或者用--customize_dtypes指定某些层用FP32。
转换成功后,一定要做精度比对。CANN提供了msame工具,可以跑推理并输出结果。把昇腾上的输出和GPU上的输出做余弦相似度对比,一般要求达到0.99以上。如果掉点严重,优先检查输入预处理是否一致——很多问题出在归一化参数或者通道顺序上。
3.4 边缘部署与性能压测
模型转好之后,部署到Atlas 200 DK或者Atlas 500上。部署方式有两种:一种是直接用Python调用pyACL接口,灵活但性能一般;另一种是用C++写推理程序,性能好但开发慢。我一般先用Python快速验证,稳定之后再考虑C++重写。
性能压测重点关注三个指标:时延、吞吐量、资源占用。时延用time命令或者代码里打时间戳,吞吐量看每秒能处理多少帧,资源占用用npu-smi info看芯片利用率和内存。我实测下来,YOLOv5s在Atlas 200 DK上跑640x640输入,单帧推理大概在20ms左右,如果开多线程并行,吞吐量能到40FPS以上。但要注意,多线程不是越多越好,线程数超过芯片的物理核心数之后,上下文切换反而会拖慢速度。一般设成4到6个线程比较合适。
4. 那些文档里不会写的坑:常见问题与排查实录
4.1 模型转换失败的五种典型情况
第一种,算子不支持。报错信息通常是“Can not find op xxx”。解决办法是查CANN的算子支持列表,如果确实没有,要么换模型结构,要么用自定义算子。我遇到过一个情况,模型里用了Hardswish激活函数,CANN早期版本不支持,后来换成ReLU6就过了。
第二种,输入shape不匹配。ONNX模型里如果有动态维度,ATC转换时必须用--input_shape固定下来。如果模型里有多个输入,每个都要指定,用分号隔开。
第三种,精度模式冲突。有些层强制要求FP32,但你全局设了FP16,就会报错。这时候可以用--precision_mode_v2或者--customize_dtypes单独指定。
第四种,内存不足。转换大模型的时候,如果机器内存不够,ATC会直接崩掉。建议至少16GB内存,模型特别大的话加到32GB。
第五种,版本不匹配。CANN版本、固件版本、ATC版本三者必须一致,否则各种奇怪报错。我一般会在项目开始前把所有版本号记下来,后面出问题先对版本。
4.2 推理精度掉点的排查思路
精度掉点是最让人头疼的问题,因为原因可能有很多。我的排查顺序是这样的:
先看预处理。昇腾上的预处理(resize、归一化、通道转换)如果跟训练时不一致,精度肯定崩。我习惯把预处理也放到模型里,用ONNX的Resize和Sub、Div算子实现,这样训练和推理完全一致。
再看量化误差。FP16量化对大多数模型影响不大,但对一些数值敏感的层(比如softmax之前的logits)可能会有影响。可以尝试用--precision_mode=must_keep_origin_dtype保精度,或者用混合精度,只对部分层做FP16。
最后看后处理。NMS的阈值、置信度阈值这些,如果跟训练时不一样,也会导致指标变化。这个不是精度问题,是配置问题,但很容易被误判。
4.3 多路视频并发时的资源争抢
边缘设备上跑多路视频,最容易出现的问题是内存泄漏和芯片过热。我遇到过Atlas 200 DK跑四路视频,跑了几个小时之后推理速度越来越慢,最后直接卡死。查了半天发现是每次推理都新建了一个context,没有释放。后来改成全局只建一个context,问题解决。
过热问题在夏天特别明显。Atlas 200 DK没有主动散热,环境温度超过35度就容易降频。我的做法是加一个小风扇,或者把设备放在通风好的地方。如果项目允许,直接用Atlas 500这种带主动散热的型号会省心很多。
还有一个坑是视频解码。如果直接用OpenCV的VideoCapture读RTSP流,CPU占用会很高。昇腾提供了DVPP硬件解码模块,用起来复杂一点,但CPU占用能降一半以上。如果路数多,强烈建议上DVPP。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| ATC转换报“op not supported” | 算子不在支持列表 | 查CANN算子清单 | 替换算子或自定义实现 |
| 推理结果全为0或乱码 | 输入预处理不一致 | 对比GPU和NPU的输入数据 | 统一预处理逻辑 |
| 芯片利用率低 | 线程数不足或IO瓶颈 | npu-smi查看利用率 | 增加线程或优化数据管道 |
| 运行一段时间后卡死 | 内存泄漏 | 监控内存增长 | 检查context和内存释放 |
| 精度掉点超过2% | 量化误差或后处理差异 | 逐层比对输出 | 调整精度模式或后处理参数 |
| 多路视频时延增大 | 资源争抢 | 查看CPU和NPU占用 | 任务分级或增加设备 |
5. 昇腾在交通领域的扩展方向与个人实践体会
5.1 从单点智能到全域协同的演进路径
现在大部分交通AI项目还是“单点智能”——每个路口独立分析,最多把结果传到中心做展示。但真正的智能交通应该是全域协同的:路口A的拥堵,能提前通知路口B调整配时;主干道的车流变化,能实时影响次干道的信号策略。这需要边缘设备之间有高效的通信机制,也需要中心有一个全局优化引擎。
昇腾在这方面的优势是端边云同构。同一个模型,可以在910上训练,在310上推理,中间不需要做太多适配。这意味着你可以把全局优化模型放在中心,把局部执行策略下发到边缘,形成一个闭环。我们做过一个仿真实验,在一个有20个路口的区域里,用全域协同策略比单点策略平均通行效率提升了18%左右。当然实际路网更复杂,但这个方向是明确的。
5.2 多模态融合与边缘侧大模型的可能性
交通场景的数据模态很丰富:视频、雷达点云、地磁、GPS轨迹、天气。以前这些数据是分开处理的,现在越来越倾向于多模态融合。比如视频检测到的车辆位置,跟雷达测距做融合,能大幅提升定位精度。昇腾的CANN支持多输入模型,可以把不同模态的数据在模型内部做特征级融合。
另一个值得关注的方向是边缘侧大模型。现在动辄几十亿参数的模型,放在边缘不现实。但通过模型压缩、稀疏化、量化,把大模型的能力蒸馏到小模型上,让边缘设备也能跑一些“类大模型”的推理,这个路线是可行的。我试过把一个7B参数的交通领域语言模型蒸馏到300M,在Atlas 500上跑,虽然生成质量有下降,但做交通事件描述、自动生成警情简报这类任务,完全够用。
5.3 我在实际项目中的几点体会
第一个体会是:不要为了用昇腾而用昇腾。如果你的项目规模很小,只有几路视频,用传统GPU方案可能更省事。昇腾的价值在于规模化、体系化,路数越多、场景越复杂,它的优势越明显。
第二个体会是:软件生态的成熟度比硬件参数更重要。昇腾这两年的进步很大,但跟CUDA比,算子覆盖、社区资料、第三方库支持还是有差距。做项目的时候,一定要留出足够的时间做适配和调优,不要指望“开箱即用”。
第三个体会是:交通场景的碎片化程度很高。每个城市的路口形态、摄像头角度、光照条件都不一样,没有一个模型能通吃。所以持续迭代的能力比初始模型精度更重要。昇腾的端边云协同架构,恰好支持这种持续迭代——现场发现问题,数据回传中心,重新训练,模型下发,整个闭环可以在一天内完成。
最后分享一个小技巧:如果你在做一个新的交通AI项目,建议先用昇腾的模型动物园里的预训练模型跑通全流程,然后再替换成自己的模型。这样可以把环境问题、转换问题、部署问题跟模型问题分开排查,效率会高很多。我刚开始做的时候,一上来就用自己训练的模型,结果出了问题根本不知道是环境没配好还是模型有问题,白白浪费了一周时间。