ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenCV DNN 实战教程:PyTorch 图像分类模型的 ONNX 转换与 C++ 推理完整流程

OpenCV DNN 实战教程:PyTorch 图像分类模型的 ONNX 转换与 C++ 推理完整流程 OpenCV DNN 实战教程PyTorch 图像分类模型的 ONNX 转换与 C 推理完整流程【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv本文以 OpenCV 官方教程 PyTorch 分类模型转换 C 实践 为主体完整讲解“PyTorch 分类模型 → ONNX → cv::dnn 网络 → C 推理”的全流程如何用torch.onnx.export把 torchvision 中的 ResNet-50 等 17 种分类模型导出为 ONNX再用cv::dnn::readNetFromONNX加载并推理。读完后你将能够独立搭建模型转换环境、复用仓库自带的转换脚本批量导出模型、理解 OpenCV 预处理参数mean/scale/std/crop与 PyTorch 原始预处理顺序的对应关系并用 classification.cpp 示例程序对任意 ONNX 分类模型跑通推理。1. 转换流水线概览教程给出的核心链路只有三步PyTorch 模型 → ONNX使用 PyTorch 内置的torch.onnx.export。ONNX 的目标是实现神经网络在不同框架间的互换性因此它是 PyTorch 模型进入 OpenCV 的“中间格式”ONNX → cv::dnn::Net将.onnx文件交给cv::dnn::readNetFromONNX或通用的cv::dnn::readNet解析为内部计算图推理通过setInput/forward完成前向计算并解析输出。整个教程以ResNet-50为例走通上述链路。2. 环境准备与依赖安装教程要求使用Python 3.7的虚拟环境virtualenv -p /usr/bin/python3.7 env_dir_path source env_dir_path/bin/activate如果要用 OpenCV-Python即cv2.dnn从源码构建需按 OpenCV 官方构建文档操作见教程中的 setup 章节指引。依赖清单位于 requirements.txt激活虚拟环境后执行pip install -r requirements.txt该文件声明的版本基线摘自文件内容依赖最低版本用途onnx1.7.0ONNX 工具链numpy1.19.1数值计算torch/torchvision1.5.1 / 0.6.1模型实例化与 ONNX 导出tensorflow2.1.0同目录下的 TF 模型转换脚本共用paddlepaddle系列2.0.0PaddlePaddle 模型转换脚本共用说明该文件是转换工具目录dnn_conversion/的公共依赖PyTorch / TensorFlow / PaddlePaddle 三条转换链路共用。如果只做 PyTorch 分类模型转换教程明确提示可以先编辑该文件剔除 tensorflow、paddle 相关条目opencv-python可视情况保留只装onnx、numpy、torch、torchvision。3. 模型转换流水线3.1 最小可运行示例ResNet-50 导出代码位于 samples/dnn/dnn_model_runner/dnn_conversion/pytorch/classification/py_to_py_resnet50_onnx.py从samples/dnn目录执行python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_resnet50_onnx它只做两件事——实例化模型、导出 ONNX# initialize PyTorch ResNet-50 model original_model models.resnet50(pretrainedTrue) # get the path to the converted into ONNX PyTorch model full_model_path get_pytorch_onnx_model(original_model) print(PyTorch ResNet-50 model was successfully converted: , full_model_path)核心转换逻辑get_pytorch_onnx_model(...)完全基于torch.onnx.export# define the directory for further converted model save onnx_model_path models # define the name of further converted model onnx_model_name resnet50.onnx # create directory for further converted model os.makedirs(onnx_model_path, exist_okTrue) # get full path to the converted model full_model_path os.path.join(onnx_model_path, onnx_model_name) # generate model input generated_input Variable( torch.randn(1, 3, 224, 224) ) # model export into ONNX format torch.onnx.export( original_model, generated_input, full_model_path, verboseTrue, input_names[input], output_names[output], opset_version11 )各参数含义generated_input构造一个1x3x224x224的随机张量作为“轨迹输入”导出器沿前向轨迹固化图结构同时确定输入形状batch1、三通道、224×224input_names/output_names把逻辑输入/输出命名成input/output方便后续setInput按名字寻址opset_version11指定 ONNX 算子集版本决定导出图中允许使用的算子verboseTrue打印导出过程信息便于排查不支持的算子。成功执行后的输出PyTorch ResNet-50 model was successfully converted: models/resnet50.onnx3.2 通用转换脚本17 种模型一键导出py_to_py_cls.py 把上述步骤泛化为命令行工具支持 torchvision 中的整套分类网络alexnetvgg11 / vgg13 / vgg16 / vgg19resnet18 / resnet34 / resnet50 / resnet101 / resnet152squeezenet1_0 / squeezenet1_1resnext50_32x4d / resnext101_32x8dwide_resnet50_2 / wide_resnet101_2转换不含与 PyTorch 原模型的精度评估只需python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_cls --model_name pytorch_cls_model_name --evaluate False以 ResNet-50 为例python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_cls --model_name resnet50 --evaluate False从源码看--model_name通过 utils.py 中的create_extended_parser做白名单校验传错名字会直接报错并打印可选列表--evaluate默认是 True置为 False 时只走“导出 用 OpenCV 测试推理”的链路。转换产物保存位置由 test_config.py 的CommonConfig定义dataclass class CommonConfig: output_data_root_dir: str dnn_model_runner/dnn_conversion即模型默认落在dnn_model_runner/dnn_conversion之下。结合 utils.py 中的路径拼接逻辑MODEL_PATH_ROOT output_data_root_dir /{库名}/models库名取pytorch可以推断通用脚本实际把转换结果写到dnn_model_runner/dnn_conversion/pytorch/models/model_name.onnx而 3.1 节的最小示例脚本是相对工作目录直接写入models/resnet50.onnx。值得一提的是通用脚本内部复用的PyTorchModelPreparerpytorch_model.py与最小示例完全同构同样的torch.randn(batch, 3, height, width)轨迹输入、同样的opset_version11导出完成后还会立即调用cv2.dnn.readNetFromONNX回读一次等于在 Python 侧先做了一次加载自检再进入与 PyTorch 原模型的对比评测PyTorchModelProcessorvsPyTorchDnnModelProcessor。4. C 推理流水线example_dnn_classification4.1 构建与运行转换得到的models/resnet50.onnx即可交给 OpenCV C API。推理示例即 samples/dnn/classification.cpp构建时把BUILD_EXAMPLES置为ON编译后得到可执行文件example_dnn_classification。教程使用 samples/data/squirrel_cls.jpg 这张松鼠照片对应 ImageNet ILSVRC2012 类别 335“fox squirrel, eastern fox squirrel, Sciurus niger”并需要类别名文件 samples/data/dnn/classification_classes_ILSVRC2012.txt包含全部 1000 个 ImageNet 类名做标签解码。从构建目录samples/build执行./dnn/example_dnn_classification --model../dnn/models/resnet50.onnx --input../data/squirrel_cls.jpg --width224 --height224 --rgbtrue --scale0.003921569 --mean123.675 116.28 103.53 --std0.229 0.224 0.225 --croptrue --initial_width256 --initial_height256 --classes../data/dnn/classification_classes_ILSVRC2012.txt4.2 参数逐项解读结合 common.hpp 中genPreprocArguments生成的参数定义各参数含义与默认值如下参数默认值含义--model空ONNX 模型文件路径必填否则CV_Assert失败--input空输入图像/视频不给则打开默认摄像头--width/--height-1blobFromImage的目标尺寸-1 表示不 resize--scale1.0像素值缩放系数--mean无减去的均值BGR 顺序、空格分隔--std无除的标准差--rgbfalse模型是否吃 RGB内部把 BGR 交换为 RGB--cropfalse是否中心裁剪到目标尺寸--labels无类别名文本文件路径--backend/--targetdefault/cpu计算后端openvino、opencv、cuda、webnn…与目标设备opencl、vulkan、cuda_fp16…由 common.hpp 中的映射表解析注意 findFile / findModel 的寻址规则相对路径找不到时会依次尝试环境变量OPENCV_SAMPLES_DATA_PATH指向opencv/samples/data、OPENCV_DNN_TEST_DATA_PATH、OPENCV_DOWNLOAD_CACHE_DIR下的同名文件。教程示例中的../data/squirrel_cls.jpg正是利用“相对构建目录 数据根目录”的方式定位素材。4.3 源码关键步骤解析classification.cpp的推理主循环L148-L259可拆成四步与教程逐一对应1加载模型并初始化网络教程展示的是通用写法Net net readNet(model, config, framework);。当前仓库源码更直接//! [Read and initialize network] EngineType engine ENGINE_OPENCV; Net net readNetFromONNX(model, engine); net.setPreferableBackend(getBackendID(backend)); net.setPreferableTarget(getTargetID(target)); net.setProfilingMode(DNN_PROFILE_SUMMARY); //! [Read and initialize network]readNetFromONNX是readNet针对 ONNX 容器的专门入口--model指向的resnet50.onnx在此被解析为 OpenCV 内部的cv::dnn::Net同时通过setProfilingMode(DNN_PROFILE_SUMMARY)打开性能摘要每帧末尾net.printPerfProfile()会打印各层耗时。2输入预处理blobFromImage 除以 stdblobFromImage(frame, blob, scale, Size(inpWidth, inpHeight), mean, swapRB, crop); // Check std values. if (std.val[0] ! 0.0 std.val[1] ! 0.0 std.val[2] ! 0.0) { // Divide blob by std. divide(blob, std, blob); }这里是“复现 PyTorch 预处理”的关键。cv::dnn::blobFromImage的执行顺序是先减 mean、再乘 scale且没有内置“除以 std”的步骤所以示例把除法放到外面。而 PyTorch ResNet 的标准预处理顺序是img / 255.0 img - [0.485, 0.456, 0.406] img / [0.229, 0.224, 0.225]两套顺序不同参数就需要“换一种写法”来对齐把 mean 写成[0.485, 0.456, 0.406] × 255.0即123.675 116.28 103.53255 尺度scale 写成1/255 ≈ 0.003921569std 保持0.229 0.224 0.225。这样blobFromImage内的“减 123.675 再除 255”恰好等价于“先除 255 再减 0.485”再手动除以 std三步结果与 PyTorch 完全一致。此外--croptrue配合教程给出的 resize 参数先把短边放大到 256 再中心裁剪 224复现了 PyTorch Hub 的Resize(256) CenterCrop(224)--rgbtrue负责 BGR→RGB 交换。仓库里 default_preprocess_config.py 中的pytorch_resize_input_blob配置mean/scale/std/crop/rgb/256正是同一组参数在 Python 测试管线中的镜像。作为对照models.yml 里resnet条目给出另一种等价写法scale: 1.0、std: [58.395, 57.12, 57.375]即0.229×255等二者数学上等价只是把 255 的缩放并入了 std。3前向传播net.setInput(blob); Mat prob net.forward();prob是 1×1000 的分数矩阵ONNX 图输出名output对应的节点。4后处理取最高分类别教程展示minMaxLoc取 argmaxPoint classIdPoint; double confidence; minMaxLoc(prob.reshape(1, 1), 0, confidence, 0, classIdPoint); int classId classIdPoint.x;当前仓库实现改为对分数排序取Top-5并逐行绘制到画面上L236-L259标签从--labels文件按classId下标取出同时用TickMeter统计单次推理耗时输出Inference time: xx ms。程序在 GUI 窗口中循环显示按q或ESC退出对输入为图片列表--imglist的场景每张图停留 1 秒自动切换。4.4 预期结果对squirrel_cls.jpg运行后预测类别 ID 为335对应标签fox squirrel, eastern fox squirrel, Sciurus niger与教程给出的输出截图一致见文首第二张图。5. 小结与延伸阅读整条链路可以概括为一句话用torch.onnx.export固定“图结构 输入形状 输入输出命名”用cv::dnn::readNetFromONNX换运行时再用“mean×255 / scale1/255 / 显式除 std / 256→224 中心裁剪 / RGB”这组参数把 OpenCV 侧预处理对齐到 PyTorch 的官方顺序。仓库中与本主题直接相关的入口转换脚本PyTorch 分类py_to_py_resnet50_onnx.py、py_to_py_cls.py、py_to_py_resnet50.pyPython 侧端到端对照同一张预处理后的图分别喂给 OpenCV 与 PyTorch打印两边的类别与置信度C 推理示例classification.cpp参数定义见 common.hpp模型参数注册表models.ymlresnet/squeezenet等分类条目素材与标签squirrel_cls.jpg、classification_classes_ILSVRC2012.txt原教程文档pytorch_cls_model_conversion_c_tutorial.md同目录另有 PyTorch 分类模型 Python 版教程 与 TensorFlow 对应教程可作为姊妹篇参考适用前提提醒转换脚本依赖较新的 torch/onnx 版本requirements 基线为 torch1.5.1、onnx1.7.0torch.autograd.Variable的用法在新版 PyTorch 中已被torch.no_grad()下直接传张量取代但导出行为不变C 侧则要求 OpenCV 启用 ONNX 解析器DNN 模块默认支持 ONNX示例程序需BUILD_EXAMPLESON参与构建。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表