本文为稀土技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

作者简介:秃头小苏,致力于用最通俗的言语描述问题

专栏引荐:深度学习网络原理与实战

近期方针:写好专栏的每一篇文章

支持小苏:点赞、保藏⭐、留言

深度学习模型布置篇——从0布置深度学习分类模型(一)

写在前面

Hello,咱们好,我是小苏

在过往的博客中,我为咱们介绍过物体分类、方针检测、言语分割、缺陷检测等等深度学习模型,感兴趣的能够点击☞☞☞进入我的主页了解详情。今日预备来给咱们介绍介绍咱们如何来布置咱们练习的深度学习模型,当然啦,这篇布置的是分类模型,所以期望咱们对物体分类有必定的了解,不熟悉的能够先看一下下面几篇博客:

  • 运用pytorch自己构建网络模型实战
  • 基于pytorch建立AlexNet神经网络用于花类辨认
  • 基于pytorch建立ResNet神经网络用于花类辨认

预备好了吗,让咱们一起从0布置深度学习分类模型叭~~~

模型布置概述

首要来谈谈到底什么是模型布置呢?其实模型布置便是将咱们练习的深度学习模型应用到出产环境中。这儿咱们可能就有一个问题了,咱们之前练习的分类网络难道不能用于出产环境嘛,为什么还要布置模型呢?在我看来,其实咱们之前练习的模型理论上是能够用的,可是一方面在出产环境中往往对模型的速度提出更高的要求,直接运用练习好的模型往往速度慢,难以满足实际需求;另一方面咱们练习模型时往往运用不同的结构,如Pytorch、TensorFlow、Caffe等等,这些结构需求特定的环境依靠,装备杂乱,往往不适合在实际出产环境中装置。

总之,假如咱们直接将咱们练习的模型应用于出产环境,会存在环境装备杂乱、推理速度较慢的问题 ,因而咱们需求对咱们的模型进行布置。

下图展现了咱们从数据收集到终究应用于出产环境的进程,首要咱们会收集数据,然后挑选合适的模型对咱们的数据进行练习,并进行测验评价。其实到这儿都是咱们之前把握的常识,也便是练习咱们的模型。当咱们练习好咱们的模型后,会对咱们的模型进行布置,使其能够应用于出产环境傍边。

深度学习模型部署篇——从0部署深度学习分类模型(一)

模型布置流程

上文对什么是模型布置以及为什么要进行模型布置进行概述,下面就来谈谈模型布置的通用流程。模型布置常见的流程为“深度学习结构-->中心表明-->推理引擎”。咱们用下图来解释一下这个流程:首要深度学习结构咱们应该很熟悉了,如Pytorch、TensorFlow等等,图中以Pytorch为例,咱们先运用Pytorch界说了一个网络架构,如resnet,然后将咱们收集的数据喂入网络进行练习,得到权重文件;之后咱们会将刚刚得到的权重文件转化成一种中心格局,如图中的ONNX【这个最常见】;最后咱们会运用推理引擎【有TensorRT、ONNX RUNTIME、OpenVINO等等】把刚刚得到的中心表明转化成特定的格局,之后就能够在硬件平台高效的运转模型。

深度学习模型部署篇——从0部署深度学习分类模型(一)

这儿咱们只需知道这个流程就行,后边咱们会结合代码协助咱们了解。代码部分将依照下图流程进行,即选用Pytorch结构,ONNX中心表明,ONNX RUNTIME推理引擎,在本地PC上进行模型布置。

深度学习模型部署篇——从0部署深度学习分类模型(一)

模型布置代码解析

这节将以布置一个分类模型为例为咱们介绍,让咱们一起来看看叭~~~

装置环境

先给再咱们提个醒,咱们在装置环境的时分务必要把系统署理关上喔,否则会报错滴。

  • 装置深度学习结构Pytorch

    pip3 install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113
    
  • 装置中心表明ONNX

    pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  • 装置推理引擎ONNX Runtime

    pip install onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  • 装置其它依靠包

    pip install numpy pandas matplotlib tqdm opencv-python pillow -i https://pypi.tuna.tsinghua.edu.cn/simple
    

