fasterrcnn rpn roialign tensorrt部署实践

x33g5p2x  于2022-08-17 转载在 其他  
字(21.2k)|赞(0)|评价(0)|浏览(1403)

环境安装:

pycuda安装:

开源项目信息

fasterRCNN的训练

faster rcnn onnx实践

第3步测试结果:

第4步测试结果:

单张图片测试代码:

多张图片预测代码:

第5步做了修改:

第7步测试:

第8步测试

onnx转trt操作

c++ 转换trt:

Onnx转trt代码及操作:

c++ tensorrt推理部分

c++onnx转tensorrt

打印模型输入输出参数:

可以忽略的报错:

环境安装:

pip install onnxsim

pytorch安装:

cuda版本是11.0,没有cuda11.0对应的torchvision,所以安装了cpu版:
pip install torch==1.10.0+cpu torchvision==0.11.0+cpu torchaudio==0.10.0 -f https://download.pytorch.org/whl/torch_stable.html

pip install torch==1.10.0+cu113 torchvision==0.11.0+cu113 -f https://download.pytorch.org/whl/torch_stable.html

tensorrt安装:

onnx转tensorrt 实战干货总结_AI视觉网奇的博客-CSDN博客_onnx转tensorrt

pycuda安装:

win10安装pycuda2022_AI视觉网奇的博客-CSDN博客

开源项目信息

根据开源项目进行部署测试:

GitHub - thb1314/tensorrt-onnx-fasterrcnn-fpn-roialign

看了代码,感觉主要是把faster rcnn拆分为两个部分,

第1部分:

AnchorGenerator

RPNHead

RegionProposalNetwork

GeneralizedRCNNTransform

第2部分:

MultiScaleRoIAlign

TwoMLPHead

FastRCNNPredictor
RoIHeads,这个又依赖前面三个。

本部分基于repo

GitHub - shouxieai/tensorRT_Pro: C++ library based on tensorrt integration

安装部分请看该项目的readme部分,在本项目文件下tensorrt_code

如果可以给该项目点个star的话,麻烦顺手给俺也点一个吧,谢谢。

fasterRCNN的训练

demo: 使用pytorch训练自己的Faster-RCNN目标检测模型 - 野生鹅鹅 - 博客园

其他git code还请自行查找

导出onnx的时候,需要加载加载自己训练的权重。

faster rcnn onnx实践

重要的环节是第3步和 第5步,

作者提供了8个步骤:
 x01export_FasterRCNN_onnx.py
 x02test_FasterRCNN_onnx.py
 x03extract_RPN.py
 x04testRPNonnx.py
 x05extract_ROIHeader.py
 x06reduceRpnOnnx.py
 x07reduce_header_onnx.py
 x08test_header_onnx.py

第一个步骤转onnx警告和解决方法:

that if the size of dimension 1 of the input is not 1, the ONNX model will return an error_AI视觉网奇的博客-CSDN博客

第3步测试结果:

输出特征名:

['rpn_boxes', 'feature_0', 'feature_1', 'feature_2', 'feature_3', 'feature_pool']

输出特征维度:

  1. list 1000*5

  2. list,长度4

0: 1 256 200 264

1: 1 256 100 132

2: 1 256 50 66

3: 1 256 25 33

pool: 256 13 17

3是图片

4是维度

原本代码batch_size为1时可以正确预测,但是batch_size为2时,预测结果都是第一张图片,

