【YoloV5 6.0|6.1 部署 TensorRT到torchserve】环境搭建|模型转换|engine模型部署(详细的packet文件编写方法)

忽然发现,关于部署TensorRT的文章少的可怜,于是乎,决定分享一下我自己关于这部分内容的一些成功实操和心得。还是希望大家可以分享出去,让更多人看到!!!

QQ: 1757093754

我的操作环境:

Yolov5 6.0:目前官方更新到6.1  —>  2022.7.5

python:3.8(anaconda3 2021.5)

CUDA: 11.4

CUDNN: 8.2.2

TensorRT: 8.2.2.1

torch:1.9.1+cu111

torchvision:0.10.1+cu111

vs:2019

OpenCV:4.5.0<如果你的yolov5版本是6.0、6.1,则可以不用OpenCV>

注:如果在进行操作的时候发现环境有问题,一定要检查自己的环境版本问题!!!

注:Yolov5 1~5版本并没有封装完好的TensorRT转换流程,故需要借助其他方法完成模型转换,但是6.0、6.1内置TensorRT的export。


目录

忽然发现,关于部署TensorRT的文章少的可怜,于是乎,决定分享一下我自己关于这部分内容的一些成功实操和心得。还是希望大家可以分享出去,让更多人看到!!!

我的操作环境:

前言

版本对应关系:(这一部分如果已经完成了,可以直接跳到下一个环节)

环境安装

第一步:安装CUDA和CUDNN

 第二步:配置环境变量

第三步:安装tensorrt到python环境(pip) 

模型转换(pt --> engine)

命令行参数解析: 

​编辑 export.py 命令行:

torchserve部署文件的制作

前言

handler.py的撰写

模型加载方法

 数据加载(预处理)方法

推理方法

后处理方法

最后 

部署工作

执行打包命令生成mar文件

打开torchserve服务

测试图片

后记

参考资料


前言

  • 本人使用的操作系统是 windows10,但同样的方法Linux也可以使用。
  • 本次操作不基于 TensorRTx 工具。<这是1~5版本yolov5模型转换时需要用到的>
  • 以下操作不会用到 OpenCV和Cmake,但是会给出下载方法。
  • 欢迎讨论、交流:QQ | 1757093754

版本对应关系:(这一部分如果已经完成了,可以直接跳到下一个环节)

tensorrtx下载链接<wang-xinyu的分享>:

GitHub - wang-xinyu/tensorrtx: Implementation of popular deep learning networks with TensorRT network definition APIhttps://github.com/wang-xinyu/tensorrtx Anaconda 和 python的对应关系:

Old package lists — Anaconda documentationhttps://docs.anaconda.com/anaconda/packages/oldpkglists/anaconda的国内下载源(清华源):

Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source MirrorIndex of /anaconda/archive/ | 清华大学开源软件镜像站,致力于为国内和校内用户提供高质量的开源软件镜像、Linux 镜像源服务,帮助用户更方便地获取开源软件。本镜像站由清华大学 TUNA 协会负责运行维护。https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Cmake下载<本次不会用到,只限windows系统的yolov5 1~5版本部署>:

Download | CMakehttps://cmake.org/download/OpenCV下载<本次不会用到,只限windows系统的yolov5 1~5版本部署>:

Releases - OpenCVhttps://opencv.org/releases/opencv与vs对应关系:

vc6 = Visual Studio 6
vc7 = Visual Studio 2003
vc8 = Visual Studio 2005
vc9 = Visual Studio 2008
vc10 = Visual Studio 2010
vc11 = Visual Studio 2012
vc12 = Visual Studio 2013
vc14 = Visual Studio 2015
vc15 = Visual Studio 2017
vc16 = Visual Studio 2019

注:这里我用的是vs2019,但是它不仅支持vc16,还支持了vc15、vc14,在你下载opencv的时候,安装包会写明其内置的vc版本。

 CUDA下载版本关系(注意自己电脑的driver version):