装备环境主张咱们运用Conda创建一个新的虚拟环境。

  • 验证装置是否成功

    import torch
    import onnx
    import onnxruntime as ort
    print('PyTorch 版别', torch.__version__)
    print('ONNX 版别', onnx.__version__)
    print('ONNX Runtime 版别', ort.__version__)
    

    装置成功回打印处对应包的版别,我的成果如下:

    深度学习模型部署篇——从0部署深度学习分类模型(一)

模型练习

装置好环境后,咱们就能够运用Pytorch模型来练习咱们的数据了,这个进程我在之前的博客中都有介绍,这儿即不赘述了,自己也偷个懒,运用官方在ImageNet上练习的resnet18模型,咱们能够直接下载模型权重:

# 导入相关包
import torch
from torchvision import models
# 有 GPU 就用 GPU,没有就用 CPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model = models.resnet18(pretrained=True)
model = model.eval().to(device)

假如咱们打印一下model,就会发现其便是resnet18的模型。【太长了,这儿就展现一部分了】

深度学习模型部署篇——从0部署深度学习分类模型(一)

将练习模型转化为中心表明ONNX

上一步咱们已经得到了一个练习模型model,下面咱们将其转化成ONNX中心格局。

首要咱们要先结构一个输入图画的Tensor:

x = torch.randn(1, 3, 256, 256).to(device)

然后咱们就能够运用下面的代码将模型model转化成ONNX格局:

with torch.no_grad():   #推理
    torch.onnx.export(
        model,                       # 要转化的模型
        x,                           # 模型的恣意一组输入
        'resnet18_imagenet.onnx',    # 导出的 ONNX 文件名
        opset_version=11,            # ONNX 算子集版别
        input_names=['input'],       # 输入 Tensor 的称号(自己起名字)
        output_names=['output']      # 输出 Tensor 的称号(自己起名字)
    ) 

咱们肯定也发现了, torch.onnx.export便是将模型转化成ONNX格局的函数。其中model表明要转化的pytorch模型;x是模型的恣意一组输入,留意这个输入的shape要和模型输入相匹配;’resnet18_imagenet.onnx’是咱们要到处的ONNX的文件名;opset_version表明算子集版别,不同的版别会更新一些新的算子; input_names和output_names是输入输出的称号,先给咱们打个预防针,这儿的输入输出称号要和咱们运转推理引擎时的保持共同。

上述代码运转成功后,会生成一个resnet18_imagenet.onnx文件:

咱们留意到我这有个图标了嘛,这是Netron,一个可视化模型的工具,咱们也能够下一个试试,能够看看模型的成果,双击点开来看看,如下图所示:

深度学习模型部署篇——从0部署深度学习分类模型(一)

好叭,这个图太长了,我展现出来是想要咱们看看这个开头的inputoutput,这两个便是咱们在 torch.onnx.export函数中输入输出的tensor称号,不信的话你在torch.onnx.export中修改一下,得到的ONNX成果也会发生变化。

运转推理引擎

先来说说推理引擎是干什么的,通俗的说它是用来加速咱们模型推理的,便利布置。

上一步咱们已经得到了中心表明的.onnx格局的模型,下面咱们将来用推理引擎ONNX Runtime来运转一下.onnx模型。

首要咱们先导入onnxruntime包,然后用InferenceSession方法来载入onnx模型,获取Onnx Runtime推理器。

import onnxruntime
ort_session = onnxruntime.InferenceSession('resnet18_imagenet.onnx')

接着咱们需求有一个输入数据,我从网上下载了一张橘子图片作为输入,可是咱们考虑一下,咱们能直接把下载的图片作为输入嘛,显然是不能的,由于咱们输入的要求是[3,256,256]巨细的图片,因而需求对输入的橘子做一些预处理操作,使其满足输入要求。

img_path = 'orange.jpg'  #输入图片途径
# 用 pillow 载入
from PIL import Image
img_pil = Image.open(img_path)

能够先来看一下图片和其尺度:

深度学习模型部署篇——从0部署深度学习分类模型(一)

深度学习模型部署篇——从0部署深度学习分类模型(一)

由于图画是PIL格局的,通道数为RGB格局表明图画有3个通道,即图片的shape为[3,310,163]。由于其不满足输入[3,256,256]的要求,故需求对图画进行预处理,如下:

