上一篇博文撰写了关于pointpillars算法的pytorch模型如何转换为onnx模型中间件,具体参考此链接:pointpillars点云算法TensorRT环境加速系列一以此来方便TensorRT进行加载解析优化模型。接下来,我们在完成第一步模型成功从pytorch模型转换成为onnx之后,需要验证onnx模型转换之后的精度与原始的pytorch模型精度差多少。
Attention: 环境与代码与第一篇一致
或者你可以参考我的github上ReadMe,里面有具体的步骤关于如何测试onnx模型的精度对比,传送门点击此链接。
首先,我们对第一个onnx模型pfe.onnx与原始pytorch模型对于pfe层的网络输出结果进行对比,需要将输入对应一致进行检查:
以下为onnx模型预测pfe.onnx模型输出的主要代码部分: 简单说下:输入分别为pillar_x、pillar_y、pillar_z、pillar_i、num_points_per_pillar、x_sub_shaped、y_sub_shaped、mask总共8个张量作为输入,同时需要主要每个张量的device设置,我这边通过打印原始的输出device进行手动添加以此来对应上。
def onnx_model_predict(config_path=None, model_dir=None): import onnxruntime from second.pytorch.models.pointpillars import PillarFeatureNet, PointPillarsScatter # check the pfe onnx model IR input paramters as follows pillar_x = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") pillar_y = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") pillar_z = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") pillar_i = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") num_points_per_pillar = torch.ones([1, 12000], dtype=torch.float32, device="cuda:0") x_sub_shaped = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") y_sub_shaped = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") mask = torch.ones([1, 1, 12000, 100], dtype=torch.float32, device="cuda:0") pfe_session = onnxruntime.InferenceSession("pfe.onnx") # Compute ONNX Runtime output prediction pfe_inputs = {pfe_session.get_inputs()[0].name: (pillar_x.data.cpu().numpy()), pfe_session.get_inputs()[1].name: (pillar_y.data.cpu().numpy()), pfe_session.get_inputs()[2].name: (pillar_z.data.cpu().numpy()), pfe_session.get_inputs()[3].name: (pillar_i.data.cpu().numpy()), pfe_session.get_inputs()[4].name: (num_points_per_pillar.data.cpu().numpy()), pfe_session.get_inputs()[5].name: (x_sub_shaped.data.cpu().numpy()), pfe_session.get_inputs()[6].name: (y_sub_shaped.data.cpu().numpy()), pfe_session.get_inputs()[7].name: (mask.data.cpu().numpy())} pfe_outs = pfe_session.run(None, pfe_inputs) print('-------------------------- PFE ONNX Outputs ----------------------------') print(pfe_outs) # also you could save it to file for comparing print('-------------------------- PFE ONNX Ending ----------------------------')看过主要的预测pfe.onnx代码之后,我们来对比一下结果:左边为原始pytorch模型关于pfe-layer的张量输出结果,右边为pfe.onnx模型的输出结果,可以看到输出误差在小数点后三位级别。
接下来,我们来主要对比一下rpn.onnx模型的输出与pytorch模型进过rpn网络的输出进行对比。由于rpn网络之前并不是直接接入pfe网络的输出,中间进过pillarscatter网络,所以针对验证输入输出不可以单独抛开pfe网络层。当然,你也可以直接读取pfe层的输出,通过pillarscatter网络后,接入rpn网络来查看输出进行对比。
以下为预测rpn.onnx主要部分代码,包括rpn网络输入连接pillarscatter网络的输出,这样也连接上pfe网络的输出,具体代码如下:
def onnx_model_predict(config_path=None, model_dir=None): import onnxruntime from second.pytorch.models.pointpillars import PillarFeatureNet, PointPillarsScatter # check the rpn onnx model IR input paramters as follows pillar_x = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") pillar_y = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") pillar_z = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") pillar_i = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") num_points_per_pillar = torch.ones([1, 9918], dtype=torch.float32, device="cuda:0") x_sub_shaped = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") y_sub_shaped = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") mask = torch.ones([1, 1, 9918, 100], dtype=torch.float32, device="cuda:0") pfe_session = onnxruntime.InferenceSession("pfe.onnx") # Compute ONNX Runtime output prediction pfe_inputs = {pfe_session.get_inputs()[0].name: (pillar_x.data.cpu().numpy()), pfe_session.get_inputs()[1].name: (pillar_y.data.cpu().numpy()), pfe_session.get_inputs()[2].name: (pillar_z.data.cpu().numpy()), pfe_session.get_inputs()[3].name: (pillar_i.data.cpu().numpy()), pfe_session.get_inputs()[4].name: (num_points_per_pillar.data.cpu().numpy()), pfe_session.get_inputs()[5].name: (x_sub_shaped.data.cpu().numpy()), pfe_session.get_inputs()[6].name: (y_sub_shaped.data.cpu().numpy()), pfe_session.get_inputs()[7].name: (mask.data.cpu().numpy())} pfe_outs = pfe_session.run(None, pfe_inputs) # print('-------------------------- PFE ONNX Outputs ----------------------------') # print(pfe_outs) # also you could save it to file for comparing # print('-------------------------- PFE ONNX Ending ----------------------------') ##########################Middle-Features-Extractor######################### # numpy --> tensor pfe_outs = np.array(pfe_outs) voxel_features_tensor = torch.from_numpy(pfe_outs) voxel_features = voxel_features_tensor.squeeze() # voxel_features = np.array(pfe_outs).squeeze() voxel_features = voxel_features.permute(1, 0) if isinstance(config_path, str): config = pipeline_pb2.TrainEvalPipelineConfig() with open(config_path, "r") as f: proto_str = f.read() text_format.Merge(proto_str, config) else: config = config_path model_cfg = config.model.second vfe_num_filters = list(model_cfg.voxel_feature_extractor.num_filters) voxel_generator = voxel_builder.build(model_cfg.voxel_generator) grid_size = voxel_generator.grid_size output_shape = [1] + grid_size[::-1].tolist() + [vfe_num_filters[-1]] num_input_features = vfe_num_filters[-1] batch_size = 2 mid_feature_extractor = PointPillarsScatter(output_shape, num_input_features, batch_size) device = torch.device("cuda:0") coors_numpy = np.loadtxt('./onnx_predict_outputs/coors.txt', dtype=np.int32) coors = torch.from_numpy(coors_numpy) coors = coors.to(device).cuda() # CPU Tensor --> GPU Tensor voxel_features = voxel_features.to(device).cuda() rpn_input_features = mid_feature_extractor(voxel_features, coors) #################################RPN-Feature-Extractor######################################## # rpn_input_features = torch.ones([1, 64, 496, 432], dtype=torch.float32, device='cuda:0') rpn_session = onnxruntime.InferenceSession("rpn.onnx") # compute RPN ONNX Runtime output prediction rpn_inputs = {rpn_session.get_inputs()[0].name: (rpn_input_features.data.cpu().numpy())} rpn_outs = rpn_session.run(None, rpn_inputs) print('---------------------- RPN ONNX Outputs ----------------------') print(rpn_outs) print('---------------------- RPN ONNX Ending ----------------------')当然,rpn-layer层对比rpn.onnx操作对比输出的精度差,如下可以查看,误差系数在小数点3位之后:
到此,验证pointpillars算法pytorch模型转换成为pfe.onnx与rpn.onnx精度对比基本完成。具体的代码将会在我的github上面进行更新,目前结果来看模型转换成功,下一篇将会将其使用TensorRT进行加速来对比一下经过TensorRT优化加速之后,效率提升了多少,敬请期待。
https://github.com/SmallMunich/nutonomy_pointpillars
https://blog.csdn.net/Small_Munich/article/details/101559424
https://arxiv.org/abs/1812.05784
