1. “Atlas 300V 24G到底是不是运算加速卡”:这个问法本身就值得掰开揉碎
刚接触Ascend系列硬件的朋友,十有八九会先在社区里搜这么一句话:Atlas 300V 24G是运算加速卡吗。我第一次看到这个问题的时候愣了一下,后来发现这其实是很多人的共同困惑。因为单看“24G”这个显存规格,大家脑子里默认对齐的是英伟达那张动辄一两万的显卡,然后就开始纠结:它能不能当GPU用?能不能直接跑CUDA?为什么别人说它“不能训练只能推理”?
先给结论:Atlas 300V 24G确实是一张运算加速卡,但它不是GPU,而是一张基于华为昇腾(Ascend)芯片的AI推理加速卡,产品全称通常是Atlas 300V Pro视频分析加速卡,24G指的就是板载显存容量为24GB,主要用于视频结构化、目标检测、图像分类这类推理负载。
很多人问“是不是运算加速卡”,本质上是在用GPU的心智模型去套NPU。GPU的核心优势是通用并行计算,CUDA生态把“写程序”这个事变成了“写核函数”,只要你懂并行编程,什么计算都能往上丢。但Ascend不一样,昇腾芯片走的是“异构计算架构”,里面有专门的计算单元、向量单元、标量单元,还有一个非常关键的模块——DVPP(Digital Vision Pre-Processing),专门负责图像解码、缩放、格式转换这些预处理操作。
换句话说,Atlas 300V 24G是一张为推理场景定制的算力卡,它的强项是“把训练好的模型高效跑起来”,而不是“从零开始训练一个大模型”。这和“运算加速卡”这个称呼并不矛盾,只是大家默认把“运算加速”等同于“通用计算加速”,才会有这个疑问。
1.1 一张24GB显存的卡,为什么总有人拿它和GPU比
从规格表上看,Atlas 300V 24G的24GB显存确实很显眼,这个容量在边缘推理卡里算是比较大的。大家天然会拿它和RTX 3090、RTX 4090这类24GB显存的消费级显卡做对比,然后发现价格差了好几倍,就开始怀疑它是不是“智商税”。
实际上两张卡的设计目标完全不同。GPU的24GB显存是为了装下大模型、大Batch、大特征图,训练和推理通吃;Atlas 300V的24GB显存则是为了在视频分析场景里同时处理多路视频流。假设一路1080p视频经过预处理后,模型输入是640x640x3,单个样本的显存占用可能只有几MB到几十MB,24GB已经能支撑几十路并发推理。而且NPU的显存管理逻辑和GPU不太一样,它在设计上就更强调高密度并发和低功耗。
我见过一个比较典型的场景:一个智慧园区项目需要同时分析32路摄像头画面,服务器上插了两张Atlas 300V,每张卡处理16路,整机功耗控制在300W出头。如果换成GPU方案,单张卡可能也能跑,但整卡功耗动不动就是300W起步,散热和机房电费都是问题。
所以拿Atlas 300V和GPU直接比“谁的算力强”没有意义,正确的比较维度是“每路视频流的推理成本”和“单位功耗下的算力产出”。
1.2 从训练卡到推理卡,Atlas家族的分工逻辑
了解Atlas系列的产品线,会对判断“运算加速卡”这个词更有帮助。昇腾产品线大致可以分成几档:
| 产品系列 | 定位 | 典型场景 |
|---|---|---|
| Atlas 800/900系列 | 训练服务器 | 大模型训练、微调 |
| Atlas 300I系列 | 推理卡 | 数据中心离线推理、批量推理 |
| Atlas 300V系列 | 视频分析/边缘推理卡 | 视频流分析、目标检测、边缘盒子 |
| Atlas 200/500系列 | 开发板/模组 | 嵌入式设备、机器人、无人机 |
Atlas 300V 24G属于视频分析加速卡,它的接口设计、驱动配套、内存管理都围绕“视频流进、结构化数据出”这个核心任务来优化。它支持PCIe插卡形态,可以插在标准服务器上,也能放进边缘网关设备里。
明白了这层分工之后,再回到部署YOLO这个话题。YOLO这种目标检测算法恰好是视频分析的“主力机型”,所以Atlas 300V部署YOLO属于“对口专业”,而不是“强行移植”。但接下来你很快会遇到一个现状:网上关于YOLOv5/v8跑在GPU上的教程满天飞,而Atlas上部署YOLO的完整实战记录相对分散,很多细节要自己趟。这也是我想把整个流程写明白的原因。
2. 用Atlas部署YOLO的完整链路:从PyTorch/ONNX到OM再到ACL推理
先说一个核心认知:在Atlas上跑YOLO,不能直接把PyTorch模型文件丢上去。昇腾芯片不认识.pt文件,也不直接运行ONNX模型,它需要的是经过昇腾离线模型转换器(ATC,Ascend Tensor Compiler)生成的.om格式模型文件。这个.om文件才是NPU能直接加载执行的“可执行文件”。
所以整个部署链路可以概括为四步:
- 准备YOLO模型:用PyTorch训练或者拿到官方预训练权重
- 导出ONNX:把PyTorch模型导出成带动态/固定shape的ONNX
- ATC转换:用ATC工具把ONNX转成OM,涉及算子映射、精度选择、输入输出设置
- 编写推理程序:用ACL(Ascend Compute Language)接口加载OM模型,做预处理、推理、后处理
下面把每一步拆开讲,每一步都有容易踩坑的细节。
2.1 ATC模型转换:算子映射与精度设置是第一个分水岭
在Atlas上部署YOLO,最核心的一步就是ATC转换。命令本身不复杂,但从ONNX到OM能否一次通过,完全取决于你原始模型里用的算子。
一个典型的ATC转换命令长这样:
atc --model=yolov5s.onnx \ --framework=5 \ --output=yolov5s_16 \ --input_shape="images:1,640,640,3" \ --insert_op_conf=aipp_yolov5.cfg \ --output_type=FP16 \ --soc_version=Ascend310P3参数含义先解释一下:
--model:输入的ONNX模型文件路径--framework=5:5代表ONNX,1代表Caffe,2代表MindSpore--output:输出的OM文件名--input_shape:固定输入shape,这里设置为1,640,640,3,即Batch=1,高宽640,通道3--insert_op_conf:插入AIPP预处理配置,用于图像缩放、颜色转换、均值归一化--output_type=FP16:算子的输出精度,FP16在昇腾上效率更高--soc_version:芯片型号,Atlas 300V 24G需要查对应soc_version,通常是Ascend310P系列
这里第一个容易翻车的地方是input_shape的顺序。PyTorch里YOLO模型的输入是NCHW,也就是(Batch, Channel, Height, Width),但如果你在ATC的input_shape里写成1,3,640,640,然后AIPP配置里又按NHWC方式排布,两者一错位,出来的模型推理结果就会非常离谱——检测框全乱,置信度也不对。原因很简单,昇腾的DVPP硬件模块内部处理图像时用的是NHWC格式(高度、宽度、通道在连续内存中排列),所以很多官方示例里输入shape写的是1,640,640,3。你需要搞清楚自己ONNX模型里的真实layout,以及AIPP配置里要做的转换,而不是想当然。
第二个容易翻车的地方是未支持的算子。YOLOv5的SiLU激活函数、YOLOv8的C2f模块里的某些算子,在旧版本CANN上可能没有完整映射。遇到这种情况,ATC转换会直接报错,提示某个算子不支持。常规解法是升级CANN版本(最好用5.1.RC2以上),或者修改模型结构,把不兼容的算子替换成等价实现。YOLOv8系列在较新CANN版本下基本可以直接转,但YOLOv5的某些早期版本偶尔会遇到问题,这时候优先升级环境,别耗在算子替换上。
2.2 AIPP预处理配置:让硬件帮你完成“标准化”
ATC转换时通过--insert_op_conf指定的AIPP配置文件,是Atlas部署YOLO里一个很特别的设计。AIPP全称是AI Preprocessing,它能把图像缩放、通道转换、归一化这些操作从CPU/GPU搬到NPU里专门的硬件模块去执行,释放CPU资源。
一个面向YOLOv5的AIPP配置示例:
aipp_op { aipp_mode: static input_format: YUV420SP_U8 src_image_size_w: 1920 src_image_size_h: 1080 crop: true load_start_pos_w: 0 load_start_pos_h: 0 crop_size_w: 1920 crop_size_h: 1080 resize: true resize_w: 640 resize_h: 640 csc_switch: true rbuv_swap_switch: false color_space: COLOR_SPACE_BGR mean_chn_0: 0 mean_chn_1: 0 mean_chn_2: 0 min_chn_0: 255.0 min_chn_1: 255.0 min_chn_2: 255.0 }这段配置的意思是:输入源图像是YUV420SP格式(摄像头输出的原始格式),宽高1920x1080,先裁剪(crop),再缩放到640x640,做颜色空间转换(YUV转BGR),最后除以255做归一化。
注意几点:
input_format必须和你的输入数据实际格式一致,如果你的图像源是JPEG解码后的YUV,但配置里写成了RGB,那么颜色会乱套mean_chn/min_chn里的min_chn实际上是“除以的值”,如果YOLO训练时归一化是除以255,那这里就是255.0,而不是减去均值csc_switch: true表示开启颜色空间转换,rbuv_swap_switch控制是否交换R/B通道
很多人在这一步栽跟头,是因为他们把PyTorch推理时的预处理逻辑(比如letterbox、RGB、归一化)默认为在外部用Python/OpenCV做完了,结果AIPP又做了一遍,导致输入图像被处理两次。我的建议是:要么全部交给AIPP做,要么全部在外部做,不要混着来。如果使用AIPP,前端的图像输入给到DVPP后就直接按AIPP配置处理,此时模型输入tensor拿到的已经是预处理后的数据;如果不用AIPP,就需要在Host侧代码里自己完成所有预处理。
2.3 ACL推理:理解“Host侧”和“Device侧”这两套内存
模型转换完成、得到.om文件之后,下一步就是用代码调用ACL接口来执行推理。这一步是纯工程的活,主要难点不在算法,而在理解昇腾的异构架构和内存管理模型。
昇腾平台把运行环境分为两层:
- Host侧:CPU和内存,负责控制逻辑、数据准备、结果解析
- Device侧:昇腾NPU和显存,负责实际执行推理
所以ACL编程的核心思路就是:Host侧准备好输入数据,拷贝到Device侧的显存里,调用推理接口让NPU执行,推理完成后把结果从Device显存拷贝回Host内存,再做后处理。
用C++写的核心推理流程大致如下:
#include "acl/acl.h" #include <iostream> int main() { // 1. 初始化 aclInit(nullptr); aclrtSetDevice(0); aclrtContext context; aclrtCreateContext(&context, 0); // 2. 加载OM模型 uint32_t modelId; aclmdlLoadFromFile("yolov5s_16.om", &modelId); // 3. 获取模型输入输出信息 aclmdlDesc* modelDesc = aclmdlCreateDesc(); aclmdlGetDesc(modelDesc, modelId); // 4. 申请输入输出内存 size_t inputSize = 1 * 640 * 640 * 3 * sizeof(float); void* inputBuffer = nullptr; aclrtMalloc(&inputBuffer, inputSize, ACL_MEM_MALLOC_HUGE_FIRST); size_t outputSize = 1 * 25200 * 85 * sizeof(float); // YOLOv5输出的shape void* outputBuffer = nullptr; aclrtMalloc(&outputBuffer, outputSize, ACL_MEM_MALLOC_HUGE_FIRST); // 5. 准备输入数据(这里需要自己填充预处理后的图像数据) // memcpy(inputBuffer, hostInputData, inputSize); // 6. 执行推理 aclmdlDataset* inputDataSet = aclmdlCreateDataset(); aclDataBuffer* inputDataBuffer = aclCreateDataBuffer(inputBuffer, inputSize); aclmdlAddDatasetBuffer(inputDataSet, inputDataBuffer); aclmdlDataset* outputDataSet = aclmdlCreateDataset(); aclDataBuffer* outputDataBuffer = aclCreateDataBuffer(outputBuffer, outputSize); aclmdlAddDatasetBuffer(outputDataSet, outputDataBuffer); aclmdlExecute(modelId, inputDataSet, outputDataSet); // 7. 把结果拷回Host aclrtMemcpy(hostOutputData, outputSize, outputBuffer, outputSize, ACL_MEMCPY_DEVICE_TO_HOST); // 8. 后处理:解析检测框、NMS等 // 9. 清理资源 aclrtFree(inputBuffer); aclrtFree(outputBuffer); aclmdlUnload(modelId); aclrtDestroyContext(context); aclFinalize(); return 0; }这段代码没有编译过,但ACL接口的调用逻辑就是这样的。你如果用昇腾官方提供的acllite封装库,代码会更简洁,但底层逻辑不变。
这里有一个关键点经常被忽略:模型输出的解析。YOLOv5导出的ONNX输出shape是(1, 25200, 85),也就是25200个候选框,每个候选框有85个值(4个坐标 + 1个置信度 + 80个类别概率)。GPU上用PyTorch跑的时候,你拿到这个tensor之后可以方便地在Python里做筛选和NMS。但在C++的ACL代码里,你要自己把输出buffer按float数组解析出来,自己写NMS和阈值过滤。这部分工作量不小,建议提前规划好。
2.4 为什么要用固定Batch而不是动态Batch
ATC转换时,input_shape里的Batch维度是固定的。比如你转了一个Batch=1的OM模型,那推理时输入就必须是1张图;如果你用了动态Batch(设置成-1或dynamic),推理时的灵活性会增加,但性能会有损失,而且在代码里要多处理动态shape的信息获取。
我实测下来的经验是:在视频流分析场景里,固定Batch=1通常就够了,因为每一路视频流是独立推理请求,没必要把多路视频流拼成一个Batch送进去。如果确实需要提升吞吐,可以在板端做多线程并发推理,每路独立调用,而不是靠加大Batch。
固定Batch还有一个好处:显存分配、模型编译优化都更激进,推理延迟更低。所以如果业务上没有“一次必须送多张图”的需求,就不要偷懒去开动态Batch,直接固定1。
3. 部署YOLO时最容易翻车的三个坑:DVPP图像预处理、NMS后处理改写、内存拷贝开销
在Atlas 300V上部署YOLO,最难的部分不是把模型“跑起来”,而是把整个业务串起来后,性能还能满足需求。这里有三个坑,我一一踩过,每一个都值得单独拿出来说。
3.1 DVPP预处理:不是简单的OpenCV替代品
很多教程会告诉你“用DVPP做图像缩放和格式转换,比用OpenCV快得多”。这话没错,但DVPP远没有OpenCV那么“随和”。
DVPP模块对图像有严格的对齐要求。比如输入图像的宽高必须是2的倍数,某些格式还要求16字节对齐、甚至128字节对齐。你从摄像头拿到的1080p图像宽高都是1920和1080,刚好都是2的倍数,但如果你要裁剪或缩放,目标尺寸就必须再对齐。
我在一个项目里遇到过这样的问题:视频流里的ROI区域是1920x1040,不是2的倍数,DVPP直接报错。后来在代码里把宽高对齐到1920x1042,才跑通。这就是为什么昇腾的sample代码里总有那么一堆alignUp操作——这些看起来“多余”的位运算,实际上是在满足硬件的对齐约束。
int alignUp(int value, int align) { return (value + align - 1) / align * align; }另外一个和DVPP强相关的点是:DVPP处理的输出格式和模型输入格式必须匹配。DVPP输出通常是YUV420SP或者RGB24,但你的模型输入可能是FP32的NHWC张量。所以你在Host侧还得自己做一次数据排布转换,把DVPP输出的图像内存重排成模型期望的格式。这一步如果用CPU去做,性能会打折扣;如果直接用DVPP的AIPP能力,可以在NPU内部完成转换。因此,在配置AIPP时就要想清楚整条数据链路的格式走向。
3.2 YOLO原生的后处理逻辑在NPU上并不适用
GPU上跑YOLO,后处理通常写在Python里,用PyTorch张量操作就能完成NMS。但到了Atlas上,情况就变了:ACL接口拿到的输出只是裸数据,你需要自己实现坐标解析 + 置信度过滤 + NMS。
很多人第一次写这个后处理时,会直接在Python里用for-loop遍历25200个候选框做NMS。但Python的for-loop在这类场景下慢得感人,25200个框,每个都要做IoU计算,一帧图像的后处理可能耗掉几十毫秒——这个开销在GPU上不明显,但在NPU推理本身只要几毫秒的情况下,反而成了性能瓶颈。
我的做法是:把后处理尽量用C++实现,在Host侧编译成动态库,再供上层调用。NMS部分如果数据量确实大,可以考虑用std::sort按置信度降序排好,然后依次做抑制。这个方案在工程上最简单,也足够满足实时性。
另外还有一个技巧:如果YOLO模型输出端的候选框数量过多,可以在ATC转换时把模型的输出分支做裁剪,比如只保留前检测头,或者通过修改ONNX图结构把输出shape从(1, 25200, 85)压缩为(1, 25200, 5)(只保留一个类别)。类别数少的时候,这种方式效果非常明显。
3.3 内存拷贝开销:隐藏的性能杀手
ACL推理链路里,数据至少经过两次拷贝:Host输入内存 -> Device显存(为了传输入),Device显存 -> Host内存(为了取结果)。当图像尺寸从1080p缩放到640x640时,输入单帧数据约1.2MB,输出约8.5MB(25200x85x4字节),看起来不大。但如果你跑32路视频流,每路25fps,那么每秒的内存拷贝量就变成了32 x 25 x (1.2 + 8.5)MB ≈ 7.7GB。这个带宽需求在PCIe 3.0 x16(约12GB/s有效带宽)下还能承受,但如果你用的是PCIe 3.0 x4插槽或者转接卡,很快就会被带宽卡住。
因此,在选服务器主板和插卡位置时,尽量把Atlas 300V插在直连CPU的PCIe x16插槽上,不要用转接线延长,也不要和其他高带宽设备抢带宽。同时,可以考虑用ACL的异步推理接口(aclmdlExecuteAsync),让拷贝和计算重叠起来,能进一步压榨带宽利用率。
4. 从驱动到CANN再到MindX:搭建Atlas推理环境时我踩过的那几脚
很多人在部署的第一步——装环境——就被卡住了。虽然现在昇腾的Python工具链越来越完善,但版本之间的耦合关系仍然非常多,一个版本不对,后面全是坑。下面是我认为最稳妥的环境搭建顺序。
4.1 版本匹配是第一步,也是最容易忽略的一步
Atlas 300V 24G涉及到的软件栈主要分为三层:
- 固件与驱动:NPU的底层驱动,以
.run安装包形式提供 - CANN工具链:昇腾计算架构,包含ATC转换器、ACL运行时、算子库等
- 应用层工具:如MindX SDK、昇腾的Python ACL接口
torch_npu等
这三层版本必须匹配,最好都从同一个版本的发布包中获取。比如CANN 6.2版本对应配套的驱动版本是多少,这些在官方文档的“版本配套表”里都能查到。我的建议是安装前先找对应版本配套表,把驱动、固件、CANN三个包的版本号钉死,不要图新随便升级其中一个。
我踩过的一个经典坑是:驱动装的是最新版,但CANN还是旧版,结果ACL初始化时报aclInit failed,错误码根本查不到。后来把驱动回退到配套版本,问题立刻消失。这是个大概率事件,不是偶发。
4.2 固件和驱动的安装顺序与检查方法
安装时先装固件,再装驱动,最后装CANN。命令大致如下:
# 1. 安装固件 ./Ascend-hdk-*.run --full # 2. 安装驱动 ./Ascend-hdk-*.run --full # 3. 安装CANN ./Ascend-cann-toolkit_*.run --install # 4. 验证驱动状态 npu-smi infonpu-smi info命令能看到NPU的实时状态。如果输出正常,会列出芯片的型号、温度、显存占用和当前算力利用率。这一步是排查环境问题的第一站,比如驱动没装好,这里会直接报错;如果CANN版本不匹配,也会在这里出现告警。
另外提一句:Atlas 300V 24G支持在容器里使用,但需要在宿主机上装好驱动后,把/dev/davinci*设备节点和/usr/local/Ascend/driver目录挂载进容器。这个操作比较繁琐,如果不熟悉,刚开始先物理机上跑通,再考虑容器化。
4.3 一个典型的推理故障排查链路:从“模型加载失败”到“内存越界”
部署过程中最容易收到的一类报错就是aclmdlLoadFromFile失败,或者推理时崩溃。这类问题的排查链路,我总结了一个通用步骤:
- 先看
npu-smi info,确认NPU状态正常 - 检查OM模型的soc_version是否和当前芯片匹配,不匹配会直接报错
- 检查输入数据的shape、格式、内存大小是否和模型输入定义一致
- 检查输出buffer大小是否足够,YOLO的25200x85x4字节一个都不能少
- 用官方提供的
msame工具跑一次离线推理,它能快速验证OM模型本身能否正常推理出一个结果
msame是一个非常实用的工具,用法是:
./msame --model=yolov5s_16.om \ --input=test.bin \ --output=./out \ --outfmt=BIN它能帮你把“模型转换是否正确”和“业务代码是否正确”这两个问题隔离。如果msame输出正常,说明OM没问题,问题出在自己的代码里;如果msame也报错,那问题基本在模型转换阶段。
我遇到过一种比较隐蔽的内存越界:后处理代码在解析输出时,把输出缓冲区按float*强转,然后越界读取。这类问题运行时不一定会立刻崩溃,但会随机覆盖其他内存,导致一些莫名其妙的推理结果“时好时坏”。所以写后处理代码时,最好把输出大小常量定义在明显的位置,并且加一个越界断言,别嫌麻烦。
5. 选型问题:你的项目真的需要Atlas 300V 24G吗
聊完了部署细节,回到很多人最开始纠结的问题:什么时候该选Atlas 300V 24G,什么时候选GPU更合适。
从我的实际项目经验来看,以下几个场景更适合Atlas 300V:
- 视频结构化项目:多路摄像头视频流接进来,每路都要做目标检测、跟踪、属性识别。Atlas 300V的DVPP模块非常适合这种场景,甚至可以说这卡就是为这个需求造的
- 功耗和体积敏感的边缘机房:单卡功耗约72W,整机功耗低,不需要特殊的散热改造,1U/2U服务器里能塞好几张卡
- 国产化要求严格的项目:如果你所在的行业有信创要求,必须使用国产芯片方案,那昇腾就是绕不开的选择
而以下几类项目,我不建议硬上Atlas 300V:
- 需要频繁迭代模型结构、做训练和推理混合部署的项目,GPU生态的灵活度更高
- 模型里包含大量自定义算子或非标准结构,转OM时会很痛苦
- 团队完全没有昇腾经验,也没有专门的人力和时间成本去啃ACL、CANN这些文档
老实说,Atlas 300V的上手门槛比GPU要高一些,因为它的工具链、文档质量和社区讨论密度目前都不如CUDA生态成熟。但一旦过了“模型转换 + ACL编程”这道坎,它在视频推理场景下的性价比确实很有竞争力。
5.1 算力、带宽、功耗、软件生态:四个维度的判断框架
选型时我一般用四个维度做判断:
| 维度 | 说明 |
|---|---|
| 算力 | 芯片的INT8/FP16算力是否满足业务峰值 |
| 功耗 | 整卡功耗是否容易散热 |
| 资金 | 单卡价格和整体TCO是否在预算内 |
| 软件生态 | 模型是否容易转换,团队是否有能力解决踩坑问题 |
在算力方面,Atlas 300V 24G的INT8算力在百TOPS级别,FP16算力也足够跑多数检测模型,但对于动不动就上千万参数的Transformer类检测模型(如DETR),则需要仔细评估。YOLO系列问题不大,但如果你后面要跑更重的模型,最好先在文档里查一下算力表,不要凭感觉。
5.2 模型部署的隐藏成本:模型转换工时与维护人力
最后再说一个经常被忽略的隐藏成本:昇腾的模型转换和算子适配成本。
如果你只用YOLO系列,那还好,因为YOLO在昇腾社区里的适配度很高,几乎能找到现成的转换案例。但如果你的模型是某个新出的检测架构,或者内部有两三个自定义算子,那ATC转换阶段可能就要花掉你几周时间。而且就算转换成功,后续CANN版本升级时,还有可能因为算子行为变化导致结果有细微差异,需要重新做精度验证。
所以,在项目规划阶段,我建议单独给模型适配留出至少一到两周的缓冲时间,不要把所有工期都压在“模型转换很简单”这个假设上。对于大型团队,可以考虑用MindX SDK封装后的API,它能省掉部分底层适配工作,但同时也会带来一定的灵活性损失。
从我自己的体会出发,Atlas 300V 24G是一张“专才”卡,它在视频分析推理场景里是利器,但别把它当万能加速卡用。部署YOLO这件事,它确实能胜任,而且性能不错,但前提是你得接受它的思维方式和工具链,耐下心把ATC、ACL、DVPP这些概念吃透。只要过了这个坎,后面做多路视频分析项目,你会越用越顺手。