稍微修改了代码:

  1. import torch
  2. import os
  3. import sys
  4. sys.path.insert(0, os.path.abspath('..'))
  5. from model import fasterrpn_resnet50_fpn
  6. import glob
  7. from torchvision import transforms
  8. import cv2
  9. if __name__ == '__main__':
  10. model = fasterrpn_resnet50_fpn(pretrained=True)
  11. model.eval()
  12. img_tensor_list = list()
  13. transform_func = transforms.Compose([
  14. transforms.ToTensor(),
  15. # transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
  16. ])
  17. input_height, input_width = (600 + 31) // 32 * 32, (800 + 31) // 32 * 32
  18. image_list = list()
  19. for item in glob.glob("./*.jpg"):
  20. image_list.append(cv2.resize(cv2.imread(item), dsize=(input_width, input_height)))
  21. img_tensor_list.append(
  22. transform_func(cv2.cvtColor(cv2.resize(cv2.imread(item), dsize=(input_width, input_height)), cv2.COLOR_BGR2RGB)))
  23. with torch.no_grad():
  24. results = model(img_tensor_list, is_show=True)
  25. result = results[0]
  26. for i, item in enumerate(result):
  27. image = image_list[i].copy()
  28. for score_box in item:
  29. box = score_box[1:]
  30. box = box.numpy()
  31. cv2.rectangle(image, tuple(map(int, box[0:2])), tuple(map(int, box[2:4])), (0, 255, 0))
  32. cv2.imshow("win", image)
  33. cv2.waitKey()
  34. cv2.destroyWindow("win")
  35. output_names = ["rpn_boxes", *tuple(['feature_'+item for item in results[1].keys()])]
  36. print(output_names)
  37. dynamic_axes = {'input':{0: "N"},'rpn_boxes': {0: "N"},'feature_0': {0: "N"}, 'feature_1': {0: "N"}, 'feature_2': {0: "N"}, 'feature_3': {0: "N"}, 'feature_pool': {0: "N"}}
  38. onnx_save_path = 'rpn_backbone_resnet50.onnx'
  39. torch.onnx.export(model, torch.rand(2, 3, input_height, input_width), onnx_save_path, verbose=False,
  40. do_constant_folding=True,
  41. input_names=["input"], output_names=output_names,
  42. dynamic_axes=dynamic_axes,
  43. opset_version=11)
  44. import onnxsim
  45. import onnx
  46. model = onnx.load(onnx_save_path)
  47. # convert model
  48. model_simp, check = onnxsim.simplify(model, check_n=0,input_shapes={'input':[-1,3,input_height,input_width]},
  49. dynamic_input_shape=True)
  50. # dynamic_input_shape=False)
  51. with open(onnx_save_path,'wb') as f:
  52. # with open(onnx_save_path.replace(".onnx","_simp.onnx"),'wb') as f:
  53. onnx.save(model_simp, f)

多图片可以批量预测了,但是预测结果都不对。

第4步测试结果:

单张图片测试代码:

  1. import onnxruntime as rt
  2. import numpy as np
  3. import torch
  4. import torchvision
  5. import cv2
  6. from torchvision import transforms
  7. def get_classes(filepath):
  8. with open(filepath, 'r', encoding='gbk') as f:
  9. return [item.strip() for item in f.readlines()]
  10. if __name__ == '__main__':
  11. onnx_save_path = "rpn_backbone_resnet50.onnx"
  12. img = cv2.imread('./car.jpg')
  13. img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  14. img = cv2.resize(img, dsize=(800, 608))
  15. normalize = transforms.Compose([
  16. transforms.ToTensor(),
  17. transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
  18. ])
  19. img_tensor = normalize(img).unsqueeze(dim=0)
  20. img_input = img_tensor.numpy().astype(np.float32)
  21. sess = rt.InferenceSession(onnx_save_path)
  22. input_name = sess.get_inputs()[0].name
  23. label_names = [sess.get_outputs()[i].name for i in range(1)]
  24. print("input_name",input_name)
  25. pred_onnx = sess.run(label_names, {input_name:img_input})
  26. print("label_names", label_names,"pred size",pred_onnx[0].shape)
  27. # output without nms
  28. pred_onnx = dict(zip(label_names, pred_onnx))
  29. image = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
  30. for box in pred_onnx['rpn_boxes'][0]:
  31. box = box[1:]
  32. cv2.rectangle(image, tuple(map(int,box[0:2])), tuple(map(int,box[2:4])), (0,255,0))
  33. cv2.imshow("img", img)
  34. cv2.imshow("win", image)
  35. cv2.waitKey()
  36. cv2.destroyWindow("win")

