• fasterrcnn tensorrt部署实践


    目录

    环境安装:

    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

    本部分基于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是不一样的, 4390*6,步骤3的结果是1000*6

    第四步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()

    结果:

    #0 Variable (rpn_boxes): (shape=[1, 4390, 6], dtype=float32)
    # 0 Variable (feature_0): (shape=[1, 256, 152, 200], dtype=float32)
    # 0 Variable (feature_1): (shape=[1, 256, 76, 100], dtype=float32)
    # 0 Variable (feature_2): (shape=[1, 256, 38, 50], dtype=float32)
    # 0 Variable (feature_3): (shape=[1, 256, 19, 25], dtype=float32)
    # 1 Variable (rpn_boxes): (shape=[1, 4390, 6], dtype=float32)
    # 1 Variable (feature_0): (shape=[1, 256, 152, 200], dtype=float32)
    # 1 Variable (feature_1): (shape=[1, 256, 76, 100], dtype=float32)
    # 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操作进行处理

    2. 对应一下几行代码

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

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

    backbone部分可以转trt:
    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是一样的。

  • 相关阅读:
    qt在不同的线程中传递自定义结构体参数
    基于UE4 的AirSim虚拟仿真
    Linux面试常考命令
    计算机视觉与深度学习 | 视觉惯性SLAM的基础理论
    [附源码]java毕业设计校园博客系统
    [附源码]计算机毕业设计JAVA基于ssm的电子网上商城
    Android 面经总结分享(相当走心)
    若依前端vue设置子路径
    深度剖析Java的volatile实现原理,再也不怕面试官问了
    MongoDB数据库入门到精通看这一篇就够了
  • 原文地址:https://blog.csdn.net/jacke121/article/details/126191184