CUDA ToolkitToolkit Driver Version
Linux x86_64 Driver VersionWindows x86_64 Driver Version
CUDA 11.7 GA>=515.43.04>=516.01
CUDA 11.6 Update 2>=510.47.03>=511.65
CUDA 11.6 Update 1>=510.47.03>=511.65
CUDA 11.6 GA>=510.39.01>=511.23
CUDA 11.5 Update 2>=495.29.05>=496.13
CUDA 11.5 Update 1>=495.29.05>=496.13
CUDA 11.5 GA>=495.29.05>=496.04
CUDA 11.4 Update 4>=470.82.01>=472.50
CUDA 11.4 Update 3>=470.82.01>=472.50
CUDA 11.4 Update 2>=470.57.02>=471.41
CUDA 11.4 Update 1>=470.57.02>=471.41
CUDA 11.4.0 GA>=470.42.01>=471.11
CUDA 11.3.1 Update 1>=465.19.01>=465.89
CUDA 11.3.0 GA>=465.19.01>=465.89
CUDA 11.2.2 Update 2>=460.32.03>=461.33
CUDA 11.2.1 Update 1>=460.32.03>=461.09
CUDA 11.2.0 GA>=460.27.03>=460.82
CUDA 11.1.1 Update 1>=455.32>=456.81
CUDA 11.1 GA>=455.23>=456.38
CUDA 11.0.3 Update 1>= 450.51.06>= 451.82
CUDA 11.0.2 GA>= 450.51.05>= 451.48
CUDA 11.0.1 RC>= 450.36.06>= 451.22
CUDA 10.2.89>= 440.33>= 441.22
CUDA 10.1 (10.1.105 general release, and updates)>= 418.39>= 418.96
CUDA 10.0.130>= 410.48>= 411.31
CUDA 9.2 (9.2.148 Update 1)>= 396.37>= 398.26
CUDA 9.2 (9.2.88)>= 396.26>= 397.44
CUDA 9.1 (9.1.85)>= 390.46>= 391.29
CUDA 9.0 (9.0.76)>= 384.81>= 385.54
CUDA 8.0 (8.0.61 GA2)>= 375.26>= 376.51
CUDA 8.0 (8.0.44)>= 367.48>= 369.30
CUDA 7.5 (7.5.16)>= 352.31>= 353.66
CUDA 7.0 (7.0.28)>= 346.46>= 347.62

注:该版本为最小驱动版本,可以大于该版本。 

cudnn与cuda对应关系及下载:

cuDNN Archive | NVIDIA Developerhttps://developer.nvidia.com/rdp/cudnn-archive#a-collapse742-10 cuda与TensorRT对应关系及下载:

NVIDIA TensorRT Download | NVIDIA Developerhttps://developer.nvidia.com/nvidia-tensorrt-download注:下载TensorRT的时候记得点这个: 

点开任意一个,可以看到有给出的版本对应关系,自行下载即可!

 恭喜你!第一步完成了,成功下载了所有环境!


环境安装

  • 前面讲了所需要的环境和其版本对应关系,这一节讲如何进行搭建环境。

第一步:安装CUDA和CUDNN

CUDA的安装默认路径设置在了:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA

这个就不要移动了,方便以后修改和查找。多个CUDA版本之间可以共存且不影响(注意区分你的驱动和CUDA的关系,他们不是一回事,驱动肯定不能多安装) ,实际工作的CUDA取决于你的环境变量。

安装好CUDA之后,你需要安装cudnn,方法有点特殊:

  • cuda\bin中的文件复制到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin
  • cuda\include中的文件复制到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\include
  • cuda\lib中的文件复制到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\lib

 第二步:配置环境变量

  • C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\bin
  • C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\libnvvp
  • D:\TensorRT-8.2.2.1.Windows10.x86_64.cuda-11.4.cudnn8.2\TensorRT-8.2.2.1\include
  • D:\TensorRT-8.2.2.1.Windows10.x86_64.cuda-11.4.cudnn8.2\TensorRT-8.2.2.1\lib
  • D:\opencv_4.5.0\opencv\build\x64\vc15\bin
  • D:\opencv_4.5.0\opencv\build\x64\vc15\lib
  • D:\Cmake\bin

注:OpenCV、Cmake没安装则不用配置,只检查tensorrt、cuda、anaconda的环境即可。 

第三步:安装tensorrt到python环境(pip) 

打开下载好的tensorrt,注意以下4个文件夹,我们需要安装里面的whl到python环境当中。