步骤4测试可视化结果,与3是不一样的, 43906,步骤3的结果是10006

第四步backbone输入输出维度:

input_name input
label_names ['rpn_boxes'] pred size (1, 4390, 6)

多张图片预测代码:

  1. import onnxruntime as rt
  2. import numpy as np
  3. import torch
  4. import torchvision
  5. import cv2
  6. from torchvision import transforms
  7. def get_classes(filepath):
  8. with open(filepath, 'r', encoding='gbk') as f:
  9. return [item.strip() for item in f.readlines()]
  10. if __name__ == '__main__':
  11. onnx_save_path = "rpn_backbone_resnet50.onnx"
  12. img = cv2.imread('./car.jpg')
  13. img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  14. img = cv2.resize(img, dsize=(800, 608))
  15. print(img.shape)
  16. normalize = transforms.Compose([
  17. transforms.ToTensor(),
  18. # transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
  19. ])
  20. img_tensor = normalize(img)#.unsqueeze(dim=0)
  21. img_input = img_tensor.numpy().astype(np.float32)
  22. img_input=np.array([img_input,img_input])
  23. sess = rt.InferenceSession(onnx_save_path)
  24. input_name = sess.get_inputs()[0].name
  25. for data in sess.get_outputs():
  26. print("outname",data.name)
  27. label_names = [sess.get_outputs()[i].name for i in range(1)]
  28. print("input_name",input_name)
  29. pred_onnx = sess.run(label_names, {input_name:img_input})
  30. print("label_names", label_names,"pred size",pred_onnx[0].shape)
  31. # output without nms
  32. pred_onnx = dict(zip(label_names, pred_onnx))
  33. image = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
  34. for box in pred_onnx['rpn_boxes'][0]:
  35. box = box[1:]
  36. cv2.rectangle(image, tuple(map(int,box[0:2])), tuple(map(int,box[2:4])), (0,255,0))
  37. cv2.imshow("img", img)
  38. cv2.imshow("win", image)
  39. cv2.waitKey()
  40. cv2.destroyWindow("win")

第5步做了修改:

