PyTorch 分类模型的转换并使用 OpenCV Python 启动

目标

在本教程中,您将学习如何:

  • 将 PyTorch 分类模型转换为 ONNX 格式
  • 使用 OpenCV Python API 运行转换后的 PyTorch 模型
  • 获取 PyTorch 和 OpenCV DNN 模型的评估。

我们将以 ResNet-50 架构为例来探讨上述几点。

介绍

让我们简要回顾一下使用 OpenCV API 进行 PyTorch 模型转换的管道中涉及的关键概念。将 PyTorch 模型转换为 cv.dnn.Net 的第一步是将模型转换为 ONNX 格式。ONNX 旨在实现神经网络在各种框架之间的可互换性。PyTorch 中有一个用于 ONNX 转换的内置函数:torch.onnx.export。此外,将获得的模型传递到 cv.dnn.readNetFromONNX 中。.onnx

要求

为了能够试验以下代码,您需要安装一组库。为此,我们将使用 python3.7+ 的虚拟环境:

virtualenv -p /usr/bin/python3.7 <env_dir_path>
源<env_dir_path>/bin/activate

对于从源代码构建 OpenCV-Python,请遵循 OpenCV 简介中的相应说明。

在开始安装库之前,可以自定义要求 .txt,排除或包括(例如)某些依赖项。以下行将需求安装启动到先前激活的虚拟环境中:opencv-python

pip 安装 -r 要求.txt

实践

在这一部分中,我们将介绍以下几点:

  1. 创建分类模型转换管道并提供推理
  2. 评估和测试分类模型

如果只想运行评估或测试模型管道,则可以跳过“模型转换管道”部分。

模型转换管道

本子章中的代码位于模块中,可以使用以下行执行:dnn_model_runner

python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_resnet50

以下代码包含下面列出的步骤的说明:

  1. 实例化 PyTorch 模型
  2. 将 PyTorch 模型转换为.onnx
  3. 使用 OpenCV API 读取传输的网络
  4. 准备输入数据
  5. 提供推理
# 初始化 PyTorch ResNet-50 模型
original_model = models.resnet50(预训练=True)
# 获取转换为 ONNX PyTorch 模型的路径
full_model_path = get_pytorch_onnx_model(original_model)
# 使用 OpenCV API 读取转换后的 .onnx 模型
opencv_net = cv2.dnn.readNetFromONNX (full_model_path)
print(“OpenCV 模型已成功读取。图层 ID:\n“, opencv_net.getLayerNames())
# 获取预处理后的图片
input_img = get_preprocessed_img(“../数据/squirrel_cls.jpg“)
# 获取 ImageNet 标签
imagenet_labels = get_imagenet_labels(“../data/dnn/classification_classes_ILSVRC2012.txt“)
# 获取 OpenCV DNN 预测
get_opencv_dnn_prediction(opencv_net、input_img、imagenet_labels)
# 获取原始 PyTorch ResNet50 预测
get_pytorch_dnn_prediction(original_model、input_img、imagenet_labels)

为了提供模型推理,我们将使用下面与 ImageNet 类 ID 335 相对应的松鼠照片(在 CC0 许可下):

狐狸松鼠、东方狐狸松鼠、黑狐狸

squirrel_cls.jpg

分类模型输入图像

对于所获得的预测的标签解码,我们还需要文件,其中包含 ImageNet 类的完整列表。imagenet_classes.txt

让我们以预训练的 PyTorch ResNet-50 为例,更深入地了解每个步骤:

  • 实例化 PyTorch ResNet-50 模型:
# 初始化 PyTorch ResNet-50 模型
original_model = models.resnet50(预训练=True)
  • 将 PyTorch 模型转换为 ONNX:
# 定义进一步转换后的模型保存目录
onnx_model_path = “模型”
# 定义进一步转换的模型名称
onnx_model_name = “resnet50.onnx”
# 为进一步转换的模型创建目录
os.makedirs(onnx_model_path, exist_ok=True)
# 获取转换后模型的完整路径
full_model_path = os.path.join(onnx_model_path, onnx_model_name)
# 生成模型输入
generated_input = 变量(
火炬.randn(1, 3, 224, 224)
)
# 模型导出为 ONNX 格式
torch.onnx.export(
original_model,
generated_input,
full_model_path,
verbose=真,
input_names=[“输入”],
output_names=[“输出”],
opset_version=11
)