pip install graphsurgeon\graphsurgeon-0.4.5-py2.py3-none-any.whl
pip install onnx_graphsurgeon\onnx_graphsurgeon-0.3.12-py2.py3-none-any.whl
pip install python\tensorrt-8.2.2.1-cp38-none-win_amd64.whl
pip install uff\uff-0.6.9-py2.py3-none-any.whl

 注:在python文件夹下有4个whl,这里我的python环境是3.8,故只安装cp38版本的whl即可。

注:以上过程正常情况下均不会报错。 


模型转换(pt --> engine)

在yolov5 6版本中,给出了市面主流模型的转换方案,下面是支持模型的权重图:

 我们直接使用 export.py 就可以直接转换模型了:(如果你前面的过程没有任何问题的话)

命令行参数解析: 

  • --data:因为转换的权重不再是yolo.py里面的模型类,故不再有names的成员变量,需要我们指定data文件去加载类别信息!
  • --weights:我们训练完成了 pt 权重。(best.pt、epoch.pt都可以)
  • --imgsz:固定一个大小去模拟推理,这里建议你训练的时候用的什么resize,你这里就写什么。(当指定完大小时,生成的权重只能将如此大小的图片输入模型预测)
  • --device:一定要用GPU!!! 一定要用GPU!!!一定要用GPU!!!重要的事情说3遍,这个是推理计算用的,和生成的模型无关,我用GPU都跑了半个小时!!!
  • --opset:你的onnx opset型号。(如果你以上过程均和我一样,就是12,不然也是12 【doge】)(其实你这个地方改不改都无所谓。。因为源代码默认13了【如果报opset版本的错,则要修改以下源代码】)
  • --conf-thres: 你的预测结果的置信度的阈值,大于此值时显示
  • --include:只写 engine 就行。

其他参数:

  • --workspace:推理过程当中显存最大开销,这个默认是4,我设置的7。 【该参数可以减少模型转换时间】

注:运行的时候如果报opset版本的错误,请把这个地方改成12。(opset version)

 export.py 命令行:

python .\export.py --data .\data\voc_xf.yaml --weights .\best.pt --imgsz 640,640 --batch-size 1 --device 0 --workspace 7 --conf-thres 0.6 --include engine

 注:

  • export通过onnx为中介,故中间会生成一个onnx的模型,再通过其生成engine。
  • 转换时间很长,大概半个小时(开4G显存的话,我开了7G,是10多分钟)
  • 期间转换使用的显存会持续增加,可以开另外一个进程的终端去查看显存使用情况。
  • 转换期间可能会出现警告,只要程序没终止,说明还在转换,不要暂停!!!

查看显存使用情况: 

nvidia-smi

 生成的engine和onnx:

 可以看到生成的engine还是非常小的。


torchserve部署文件的制作

  • 在之前的工作中,我们已经获得了engine权重,它可以加速我们的模型预测,我们要把它部署在服务器上,这一小节将讲述如何制作torchserve部署所用的文件。

前言

在之前,我写过了一篇博客,记录了torchserve的安装和使用过程: (可以参考一下)

【torchserve安装和使用】torchserve部署方法|常见问题汇总|mmdetection使用torchserve部署|不使用docker_活成自己的样子啊的博客-CSDN博客_torchserve部署https://blog.csdn.net/m0_61139217/article/details/125014279?spm=1001.2014.3001.5501

handler.py的撰写

上面那篇博客里面讲到,handler.py 要重新实现自己的 模型加载方法、数据加载(预处理)方法、推理方法、后处理方法。这一次,就亲手实现一下yolov5的handler编写:

模型加载方法

加载模型的方法,我们采用yolov5里面 detect.py 使用的 DetectMultiBackend 类。

我们自定义一个model.py去继承一下这个类,方便我们在handler中调用:

model.py:

from models.common import DetectMultiBackend

class YOLOV5ObjectDetector(DetectMultiBackend):
    def __init__(self, weights, device, data):
        super(YOLOV5ObjectDetector, self).__init__(weights=weights, device=device, data=data)

在继承的时候,我们只需要传入3个参数即可,一个是权重的路径,一个是预测使用的GPU还是CPU,一个是我们的数据集格式文件(voc_xf.yaml)

 之后我们开始实现 handler.py 里面的模型加载方法:

