• 深入浅出PyTorch——PyTorch生态简介+模型部署


    1. 生态简介

            介绍PyTorch生态在图像、视频、文本等领域中的发展,针对某个领域选择其中有代表性的一个工具包进行详细介绍

    1.1 torchvision

            torchvision包含了在计算机视觉中常常用到的数据集,模型和图像处理的方式

    函数作用

    torchvision.datasets *

    计算机视觉中常见的数据集

    torchvision.models *

    提供一些预训练好的模型,具体

    torchvision.tramsforms*

    数据预处理方法,具体

    torchvision.io

    视频、图片和文件的 IO 操作的功能,读取、写入、编解码处理操作

    torchvision.ops

    提供许多计算机视觉的特定操作,具体

    torchvision.utils

    提供一些可视化的方法,具体

    1.2 PyTorchVideo

            提供了加速视频理解研究所需的模块化和高效的API

    1.2.1 亮点

    亮点说明
    基于 PyTorch使用 PyTorch 构建
    Model Zoo提供了包含I3D、R(2+1)D、SlowFast、X3D、MViT等SOTA模型的高质量model zoo,PyTorch Hub
    数据预处理和常见数据主流数据集和相应的数据预处理,数据增强trick
    模块化设计提供许多模块方便用户进行调用和读取
    支持多模态支持visual和audio
    移动端部署优化模型经过PyTorchVideo优化了最高达7倍的提速,并实现了第一个能实时跑在手机端的X3D模型(Android Demo APP

    1.2.2  PyTorchVideo的安装

    pip install pytorchvideo

    1.2.3 Model zoo 和 benchmark

            (1)Kinetics-400;

            (2)Something-Something V2

    1.2.4 使用 PyTorchVideo model zoo

            (1)TorchHub

            (2)PySlowFast

            (3)PyTorch Lightning

    1.3 torchtext

    1.3.1 torchtext的主要组成部分

    数据处理工具torchtext.data.functional、torchtext.data.utils
    数据集torchtext.data.datasets
    词表工具torchtext.vocab
    评测指标

    torchtext.metrics

    1.3.2 torchtext的安装

    pip install torchtext

    1.3.3 构建数据集

           Field函数

    1. tokenize = lambda x: x.split()
    2. TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True, fix_length=200)
    3. LABEL = data.Field(sequential=False, use_vocab=False)
    4. # sequential设置数据是否是顺序表示的;
    5. #​ tokenize用于设置将字符串标记为顺序实例的函数
    6. #​ lower设置是否将字符串全部转为小写;
    7. #@​ fix_length设置此字段所有实例都将填充到一个固定的长度,方便后续处理;
    8. #​ use_vocab设置是否引入Vocab object,如果为False,则需要保证之后输入field中的data都是numerical的

    1.3.4 评价指标

            BLEU (bilingual evaluation understudy) score来评价预测文本和标签文本之间的相似程度

    1. from torchtext.data.metrics import bleu_score
    2. candidate_corpus = [['My', 'full', 'pytorch', 'test'], ['Another', 'Sentence']]
    3. references_corpus = [[['My', 'full', 'pytorch', 'test'], ['Completely', 'Different']], [['No', 'Match']]]
    4. bleu_score(candidate_corpus, references_corpus)

    HuggingFace 

    1.4 transforms实战

    1.4.1 观察数据集

    1. from PIL import Image
    2. from torchvision import transforms
    3. import matplotlib.pyplot as plt
    4. %matplotlib inline
    5. # 加载原始图片
    6. img = Image.open("./lenna.jpg")
    7. print(img.size)
    8. plt.imshow(img)

    1.4.2 transforms.CenterCrop(size)

    1. # 对给定图片进行沿中心切割
    2. # 对图片沿中心放大切割,超出图片大小的部分填0
    3. img_centercrop1 = transforms.CenterCrop((500,500))(img)
    4. print(img_centercrop1.size)
    5. # 对图片沿中心缩小切割,超出期望大小的部分剔除
    6. img_centercrop2 = transforms.CenterCrop((224,224))(img)
    7. print(img_centercrop2.size)
    8. plt.subplot(1,3,1),plt.imshow(img),plt.title("Original")
    9. plt.subplot(1,3,2),plt.imshow(img_centercrop1),plt.title("500 * 500")
    10. plt.subplot(1,3,3),plt.imshow(img_centercrop2),plt.title("224 * 224")
    11. plt.show()

    1.4.3 transforms.ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)

    1. # 对图片的亮度,对比度,饱和度,色调进行改变
    2. img_CJ = transforms.ColorJitter(brightness=1,contrast=0.5,saturation=0.5,hue=0.5)(img)
    3. print(img_CJ.size)
    4. plt.imshow(img_CJ)

    1.4.4 transforms.Grayscale(num_output_channels)

    1. img_grey_c3 = transforms.Grayscale(num_output_channels=3)(img)
    2. img_grey_c1 = transforms.Grayscale(num_output_channels=1)(img)
    3. plt.subplot(1,2,1),plt.imshow(img_grey_c3),plt.title("channels=3")
    4. plt.subplot(1,2,2),plt.imshow(img_grey_c1),plt.title("channels=1")
    5. plt.show()

    1.4.5 transforms.Resize

    1. # 等比缩放
    2. img_resize = transforms.Resize(224)(img)
    3. print(img_resize.size)
    4. plt.imshow(img_resize)

    1.4.6 transforms.Scale

    1. # 等比缩放 不推荐使用此转换以支持调整大小
    2. img_scale = transforms.Scale(224)(img)
    3. print(img_scale.size)
    4. plt.imshow(img_scale)

    1.4.7 transforms.RandomCrop

    1. # 随机裁剪成指定大小
    2. # 设立随机种子
    3. import torch
    4. torch.manual_seed(31)
    5. # 随机裁剪
    6. img_randowm_crop1 = transforms.RandomCrop(224)(img)
    7. img_randowm_crop2 = transforms.RandomCrop(224)(img)
    8. print(img_randowm_crop1.size)
    9. plt.subplot(1,2,1),plt.imshow(img_randowm_crop1)
    10. plt.subplot(1,2,2),plt.imshow(img_randowm_crop2)
    11. plt.show()

    1.4.8 transforms.RandomHorizontalFlip

    1. # 随机左右旋转
    2. # 设立随机种子,可能不旋转
    3. import torch
    4. torch.manual_seed(31)
    5. img_random_H = transforms.RandomHorizontalFlip()(img)
    6. print(img_random_H.size)
    7. plt.imshow(img_random_H)

    1.4.9 transforms.RandomVerticalFlip

    1. # 随机垂直方向旋转
    2. img_random_V = transforms.RandomVerticalFlip()(img)
    3. print(img_random_V.size)
    4. plt.imshow(img_random_V)

    1.4.10 transforms.RandomResizedCrop

    1. # 随机裁剪成指定大小
    2. img_random_resizecrop = transforms.RandomResizedCrop(224,scale=(0.5,0.5))(img)
    3. print(img_random_resizecrop.size)
    4. plt.imshow(img_random_resizecrop)

    1.4.11 对图片进行组合变化 tranforms.Compose()

    1. # 对一张图片的操作可能是多种的,我们使用transforms.Compose()将他们组装起来
    2. transformer = transforms.Compose([
    3. transforms.Resize(256),
    4. transforms.transforms.RandomResizedCrop((224), scale = (0.5,1.0)),
    5. transforms.RandomVerticalFlip(),
    6. ])
    7. img_transform = transformer(img)
    8. plt.imshow(img_transform)

    2. 模型部署

            (1)使用ONNX进行部署并推理;

            (2)将模型部署在手机端、开发板,嵌入式设备;

            (3)模型部署pipeline

    2.1 ONNX和ONNX Runtime简介

    2.1.1 ONNX简介

            ONNX( Open Neural Network Exchange) 是 Facebook (现Meta) 和微软在2017年共同发布的,用于标准描述计算图的一种格式。

            ONNX官网

            ONNX GitHub

    2.1.2 ONNX Runtime简介

            ONNX Runtime 是由微软维护的一个跨平台机器学习推理加速器,它直接对接ONNX,可以直接读取.onnx文件并实现推理,不需要再把 .onnx 格式的文件转换成其他格式的文件。

            ONNX Runtime官网

            ONNX Runtime GitHub

    2.1.3 ONNX和ONNX Runtime的安装

    1. # 激活虚拟环境
    2. conda activate env_name # env_name换成环境名称
    3. # 安装onnx
    4. pip install onnx
    5. # 安装onnx runtime
    6. pip install onnxruntime # 使用CPU进行推理
    7. # pip install onnxruntime-gpu # 使用GPU进行推理

    2.2 模型导出为ONNX

    2.2.1 模型转换为ONNX格式

    1. import torch.onnx
    2. # 转换的onnx格式的名称,文件后缀需为.onnx
    3. onnx_file_name = "xxxxxx.onnx"
    4. # 我们需要转换的模型,将torch_model设置为自己的模型
    5. model = torch_model
    6. # 加载权重,将model.pth转换为自己的模型权重
    7. # 如果模型的权重是使用多卡训练出来,我们需要去除权重中多的module. 具体操作可以见5.4节
    8. model = model.load_state_dict(torch.load("model.pth"))
    9. # 导出模型前,必须调用model.eval()或者model.train(False)
    10. model.eval()
    11. # dummy_input就是一个输入的实例,仅提供输入shape、type等信息
    12. batch_size = 1 # 随机的取值,当设置dynamic_axes后影响不大
    13. dummy_input = torch.randn(batch_size, 1, 224, 224, requires_grad=True)
    14. # 这组输入对应的模型输出
    15. output = model(dummy_input)
    16. # 导出模型
    17. torch.onnx.export(model, # 模型的名称
    18. dummy_input, # 一组实例化输入
    19. onnx_file_name, # 文件保存路径/名称
    20. export_params=True, # 如果指定为True或默认, 参数也会被导出. 如果你要导出一个没训练过的就设为 False.
    21. opset_version=10, # ONNX 算子集的版本,当前已更新到15
    22. do_constant_folding=True, # 是否执行常量折叠优化
    23. input_names = ['input'], # 输入模型的张量的名称
    24. output_names = ['output'], # 输出模型的张量的名称
    25. # dynamic_axes将batch_size的维度指定为动态,
    26. # 后续进行推理的数据可以与导出的dummy_input的batch_size不同
    27. dynamic_axes={'input' : {0 : 'batch_size'},
    28. 'output' : {0 : 'batch_size'}})

    2.2.2 ONNX模型的检验

    1. import onnx
    2. # 我们可以使用异常处理的方法进行检验
    3. try:
    4. # 当我们的模型不可用时,将会报出异常
    5. onnx.checker.check_model(self.onnx_model)
    6. except onnx.checker.ValidationError as e:
    7. print("The model is invalid: %s"%e)
    8. else:
    9. # 模型可用时,将不会报出异常,并会输出“The model is valid!”
    10. print("The model is valid!")

    2.2.3 ONNX可视化

            Netron

    2.3 使用ONNX Runtime进行推理

    1. # 导入onnxruntime
    2. import onnxruntime
    3. # 需要进行推理的onnx模型文件名称
    4. onnx_file_name = "xxxxxx.onnx"
    5. # onnxruntime.InferenceSession用于获取一个 ONNX Runtime 推理器
    6. ort_session = onnxruntime.InferenceSession(onnx_file_name)
    7. # 构建字典的输入数据,字典的key需要与我们构建onnx模型时的input_names相同
    8. # 输入的input_img 也需要改变为ndarray格式
    9. ort_inputs = {'input': input_img}
    10. # 我们更建议使用下面这种方法,因为避免了手动输入key
    11. # ort_inputs = {ort_session.get_inputs()[0].name:input_img}
    12. # run是进行模型的推理,第一个参数为输出张量名的列表,一般情况可以设置为None
    13. # 第二个参数为构建的输入值的字典
    14. # 由于返回的结果被列表嵌套,因此我们需要进行[0]的索引
    15. ort_output = ort_session.run(None,ort_inputs)[0]
    16. # output = {ort_session.get_outputs()[0].name}
    17. # ort_output = ort_session.run([output], ort_inputs)[0]

    2.4 代码实战

    2.4.1 定义超分辨模型

    1. # 导入相关包
    2. import io
    3. import numpy as np
    4. from torch import nn
    5. import torch.utils.model_zoo as model_zoo
    6. import torch.onnx
    7. import torch.nn as nn
    8. import torch.nn.init as init
    9. # 定义超分辨网络
    10. class SuperResolutionNet(nn.Module):
    11. def __init__(self, upscale_factor, inplace=False):
    12. super(SuperResolutionNet, self).__init__()
    13. self.relu = nn.ReLU(inplace=inplace)
    14. self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
    15. self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
    16. self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
    17. self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
    18. self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
    19. self._initialize_weights()
    20. def forward(self, x):
    21. x = self.relu(self.conv1(x))
    22. x = self.relu(self.conv2(x))
    23. x = self.relu(self.conv3(x))
    24. x = self.pixel_shuffle(self.conv4(x))
    25. return x
    26. # 模型初始化
    27. def _initialize_weights(self):
    28. init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
    29. init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
    30. init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
    31. init.orthogonal_(self.conv4.weight)
    32. # 实例化模型
    33. torch_model = SuperResolutionNet(upscale_factor=3)

    2.4.2 模型导出为ONNX格式

    1. model_url = 'https://s3.amazonaws.com/pytorch/test_data/export/superres_epoch100-44c6958e.pth'
    2. batch_size = 1 # just a random number
    3. # 加载预训练得到权重
    4. map_location = lambda storage, loc: storage
    5. if torch.cuda.is_available():
    6. map_location = None
    7. torch_model.load_state_dict(model_zoo.load_url(model_url, map_location=map_location))
    8. # 将模型设置为推理模式
    9. torch_model.eval()
    10. # Input to the model
    11. x = torch.randn(batch_size, 1, 224, 224, requires_grad=True)
    12. torch_out = torch_model(x)
    13. # 导出模型
    14. torch.onnx.export(torch_model, # model being run
    15. x, # model input (or a tuple for multiple inputs)
    16. "super_resolution.onnx", # where to save the model (can be a file or file-like object)
    17. export_params=True, # store the trained parameter weights inside the model file
    18. opset_version=10, # the ONNX version to export the model to
    19. do_constant_folding=True, # whether to execute constant folding for optimization
    20. input_names = ['input'], # the model's input names
    21. output_names = ['output'], # the model's output names
    22. # variable length axes
    23. dynamic_axes={'input' : {0 : 'batch_size'},
    24. 'output' : {0 : 'batch_size'}})

    2.4.3  检验ONNX模型

    1. import onnx
    2. # 我们可以使用异常处理的方法进行检验
    3. try:
    4. # 当我们的模型不可用时,将会报出异常
    5. onnx.checker.check_model("super_resolution.onnx")
    6. except onnx.checker.ValidationError as e:
    7. print("The model is invalid: %s"%e)
    8. else:
    9. # 模型可用时,将不会报出异常,并会输出“The model is valid!”
    10. print("The model is valid!")

    2.4.4  使用ONNX Runtime进行推理

    1. import onnxruntime
    2. ort_session = onnxruntime.InferenceSession("super_resolution.onnx")
    3. # 将张量转化为ndarray格式
    4. def to_numpy(tensor):
    5. return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()
    6. # 构建输入的字典和计算输出结果
    7. ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(x)}
    8. ort_outs = ort_session.run(None, ort_inputs)
    9. # 比较使用PyTorch和ONNX Runtime得出的精度
    10. np.testing.assert_allclose(to_numpy(torch_out), ort_outs[0], rtol=1e-03, atol=1e-05)
    11. print("Exported model has been tested with ONNXRuntime, and the result looks good!")

    2.4.5 进行实际预测并可视化

    1. from PIL import Image
    2. import torchvision.transforms as transforms
    3. # 读取图片
    4. img = Image.open("/cat_224x224.jpg")
    5. # 对图片进行resize操作
    6. resize = transforms.Resize([224, 224])
    7. img = resize(img)
    8. img_ycbcr = img.convert('YCbCr')
    9. img_y, img_cb, img_cr = img_ycbcr.split()
    10. to_tensor = transforms.ToTensor()
    11. img_y = to_tensor(img_y)
    12. img_y.unsqueeze_(0)
    13. # 构建输入的字典并将value转换位array格式
    14. ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(img_y)}
    15. ort_outs = ort_session.run(None, ort_inputs)
    16. img_out_y = ort_outs[0]
    17. img_out_y = Image.fromarray(np.uint8((img_out_y[0] * 255.0).clip(0, 255)[0]), mode='L')
    18. # 保存最后得到的图片
    19. final_img = Image.merge(
    20. "YCbCr", [
    21. img_out_y,
    22. img_cb.resize(img_out_y.size, Image.BICUBIC),
    23. img_cr.resize(img_out_y.size, Image.BICUBIC),
    24. ]).convert("RGB")
    25. final_img.save("/cat_superres_with_ort.jpg")

    参考:PyTorch生态简介

              PyTorch的模型部署

     

  • 相关阅读:
    B. Two-gram
    安卓FirstStageMount阶段解析【连载】(一)创建设备Create
    免费录音转文字的软件有哪些?不知道的小伙伴快来码住
    Mybatis-Plus的CURD实操
    TeamTalk梳理概括
    linux模块使用外部符号
    ☕Java 面向对象进阶内容
    用python画计算器图形界面
    OpenGL ES入门教程(一)编写第一个OpenGL程序
    SpringMvc如何向Session域中设置数据
  • 原文地址:https://blog.csdn.net/qq_51167531/article/details/128043763