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服务
测试图片
后记
参考资料
tensorrtx下载链接
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 Toolkit | Toolkit Driver Version | |
---|---|---|
Linux x86_64 Driver Version | Windows 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的安装默认路径设置在了:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA
这个就不要移动了,方便以后修改和查找。多个CUDA版本之间可以共存且不影响(注意区分你的驱动和CUDA的关系,他们不是一回事,驱动肯定不能多安装) ,实际工作的CUDA取决于你的环境变量。
安装好CUDA之后,你需要安装cudnn,方法有点特殊:
注:OpenCV、Cmake没安装则不用配置,只检查tensorrt、cuda、anaconda的环境即可。
打开下载好的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即可。
注:以上过程正常情况下均不会报错。
在yolov5 6版本中,给出了市面主流模型的转换方案,下面是支持模型的权重图:
我们直接使用 export.py 就可以直接转换模型了:(如果你前面的过程没有任何问题的话)
其他参数:
注:运行的时候如果报opset版本的错误,请把这个地方改成12。(opset version)
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
注:
查看显存使用情况:
nvidia-smi
生成的engine和onnx:
可以看到生成的engine还是非常小的。
在之前,我写过了一篇博客,记录了torchserve的安装和使用过程: (可以参考一下)
【torchserve安装和使用】torchserve部署方法|常见问题汇总|mmdetection使用torchserve部署|不使用docker_活成自己的样子啊的博客-CSDN博客_torchserve部署https://blog.csdn.net/m0_61139217/article/details/125014279?spm=1001.2014.3001.5501
上面那篇博客里面讲到,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中(这个变量需要自己定义一下,如上面代码块的第一行)。
注:
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 放到你要部署的服务器上面:
注:这里我把权重移出来了。
注意文件的相对路径:
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 --start --model-store model-store --models test=test_trt.mar --ts_config ./config.properties
正常部署的显示:(有TensorRT的信息)
注:
这里我测试了一次性加载多张不同格式的图片:
curl http://localhost:8085/predictions/test -T "{01.jpg,02.png}"
成功测试生成的日志:(下图中上面那几行请忽略,我测试的时候点错了【doge】)
成功测试的结果:(注:这里啥也没检测到是因为我用代码隐藏了,由于项目的保密性,还请大家理解!!!)
注:
TorchServe部署pytorch模型_lulu_陌上尘的博客-CSDN博客_torchservehttps://blog.csdn.net/qq_41360255/article/details/116707586
1. TorchServe — PyTorch/Serve master documentationhttps://pytorch.org/serve/TensorRT SDK | NVIDIA Developerhttps://developer.nvidia.com/tensorrt