names = []    
def _load_pickled_model(self, model_dir, model_file, model_pt_path):
        """
        Loads the pickle file from the given model path.
        Args:
            model_dir (str): Points to the location of the model artefacts.
            model_file (.py): the file which contains the model class.
            model_pt_path (str): points to the location of the model pickle file.
        Raises:
            RuntimeError: It raises this error when the model.py file is missing.
            ValueError: Raises value error when there is more than one class in the label,
                        since the mapping supports only one label per class.
        Returns:
            serialized model file: Returns the pickled pytorch model file
        """
        # 检测是否有model.py
        model_def_path = os.path.join(model_dir, model_file)
        if not os.path.isfile(model_def_path):
            raise RuntimeError("Missing the model.py file")

        # 检测model.py当中是否只有一个类
        module = importlib.import_module(model_file.split(".")[0])
        model_class_definitions = list_classes_from_module(module)
        if len(model_class_definitions) != 1:
            raise ValueError(
                "Expected only one class as model definition. {}".format(model_class_definitions)
            )

        model_class = model_class_definitions[0]  # YOLOV5ObjectDetector类

        self.device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

        model = model_class(model_pt_path, self.device, 'voc_xf.yaml')

        self.names = model.names
        self.names[0] = 'xf_road'
        return model

因为 DetectMultiBackend  类同时将数据集格式文件和模型加载进去了,所以我们可以将其的成员变量names赋值给handler.py的成员变量names中(这个变量需要自己定义一下,如上面代码块的第一行)。

注:

  • 代码中的倒数2行是调整我自己数据集的,用来把第一个类别的名称改一下,这个不是必须的。
  • 这个names就是预测类别显示的名称,再次期间你可以使用中文但是需要下载一个中文ttf。

 数据加载(预处理)方法

handler.py 中的 preprocess 方法实现了对要检测的数据的一个预处理,参数data可能是多样的,这取决于上传的方式。

    def preprocess(self, data):
        print("DEBUG--%d" % len(data))
        images = []
        for row in data:
            image = row.get("data") or row.get("body")
            if isinstance(image, str):
                # if the image is a string of bytesarray.
                image = base64.b64decode(image)
            elif isinstance(image, (bytearray, bytes)):  # if the image is sent as bytesarray
                image = Image.open(io.BytesIO(image))
                # # 将bgr转为rbg
                image = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
            else:  # if the image is a data list
                image = image.get('instances')[0]
                image = np.divide(torch.HalfTensor(image), 255)

            img0 = image  # 保存原始图像信息
            img = letterbox(image, 640, stride=32, auto=self.model.pt)[0]

            # Convert
            img = img.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
            image = np.ascontiguousarray(img)

            image = torch.from_numpy(image).float().to(self.device)

            image /= 255

            if len(image.shape) == 3:
                image = image[None]  # 在batch-size维度展开

            images.append([image, img0])
        # images = torch.stack(images).to(self.device)  # 数据集的拼接和扩维
        return images

值得一提的是: 

因为转换之后的tensorrt模型已经固定了输入特征矩阵的大小,所以我们需要记录一下图片预处理前后的大小,方便后处理过程中对预测得到的标注框进行还原。

img0对应了原始图像。

image对应了数据增强完的图像。

推理方法

handler.py 中通过 inference 方法实现模型对数据的处理推断过程。

我们采用yolov5当中模型对数据的处理推断过程:

 def inference(self, data, *args, **kwargs):
        results = []

        for each_data in data:
            im, im0 = each_data
            pred = self.model(im, augment=False, visualize=False)
            results.append([each_data, pred])

        return results

值得一提的是: 

preprocess、inference、postprocess的参数和返回值是传递的,上一个方法的返回值既是下一个方法的参数。

后处理方法

这里就是我们要撰写的handler.py中的最后一个方法了,他负责对预测结果的处理和输出。