改完支持多batch_size,但是多张图片预测,结果都是第一张图片的。

  1. import torch
  2. import os
  3. import sys
  4. sys.path.insert(0, os.path.abspath('..'))
  5. from model import fasterrpn_resnet50_fpn, fasterroiheader_resnet50_fpn
  6. import math
  7. import glob
  8. from torchvision import transforms
  9. import cv2
  10. import os
  11. if __name__ == '__main__':
  12. model = fasterrpn_resnet50_fpn(pretrained=True)
  13. model_header = fasterroiheader_resnet50_fpn(pretrained=True, transform=model.transform, box_score_thresh=0.5,box_nms_thresh=0.3)
  14. model.eval()
  15. model_header.eval()
  16. img_tensor_list = list()
  17. transform_func = transforms.Compose([
  18. transforms.ToTensor(),
  19. # transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
  20. ])
  21. input_height, input_width = (600 + 31) // 32 * 32, (800 + 31) // 32 * 32
  22. image_list = list()
  23. for item in glob.glob("./*.jpg"):
  24. image_list.append(cv2.resize(cv2.imread(item), dsize=(input_width, input_height)))
  25. img_tensor_list.append(
  26. transform_func(cv2.cvtColor(cv2.resize(cv2.imread(item), dsize=(input_width, input_height)), cv2.COLOR_BGR2RGB)))
  27. with torch.no_grad():
  28. proposals, features, images, original_image_sizes = model(img_tensor_list)
  29. if not os.path.exists('buffle.pkl'):
  30. with open('buffle.pkl', 'wb') as f:
  31. torch.save({
  32. 'proposals':proposals,
  33. 'features':features,
  34. 'image_sizes':images.image_sizes
  35. }, f)
  36. for feature in features.values():
  37. print('feature.shape',feature.shape)
  38. proposals = [item[:,1:] for item in proposals]
  39. if not os.path.exists('roi_result.pkl'):
  40. roi_result = model_header.roi_heads.box_roi_pool(features, proposals, images.image_sizes)
  41. with open('roi_result.pkl', 'wb') as f:
  42. torch.save({
  43. 'roi_result':roi_result
  44. }, f)
  45. dummy_image = torch.rand(1, 3, input_height, input_width)
  46. batch_size = int(dummy_image.size(0))
  47. dummy_proposals = [torch.rand((model.rpn.post_nms_top_n(), 4)) for _ in range(batch_size)]
  48. height, width = int(dummy_image.size(2)), int(dummy_image.size(3))
  49. dummy_features = {
  50. key: torch.rand(batch_size, model.backbone.out_channels, math.ceil(height / (2 ** (i + 2))),
  51. math.ceil(width / (2 ** (i + 2)))) for i, key in enumerate(features.keys())}
  52. input_names = [*tuple(['feature_' + key for key in dummy_features.keys()]), 'proposals']
  53. dynamic_axes = {'proposals': {0: "N"}}
  54. dynamic_axes.update({'feature_'+key: {0: "B"} for key in dummy_features.keys()})
  55. dynamic_axes.update({name: {0: "N"} for name in ['outputs']})
  56. class Wrapper(torch.nn.Module):
  57. def __init__(self, image_sizes, model):
  58. super(Wrapper, self).__init__()
  59. self.image_sizes = image_sizes
  60. self.model = model
  61. def forward(self, x, boxes):
  62. return self.model(x, boxes, self.image_sizes)
  63. """
  64. torch.onnx.export(Wrapper(images.image_sizes, model_header.roi_heads.box_roi_pool), (features, dummy_proposals),
  65. "roialign.onnx", verbose=True,
  66. do_constant_folding=True,
  67. input_names=input_names, output_names=["outputs"],
  68. dynamic_axes=dynamic_axes,
  69. opset_version=11)
  70. print(roi_result.shape)
  71. """
  72. result = model_header(features, proposals, images, original_image_sizes)
  73. for i, item in enumerate(result):
  74. image = image_list[i].copy()
  75. for score_box in item['boxes']:
  76. box = score_box
  77. box = box.numpy()
  78. cv2.rectangle(image, tuple(map(int, box[0:2])), tuple(map(int, box[2:4])), (0, 255, 0))
  79. cv2.imshow("win", image)
  80. cv2.waitKey()
  81. cv2.destroyWindow("win")
  82. output_names = ["boxes", "labels", "scores"]
  83. dummy_image = torch.rand(1, 3, input_height, input_width)
  84. batch_size = int(dummy_image.size(0))
  85. dummy_proposals = [torch.rand((model.rpn.post_nms_top_n(), 4)) for _ in range(batch_size)]
  86. height,width = int(dummy_image.size(2)),int(dummy_image.size(3))
  87. dummy_features = {key:torch.rand(batch_size, model.backbone.out_channels, math.ceil(height / (2 ** (i + 2))), math.ceil(width / (2 ** (i + 2)))) for i,key in enumerate(features.keys())}
  88. print(dummy_features.keys())
  89. input_names = [*tuple(['feature_'+key for key in dummy_features.keys()]), 'proposals']
  90. dynamic_axes = {'proposals': {0: "N"}}
  91. dynamic_axes.update({name: {0: "N"} for name in output_names})
  92. onnx_save_path = "header.onnx"
  93. torch.onnx.export(model_header, (dummy_features, dummy_proposals, dummy_image), onnx_save_path, verbose=True,
  94. do_constant_folding=True,
  95. input_names=input_names, output_names=output_names,
  96. dynamic_axes=dynamic_axes,
  97. opset_version=11)