上述代码执行成功后,我们将得到.models/resnet50.onnx

  • 使用 cv.dnn.readNetFromONNX 读取传输的网络,将上一步 ONNX 模型中获取的网络传递到其中:
# 使用 OpenCV API 读取转换后的 .onnx 模型
opencv_net = cv2.dnn.readNetFromONNX (full_model_path)
  • 准备输入数据:
# 读取镜像
input_img = cv2.imread(img_path, cv2.IMREAD_COLOR)
input_img = input_img.astype(np.float32)
input_img = cv2.resize(input_img, (256, 256))
# 定义预处理参数
均值 = np.array([0.485, 0.456, 0.406]) * 255.0
比例 = 1 / 255.0
标准 = [0.229, 0.224, 0.225]
# 准备输入 blob 以适应模型输入:
# 1.减去平均值
# 2.缩放以设置从 0 到 1 的像素值
input_blob = cv2.dnn.blobFromImage(
image=input_img,
scalefactor=scale,
size=(224, 224), # img 目标大小
mean=平均值,
swapRB=True, # BGR -> RGB
crop=True # 居中裁剪
)
# 3.除以 std
input_blob[0] /= np.asarray(std, dtype=np.float32).reshape(3, 1, 1)

在此步骤中,我们读取图像并使用 cv.dnn.blobFromImage 函数准备模型输入,该函数返回 4 维 blob。应该注意的是,首先在 cv.dnn.blobFromImage 中减去平均值,然后才将像素值乘以小数位数。因此,乘以再现原始图像预处理顺序:mean255.0

图像 /= 255.0
图片 -= [0.485, 0.456, 0.406]
img /= [0.229, 0.224, 0.225]
# 设置 OpenCV DNN 输入
opencv_net.setInput(preproc_img)
# OpenCV DNN 推理
out = opencv_net.forward()
print(“OpenCV DNN 预测:\n”)
print(“* 形状: ”, out.shape)
# 获取预测的类 ID
imagenet_class_id = np.argmax(输出)
# 获得信心
置信度 = out[0][imagenet_class_id]
print(“* 类 ID: {}, label: {}”.format(imagenet_class_id, imagenet_labels[imagenet_class_id]))
print(“* 置信度:{:.4f}”.format(置信度))

在上述代码执行后,我们将得到以下输出:

OpenCV DNN 预测:
* 形状:(1,1000)
*类ID:335,标签:狐狸松鼠、东方狐狸松鼠、黑狐狸
* 置信度:14.8308
  • PyTorch ResNet-50 模型推理:
original_net.eval()
preproc_img = 火炬。浮点张量(preproc_img)
# 推理
输出 = original_net(preproc_img)
print(“\nPyTorch 模型预测:\n”)
print(“* 形状: ”, out.shape)
# 获取预测的类 ID
imagenet_class_id = torch.argmax(out, axis=1).item()
print(“* 类 ID: {}, label: {}”.format(imagenet_class_id, imagenet_labels[imagenet_class_id]))
# 获得信心
置信度 = out[0][imagenet_class_id]
print(“* 置信度:{:.4f}”.format(confidence.item()))

上述代码启动后,我们将得到以下输出:

PyTorch 模型预测:
* 形状:火炬。尺寸([1, 1000])
*类ID:335,标签:狐狸松鼠、东方狐狸松鼠、黑狐狸
* 置信度:14.8308

原始 ResNet-50 模型和 cv.dnn.Net 的推理结果是相等的。对于模型的扩展评估,我们可以使用该模块。本模块部分将在下一小章中介绍。py_to_py_clsdnn_model_runner

模型评估

建议的模块允许在 ImageNet 数据集上运行完整的评估管道,并测试以下 PyTorch 分类模型的执行:samples/dnndnn_model_runner

  • 亚历克斯网
  • VGG11型
  • VGG13型
  • VGG16型
  • VGG19型
  • resnet18
  • resnet34
  • resnet50的
  • resnet101的
  • resnet152
  • squeezenet1_0
  • squeezenet1_1
  • resnext50_32x4d
  • resnext101_32x8d
  • wide_resnet50_2
  • wide_resnet101_2