由于项目保密性,我已隐去重要代码

    def postprocess(self, data):
        all_result = []

        for each_data, pred in data:
            result = []

            # 非极大值抑制
            pred = non_max_suppression(pred, conf_thres=0.3, iou_thres=0.45, classes=None, agnostic=False, max_det=1000)[0]

            if pred is None:
                print('No target detected.')
                result.append({"classes": [], "scores": [], "boxes": []})
                return result
            else:
                # 将方框从img大小重新缩放为im0大小
                object = []
                pred[:, :4] = scale_coords(each_data[0].shape[2:], pred[:, :4], each_data[1].shape).round()

                pred[:, :4] = pred[:, :4].round()
                boxes = pred[:, :4].detach().cpu().numpy()
                scores = pred[:, 4].detach().cpu().numpy()
                classes = pred[:, 5].detach().cpu().numpy().astype(np.int)
                new_classes = [self.names[i] for i in classes]

                for i in range(len(classes)):
                    object.append([new_classes[i], boxes[i][0], boxes[i][1], boxes[i][2], boxes[i][3], scores[i]])
            
                new_cars = object  # 此处隐掉了重要代码

                if new_cars:
                    result.append({
                        "classes": [classes for classes, _, _, _, _, _ in new_cars],
                        "scores": [str(scores) for _, _, _, _, _, scores in new_cars],
                        "boxes": [str([b0, b1, b2, b3]) for _, b0, b1, b2, b3, _ in new_cars]
                    }
                    )

                    print('GYYDEBUG--RESULT:{}'.format(result))

                    all_result.append(result)

                    return all_result
                else:
                    result.append({"classes": [], "scores": [], "boxes": []})
                    return result

最后 

handler.py 文件的完成意味着部署的前提工作已经完成。

最后将所有文件(包含依赖关系所需要的文件)放在一起:打包成 packet_trt

 注:文中的几个步骤仅供参考学习,直接cv是没用的,这是我自己的项目的handler,要真的想学会,还请认真研究其中代码的原理。该代码是成功部署上了的代码。


部署工作

  • 当你完成了你的所有文件准备,你就可以正式开始你的部署工作了。

 将你的打包的 packet_trt 放到你要部署的服务器上面:

注:这里我把权重移出来了。

执行打包命令生成mar文件

注意文件的相对路径:

torch-model-archiver --model-name test_trt --version 1 --serialized-file best.engine --handler packets_trt/handler.py --model-file packets_trt/model.py --extra-file packets_trt -f

(生成的mar我将其移到 model-store 文件夹下面【要自己新建一个model-store文件夹】) 

打开torchserve服务

torchserve --start --model-store model-store --models test=test_trt.mar --ts_config ./config.properties

正常部署的显示:(有TensorRT的信息) 

注:

  • [I]:是tensorrt的正常信息日志报告。
  • [W]:是tensorrt的警告,这个不是报错,可以不用管。
  • [E] :这个是报错,出现了这个代表流程出现了问题。

测试图片

这里我测试了一次性加载多张不同格式的图片:

curl http://localhost:8085/predictions/test -T "{01.jpg,02.png}"

成功测试生成的日志:(下图中上面那几行请忽略,我测试的时候点错了【doge】)

成功测试的结果:(注:这里啥也没检测到是因为我用代码隐藏了,由于项目的保密性,还请大家理解!!!)


后记

注:

  • 生成engine的TensorRT环境和部署时加载模型的TensorRT需要是一样的,建议模型转换和部署在同一个环境下面进行。
  • 部署的时候建议开2个终端,一个来显示部署的信息,另一个用来测试,这样可以方便查看模型的推理部分是否会出现问题。
  • 如果部署完的时候发现模型没加载到torchserve里面,则要依次检查 生成的mar文件是否正确、handler编写是否正确、环境是否安装正确
  • 撰写不易,还请大家能给我推推流~~~【doge】

参考资料:

yolov5部署之七步完成tensorRT模型推理加速_Christo3的博客-CSDN博客_tensorrt部署yolov5https://blog.csdn.net/weixin_41552975/article/details/114398669?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-114398669-blog-125082939.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-114398669-blog-125082939.pc_relevant_aa&utm_relevant_index=1

TorchServe部署pytorch模型_lulu_陌上尘的博客-CSDN博客_torchserveicon-default.png?t=M5H6https://blog.csdn.net/qq_41360255/article/details/116707586
1. TorchServe — PyTorch/Serve master documentationicon-default.png?t=M5H6https://pytorch.org/serve/TensorRT SDK | NVIDIA Developericon-default.png?t=M5H6https://developer.nvidia.com/tensorrt


  • 17
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

活成自己的样子啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值