第6步测试backbone输出维度:

  1. import onnx_graphsurgeon as gs
  2. import onnx
  3. def cutOnnx():
  4. onnx_save_path = "rpn_backbone_resnet50.onnx"
  5. graph = gs.import_onnx(onnx.load(onnx_save_path))
  6. for output in graph.outputs:
  7. print(0,output)
  8. graph.outputs = graph.outputs[0:-1]
  9. for output in graph.outputs:
  10. print(1,output)
  11. graph.cleanup()
  12. # remove feature pool
  13. onnx.save(gs.export_onnx(graph), onnx_save_path)
  14. if __name__ == '__main__':
  15. cutOnnx()

结果:

  1. #0 Variable (rpn_boxes): (shape=[1, 4390, 6], dtype=float32)
  2. # 0 Variable (feature_0): (shape=[1, 256, 152, 200], dtype=float32)
  3. # 0 Variable (feature_1): (shape=[1, 256, 76, 100], dtype=float32)
  4. # 0 Variable (feature_2): (shape=[1, 256, 38, 50], dtype=float32)
  5. # 0 Variable (feature_3): (shape=[1, 256, 19, 25], dtype=float32)
  6. # 1 Variable (rpn_boxes): (shape=[1, 4390, 6], dtype=float32)
  7. # 1 Variable (feature_0): (shape=[1, 256, 152, 200], dtype=float32)
  8. # 1 Variable (feature_1): (shape=[1, 256, 76, 100], dtype=float32)
  9. # 1 Variable (feature_2): (shape=[1, 256, 38, 50], dtype=float32)

第7步测试:

x07reduce_header_onnx.py:精简header onnx,仅保留全连接层部分。具体细节:

1.将网络的输入更改为roialigned_featureproposals,去掉roi align和fpn_level的计算部分。

tensor = tensors["218"] Line11 这段代码即对该reshape操作输入的替换。

218哪里来的?

netron软件查看的,右下角INPUTS的 data name218

这个层在整个结构的大概位置:

这里可以根据自己的生成的onnx改变名字,下面是局部放大点的图:

  1. 对输出的box和score节点的前面的reshape操作进行处理

对应一下几行代码

这里需要根据自己的生成的onnx修改,切记

  1. shape_score = gs.Constant(name="shape_score", values=np.array((-1, 90), dtype=np.int64))
  2. shape_boxes = gs.Constant(name="shape_boxes", values=np.array((-1, 90, 4), dtype=np.int64))
  3. shape_boxes_last_node = gs.Constant(name="shape_boxes_last_node", values=np.array((-1, 91, 4), dtype=np.int64))
  4. # 这里的Reshape_320和Reshape_322是box和score的上一个reshape节点
  5. # 这里填写上面的框选的部分分
  6. for node in graph.nodes:
  7. if node.name == "Reshape_320":
  8. node.inputs[-1] = shape_boxes
  9. elif node.name == "Reshape_322":
  10. node.inputs[-1] = shape_score
  11. # the last second reshape node relative to box output
  12. elif node.name == "Reshape_308":
  13. node.inputs[-1] = shape_boxes_last_node

好像报错了:
[W] colored module is not installed, will not use colors when logging. To enable colors, please install the colored module: python3 -m pip install colored
[E] No function: shape registered for opset: 11
[W] colored module is not installed, will not use colors when logging. To enable colors, please install the colored module: python3 -m pip install colored
[E] No function: len registered for opset: 11

但是没有红色显示

清华园好像不能安装了,用豆瓣的源可以安装:

pip install colored -i https://pypi.doubanio.com/simple