from torchvision import transforms
# 测验集图画预处理-RCTN:缩放裁剪、转 Tensor、归一化
test_transform = transforms.Compose([transforms.Resize(256),
                                     transforms.CenterCrop(256),
                                     transforms.ToTensor(),
                                     transforms.Normalize(
                                         mean=[0.485, 0.456, 0.406], 
                                         std=[0.229, 0.224, 0.225])
                                    ])
input_img = test_transform(img_pil)   #将橘子图画送入预处理函数傍边

这个预处理不必我过多介绍了叭,对错常常见的,主要便是把图画变成指定的[3,256,256]巨细,并将其变成tensor格局并归一化。【对Totensor和Normalize不熟悉的能够看我的这篇博客】

咱们看看归一化之后图片的shape:

深度学习模型部署篇——从0部署深度学习分类模型(一)

已经变成[3,256,256],可是在输入模型之前呢,咱们需求加一个batch维度:

input_tensor = input_img.unsqueeze(0).numpy()

添加后的shape如下:

深度学习模型部署篇——从0部署深度学习分类模型(一)


到这儿咱们已经有了输入input_tensor,也构建了一个推理器ort_session,这样咱们就能运用推理器中的run方法进行模型推理了,代码如下:

# ONNX Runtime 输入
ort_inputs = {'input': input_tensor}
# ONNX Runtime 输出
pred_logits = ort_session.run(['output'], ort_inputs)[0]
pred_logits = torch.tensor(pred_logits)

留意这儿咱们把input_tensor先构建成一个字典,该字典的键input要和 torch.onnx.export函数中输入称号共同。ort_session.run方法的参数有两个,第一个是输出张量称号,也便是output,这个也和咱们前面 torch.onnx.export函数中输出称号共同。第二个参数便是咱们输入值的字典。咱们能够来看看pred_logits的shape:

深度学习模型部署篇——从0部署深度学习分类模型(一)

这便是将咱们的数据放入到模型中推理得到的成果,这个1000是ImageNet的分类类别,也便是模型最后的全连接层神经元个数为1000,如图:

深度学习模型部署篇——从0部署深度学习分类模型(一)

接着咱们就能够由这个成果来猜测出咱们输入的图片属于哪一类物体的概率,这些就和正常的图画分类猜测共同了,如下:

# 对 logit 分数做 softmax 运算,得到置信度概率
pred_softmax = F.softmax(pred_logits, dim=1) 
# 取置信度最高的前 n 个成果
n = 3
top_n = torch.topk(pred_softmax, n)
# 猜测类别
pred_ids = top_n.indices.numpy()[0]
# 猜测置信度
confs = top_n.values.numpy()[0]
# 载入类别 ID 和 类别称号 对应关系
df = pd.read_csv('imagenet_class_index.csv')   这个要下载ImageNet的类别索引对照表
idx_to_labels = {}
for idx, row in df.iterrows():
    #idx_to_labels[row['ID']] = row['class']   # 英文
    idx_to_labels[row['ID']] = row['Chinese'] # 中文
# 分别用英文和中文打印猜测成果
for i in range(n):
    class_name = idx_to_labels[pred_ids[i]] # 获取类别称号
    confidence = confs[i] * 100             # 获取置信度
    text = '{:<20} {:>.3f}'.format(class_name, confidence)
    print(text)

咱们能够看下

深度学习模型部署篇——从0部署深度学习分类模型(一)

能够看出橘子的概率仍是蛮高滴。

小结

整个分类模型布置的代码到这儿就完毕啦,咱们在来总结一下,主要分为三步:

  1. 练习分类模型,得到模型权重文件
  2. 将模型权重文件转化成ONNX中心表明格局
  3. 运用ONNX Runtime推理引擎进行推理

其实整个进程下来,你会发现针对分类模型来说布置仍是比较简单的,咱们能够快去试试叭。

总结

好啦,这部分就先为咱们介绍到这儿了,咱们先消化消化。这节我只展现了猜测单张图片的案例,也只为咱们梳理了模型布置的进程,可是是否运用模型布置,对推理速度的影响并没有表现,咱们将在下一节为咱们叙说,并且会完成一个自己的分类模型,敬请期待叭~~~

参考文献

图画分类模型布置

模型布置入门教程(一):模型布置简介

如若文章对你有所协助,那就

        

深度学习模型部署篇——从0部署深度学习分类模型(一)