此列表还可以通过进一步适当的评估管道配置进行扩展。

评估模式

以下行表示模块在评估模式下的运行:

python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_cls --model_name <pytorch_cls_model_name>

从列表中选择的分类模型将被读入 OpenCV cv.dnn.Net 对象。PyTorch 和 OpenCV 模型的评估结果(精度、推理时间、L1)将写入日志文件。推理时间值也将在图表中描述,以概括获得的模型信息。

必要的评估配置在test_config.py中定义,并可根据数据位置的实际路径进行修改:

@dataclass
类 TestClsConfig:
batch_size:int = 50
frame_size:int = 224
img_root_dir:str = “./ILSVRC2012_img_val”
# image-class 匹配的位置
img_cls_file:str = “./val.txt”
bgr_to_rgb:bool = True

若要启动对 PyTorch ResNet-50 的评估,请运行以下行:

python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_cls --model_name resnet50

脚本启动后,将在以下位置生成包含评估数据的日志文件:dnn_model_runner/dnn_conversion/logs

成功获取模型 PyTorch resnet50 并转换为 OpenCV DNN resnet50
===== 使用以下参数运行模型评估:
* val 数据位置:./ILSVRC2012_img_val
* 日志文件位置:dnn_model_runner/dnn_conversion/logs/PyTorch_resnet50_log.txt
测试模式

以下行表示模块在测试模式下的运行,即它提供了模型推理的步骤:

python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_cls --model_name <pytorch_cls_model_name> --test True --default_img_preprocess <True/False> --evaluate False

此处的 key 定义是要使用某些特定值参数化模型测试过程,还是使用默认值,例如 、 或 。default_img_preprocessscalemeanstd

测试配置在test_config.py类中表示:TestClsModuleConfig

@dataclass
类 TestClsModuleConfig:
cls_test_data_dir:str = “../数据”
test_module_name: str = “classification”
test_module_path:str = “classification.py”
input_img:str = os.path.join(cls_test_data_dir, “squirrel_cls.jpg”)
型号: str = “”
frame_height:str = str(TestClsConfig.frame_size)
frame_width:str = str(TestClsConfig.frame_size)
比例:str = “1.0”
mean: List[str] = field(default_factory=lambda: [“0.0”, “0.0”, “0.0”])
标准:List[str] = 字段(default_factory=list)
裁剪:str = “False”
rgb:str = “真”
rsz_height:str = “”
rsz_width:str = “”
类:str = os.path.join(cls_test_data_dir, “dnn”, “classification_classes_ILSVRC2012.txt”)

默认图像预处理选项在 default_preprocess_config.py 中定义。例如:

BASE_IMG_SCALE_FACTOR = 1 / 255.0
PYTORCH_RSZ_HEIGHT = 256
PYTORCH_RSZ_WIDTH = 256
pytorch_resize_input_blob = {
“平均值”: [“123.675”, “116.28”, “103.53”],
“比例”:str(BASE_IMG_SCALE_FACTOR),
“标准”: [“0.229”, “0.224”, “0.225”],
“crop”: “真”,
“rgb”: “真”,
“rsz_height”:str(PYTORCH_RSZ_HEIGHT),
“rsz_width”:str(PYTORCH_RSZ_WIDTH)
}

模型测试的基础在 samples/dnn/classification.py 中表示。 可以使用提供的转换模型和填充的 cv.dnn.blobFromImage 参数自主执行。classification.py--input

要从头开始重现“模型转换管道”中描述的 OpenCV 步骤,请执行以下行:dnn_model_runner

python -m dnn_model_runner.dnn_conversion.pytorch.classification.py_to_py_cls --model_name resnet50 --test True --default_img_preprocess True --evaluate False

网络预测显示在输出窗口的左上角:

pytorch_resnet50_opencv_test_res.jpg

ResNet50 OpenCV 推理输出

   在线教程

有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

请添加图片描述

人工智能书籍

第一阶段:零基础入门(3-6个月)

新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。

第二阶段:基础进阶(3-6个月)

熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。

第三阶段:工作应用

这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。

 有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在这里插入图片描述

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值