第7步按照作者的转换脚本,开始的时候报错,代码:

  1. import onnx_graphsurgeon as gs
  2. import onnx
  3. import numpy as np
  4. def cutOnnx():
  5. onnx_save_path = "header.onnx"
  6. graph = gs.import_onnx(onnx.load(onnx_save_path))
  7. tensors = graph.tensors()
  8. tensor = tensors["218"]
  9. graph.inputs = [graph.inputs[-1], tensor.to_variable(dtype=np.float32, shape=('N', 256, 7, 7))]
  10. graph.inputs[-1].name = "roialigned_feature"
  11. graph.outputs = [graph.outputs[0], graph.outputs[-1]]
  12. shape_score = gs.Constant(name="shape_score", values=np.array((-1, 90), dtype=np.int64))
  13. shape_boxes = gs.Constant(name="shape_boxes", values=np.array((-1, 90, 4), dtype=np.int64))
  14. shape_boxes_last_node = gs.Constant(name="shape_boxes_last_node", values=np.array((-1, 91, 4), dtype=np.int64))
  15. # 这里的Reshape_320和Reshape_322是box和score的上一个reshape节点
  16. for node in graph.nodes:
  17. if node.name == "Reshape_320":
  18. node.inputs[-1] = shape_boxes
  19. elif node.name == "Reshape_322":
  20. node.inputs[-1] = shape_score
  21. # the last second reshape node relative to box output
  22. elif node.name == "Reshape_308":
  23. node.inputs[-1] = shape_boxes_last_node
  24. # 添加N,90,4 和 N,90,1的结点
  25. for item in graph.outputs:
  26. item.shape.insert(1, 90)
  27. # print(item.shape)
  28. for graph_output in graph.outputs:
  29. graph_output.shape[0] = 'N'
  30. graph.cleanup()
  31. new_onnx_filepath = 'new_'+onnx_save_path
  32. onnx.save(gs.export_onnx(graph), new_onnx_filepath)
  33. import onnxsim
  34. model = onnx.load(new_onnx_filepath)
  35. # convert model
  36. model_simp, check = onnxsim.simplify(model, check_n=0,input_shapes={'roialigned_feature':[1,256, 7, 7],'proposals':[1,4]},
  37. dynamic_input_shape=True)
  38. onnx.save(model_simp, new_onnx_filepath)
  39. if __name__ == '__main__':
  40. cutOnnx()

报错: 

tensor = tensors["218"]
KeyError: '218'

torch换到作者的版本1.10,这个报错没有了。

修改了一下,支持批量预测:

  1. import onnx_graphsurgeon as gs
  2. import onnx
  3. import numpy as np
  4. def cutOnnx():
  5. onnx_save_path = "header.onnx"
  6. graph = gs.import_onnx(onnx.load(onnx_save_path))
  7. tensors = graph.tensors()
  8. for key, value in tensors.items():
  9. print(key , value)
  10. # tensor = tensors["onnx::Reshape_325"]
  11. tensor = tensors["218"]
  12. graph.inputs = [graph.inputs[-1], tensor.to_variable(dtype=np.float32, shape=('batch_size', 256, 7, 7))]
  13. graph.inputs[-1].name = "roialigned_feature"
  14. graph.outputs = [graph.outputs[0], graph.outputs[-1]]
  15. shape_score = gs.Constant(name="shape_score", values=np.array((-1, 90), dtype=np.int64))
  16. shape_boxes = gs.Constant(name="shape_boxes", values=np.array((-1, 90, 4), dtype=np.int64))
  17. shape_boxes_last_node = gs.Constant(name="shape_boxes_last_node", values=np.array((-1, 91, 4), dtype=np.int64))
  18. # 这里的Reshape_320和Reshape_322是box和score的上一个reshape节点
  19. for node in graph.nodes:
  20. if node.name == "Reshape_320":
  21. node.inputs[-1] = shape_boxes
  22. elif node.name == "Reshape_322":
  23. node.inputs[-1] = shape_score
  24. # the last second reshape node relative to box output
  25. elif node.name == "Reshape_308":
  26. node.inputs[-1] = shape_boxes_last_node
  27. # 添加N,90,4 和 N,90,1的结点
  28. for item in graph.outputs:
  29. item.shape.insert(1, 90)
  30. # print(item.shape)
  31. for graph_output in graph.outputs:
  32. graph_output.shape[0] = 'N'
  33. graph.cleanup()
  34. new_onnx_filepath = 'new_'+onnx_save_path
  35. onnx.save(gs.export_onnx(graph), new_onnx_filepath)
  36. import onnxsim
  37. model = onnx.load(new_onnx_filepath)
  38. # convert model
  39. model_simp, check = onnxsim.simplify(model, check_n=0,input_shapes={'roialigned_feature':[-1,256, 7, 7],'proposals':[-1,4]},
  40. dynamic_input_shape=True)
  41. onnx.save(model_simp, new_onnx_filepath)
  42. if __name__ == '__main__':
  43. cutOnnx()

第8步测试

  1. import onnxruntime as rt
  2. import numpy as np
  3. if __name__ == '__main__':
  4. sess = rt.InferenceSession('new_header.onnx')
  5. input_names = [item.name for item in sess.get_inputs()]
  6. output_names = [item.name for item in sess.get_outputs()]
  7. # proposal = np.array([1,1,10,10], dtype=np.float32).reshape(-1, 4)
  8. batch_size = 1
  9. input_dict = dict(
  10. proposals = np.random.randn(batch_size, 4).astype(dtype=np.float32),
  11. roialigned_feature = np.random.randn(batch_size, 256, 7, 7).astype(dtype=np.float32)
  12. )
  13. pred_onnx = sess.run(output_names, input_dict)
  14. pred_onnx = dict(zip(output_names, pred_onnx))
  15. print(pred_onnx['boxes'].shape)
  16. # print(pred_onnx['boxes'])
  17. print(pred_onnx['scores'].shape)
  18. # print(pred_onnx['scores'])

结果bath_size为1时正确,大于1就报错。

输入两个参数:proposals 和roialigned_feature

维度为 batch_size,4

和batch_size,256, 7, 7

输出:

(1, 90, 4)
(1, 90)

onnx转trt操作

c++ 转换trt:

builder\trt_builder.cpp

报错代码:

 void set_layer_hook_reshape(const LayerHookFuncReshape& func){
        //register_layerhook_reshape(func);
    }

register_layerhook_reshape函数是在NvOnnxParser.cpp中,

OnnxParser代码是在生成的时候用,需要protobuf,版本未知,

protobuf-cpp-3.11.4

pytorch转onnx

开源项目给了转换代码:

test/x01export_FasterRCNN_onnx.py

onnx测试代码:

test/x02test_FasterRCNN_onnx.py

Onnx转trt代码及操作:

onnx转tensorrt 实战干货总结_AI视觉网奇的博客-CSDN博客_onnx转tensorrt

博客的目录:onnx转tensorrt 分类成功

转trt报错了

  1. [08/06/2022-11:35:29] [TRT] [E] [graphShapeAnalyzer.cpp::nvinfer1::builder::`anonymous-namespace'::ShapeNodeRemover::analyzeShapes::1285] Error Code 4: Miscellaneous (IShuffleLayer Reshape_1226: reshape changes volume. Reshaping [720588174] to [1,4507].)
  2. Completed parsing of ONNX file
  3. Building an engine from file F:\project\jushi\tensorrt-onnx-fasterrcnn-fpn-roialign-master\test\fasterrcnn_backbone_resnet50_fpn_roialign.onnx; this may take a while...
  4. [08/06/2022-11:35:29] [TRT] [E] 4: [network.cpp::nvinfer1::Network::validate::2633] Error Code 4: Internal Error (Network must have at least one output)

解决方法,手动设置最后一层:

      last_layer = network.get_layer(network.num_layers - 1)
        network.mark_output(last_layer.get_output(0))

代码:

  1. def ONNX_build_engine(onnx_file_path, write_engine=True):
  2. # 通过加载onnx文件,构建engine
  3. # :param onnx_file_path: onnx文件路径
  4. # :return: engine
  5. G_LOGGER = trt.Logger(trt.Logger.WARNING)
  6. # 1、动态输入第一点必须要写的
  7. explicit_batch = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
  8. batch_size = 8 # trt推理时最大支持的batchsize
  9. with trt.Builder(G_LOGGER) as builder, builder.create_network(explicit_batch) as network, trt.OnnxParser(network, G_LOGGER) as parser:
  10. builder.max_batch_size = batch_size
  11. config = builder.create_builder_config()
  12. config.max_workspace_size = GiB(2)
  13. config.set_flag(trt.BuilderFlag.FP16)
  14. print('Loading ONNX file from path {}...'.format(onnx_file_path))
  15. with open(onnx_file_path, 'rb') as model:
  16. print('Beginning ONNX file parsing')
  17. parser.parse(model.read())
  18. print('Completed parsing of ONNX file')
  19. print('Building an engine from file {}; this may take a while...'.format(onnx_file_path))
  20. # 重点
  21. profile = builder.create_optimization_profile() # 动态输入时候需要 分别为最小输入、常规输入、最大输入
  22. # 有几个输入就要写几个profile.set_shape 名字和转onnx的时候要对应
  23. # tensorrt6以后的版本是支持动态输入的,需要给每个动态输入绑定一个profile,用于指定最小值,常规值和最大值,如果超出这个范围会报异常。
  24. profile.set_shape("inputs", (1, 3, 600, 600), (8, 3, 600, 600), (16, 3, 600, 600))
  25. config.add_optimization_profile(profile)
  26. last_layer = network.get_layer(network.num_layers - 1)
  27. network.mark_output(last_layer.get_output(0))
  28. engine = builder.build_engine(network, config)
  29. print("Completed creating Engine")
  30. # 保存engine文件
  31. if write_engine:
  32. engine_file_path = 'efficientnet_b1.trt'
  33. with open(engine_file_path, "wb") as f:
  34. f.write(engine.serialize())
  35. return engine

但是维度不能对齐:

ShapeNodeRemover::analyzeShapes::1285] Error Code 4: Miscellaneous (IShuffleLayer Reshape_1226: reshape changes volume. Reshaping [720588174] to [1,4507].)

torch升级版本后,转trt报错变成了:
Error Code 9: Internal Error (Floor_45: IUnaryLayer cannot be used to compute a shape tensor)

  1. backbone部分可以转trt
  2. rpn_backbone_resnet50.onnx

c++ tensorrt推理部分

c++onnx转tensorrt

也可以python转,

onnx生成tensorrt的时候,用的自带的代码,自带的,需要protobuf,

“google/protobuf/port_def.inc”:

官方的faster rcnn导出trt报错:

reshape changes volume. Reshaping [720588174] to [1,4507].)

fasterrcnn.cpp:

缩放尺寸,归一化:

virtual bool preprocess(Job& job, const Mat& image) override{

打印模型输入输出参数:

void InferImpl::print(){

xxxxx

}

宽800,高608,宽高比和car图片相反。

推理报错:

sub_model推理报错:
[][error][trt_builder.cpp:30]:NVInfer: 3: [executionContext.cpp::nvinfer1::rt::ExecutionContext::setBindingDimensions::944] Error Code 3: API Usage Error (Parameter check failed at: executionContext.cpp::nvinfer1::rt::ExecutionContext::setBindingDimensions::944, condition: profileMaxDims.d[i] >= dimensions.d[i]. Supplied binding dimension [787,256,7,7] for bindings[1] exceed min ~ max range at index 0, maximum dimension in profile is 1, minimum dimension in profile is 1, but supplied dimension is 787.
)

787是anchors的数量:new_header需要的为1。

int number_anchors = roi_align_inputs_index / 6; 

感觉就是backbone和new_header的维度没对上。

new_header.onnx

tensorrt推理:

app_fasterrcnn\fasterrcnn.cpp

  1. //forward
  2. engine->forward(false);
  3. engine->synchronize();

infer\trt_infer.cpp

bool execute_result = context->context_->enqueueV2

N和bach_size是一样的。

可以忽略的报错:

WARNING: The shape inference of prim::Constant type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function.
WARNING: The shape inference of prim::Constant type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function.

TracerWarning: Iterating over a tensor might cause the trace to be incorrect. Passing a tensor of different shape won't change the number of iterations executed (and might lead to errors or silently give incorrect results).

相关文章