一、pth导出onnx

# import torch
# import torchvision
#
# dummy_input = torch.randn(1, 3, 94, 24, device='cuda')
# model = torch.load("./weights/Final_LPRNet_model_down.pth")
#
# input_names = ["input_1"]
# output_names = ["output_1"]
#
# torch.onnx.export(model, dummy_input, "lpr.onnx", verbose=True, input_names=input_names, output_names=output_names)from data.load_data import CHARS
import torch
import torch.onnx
from model.LPRNet import build_lprnet
import osdef pth_to_onnx(input, checkpoint, onnx_path, input_names=['input'], output_names=['output'], device='cpu'):if not onnx_path.endswith('.onnx'):print('Warning! The onnx model name is not correct,\please give a name that ends with \'.onnx\'!')return 0model = build_lprnet(lpr_max_len=8, phase=False, class_num=len(CHARS), dropout_rate=0)    # 导入模型model.load_state_dict(torch.load(checkpoint))  # 初始化权重model.eval()# model.to(device)torch.onnx.export(model, input, onnx_path, verbose=True, input_names=input_names,output_names=output_names)  # 指定模型的输入,以及onnx的输出路径print("Exporting .pth model to onnx model has been successful!")if __name__ == '__main__':# os.environ['CUDA_VISIBLE_DEVICES'] = '2'checkpoint = './weights/Final_LPRNet_model_down.pth'onnx_path = './weights/Final_LPRNet_model_down.onnx'input = torch.randn(1, 3, 24, 94)# device = torch.device("cuda:2" if torch.cuda.is_available() else 'cpu')pth_to_onnx(input, checkpoint, onnx_path)

二、onnx在nvidia nx上推理
报错:

$ ./pro dclassifier
[2022-03-21 16:59:22][info][trt_builder.cpp:474]:Compile FP32 Onnx Model 'Final_LPRNet_model_down.onnx'.
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: 3: MaxPool_3: at least 5 dimensions are required for input.
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: 3: MaxPool_3: at least 5 dimensions are required for input.
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: 3: MaxPool_3: at least 5 dimensions are required for input.
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: 3: MaxPool_3: at least 5 dimensions are required for input.
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: 3: MaxPool_3: at least 5 dimensions are required for input.
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: /data/tmp-0121/tensorRT_Pro-main-ys/src/tensorRT/onnx_parser/ModelImporter.cpp:736: While parsing node number 4 [Conv -> "67"]:
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: /data/tmp-0121/tensorRT_Pro-main-ys/src/tensorRT/onnx_parser/ModelImporter.cpp:737: --- Begin node ---
[2022-03-21 16:59:27][error][trt_builder.cpp:30]:NVInfer: /data/tmp-0121/tensorRT_Pro-main-ys/src/tensorRT/onnx_parser/ModelImporter.cpp:738: input: "66

原因是MaxPool3d输出是5维,现在模型是4维。但是不知道为什么python训练和测试时4维都不报错,估计是底层代码会自动加一个维度,但是推理的代码不支持。
解决方法一:想着把MaxPool3d改成MaxPool2d,行不通。
参考:https://blog.csdn.net/yrwang_xd/article/details/106556571
MaxPool3d是在其中3个维度上池化,MaxPoo2d是在其中3个维度上池化,查看模型是用到了在3个维度上池化。
解决方法二:导出时在MaxPool3d前增加一个维度,后减少一个维度。
增加和减少维度也有三种方法:

x= torch.reshape(x, x.shape)
x = x.view(x.size(0), -1)
x = x.unsqueeze(0)

试了reshape和view,导出的onnx模型用netron查看模型时对应很多层,而且有可能把矩阵里的数据打乱(怀疑reshape等操作会重新打乱数据),所以最后采用unsqueeze增加一个维度,squeeze减少一个维度。
参考:https://www.cnblogs.com/traditional/p/12629050.html
改完后的LPRNet.py部分代码如下:

class LPRNet(nn.Module):def __init__(self, lpr_max_len, phase, class_num, dropout_rate):super(LPRNet, self).__init__()self.phase = phaseself.lpr_max_len = lpr_max_lenself.class_num = class_numself.backbone = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1), # 0nn.BatchNorm2d(num_features=64),nn.ReLU(),  # 2nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(1, 1, 1)),small_basic_block(ch_in=64, ch_out=128),    # *** 4 ***nn.BatchNorm2d(num_features=128),nn.ReLU(),  # 6nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(2, 1, 2)),small_basic_block(ch_in=64, ch_out=256),   # 8nn.BatchNorm2d(num_features=256),nn.ReLU(),  # 10small_basic_block(ch_in=256, ch_out=256),   # *** 11 ***nn.BatchNorm2d(num_features=256),   # 12nn.ReLU(),nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(4, 1, 2)),  # 14nn.Dropout(dropout_rate),nn.Conv2d(in_channels=64, out_channels=256, kernel_size=(1, 4), stride=1),  # 16nn.BatchNorm2d(num_features=256),nn.ReLU(),  # 18nn.Dropout(dropout_rate),nn.Conv2d(in_channels=256, out_channels=class_num, kernel_size=(13, 1), stride=1), # 20nn.BatchNorm2d(num_features=class_num),nn.ReLU(),  # *** 22 ***)self.container = nn.Sequential(nn.Conv2d(in_channels=448+self.class_num, out_channels=self.class_num, kernel_size=(1, 1), stride=(1, 1)),# nn.BatchNorm2d(num_features=self.class_num),# nn.ReLU(),# nn.Conv2d(in_channels=self.class_num, out_channels=self.lpr_max_len+1, kernel_size=3, stride=2),# nn.ReLU(),)def forward(self, x):keep_features = list()for i, layer in enumerate(self.backbone.children()):if 'MaxPool3d' in str(layer):print()# x1= torch.reshape(x, x.shape)# x1 = x.view(x.size(0), -1)x = x.unsqueeze(0)x = layer(x)x = x.squeeze(0)else:x = layer(x)if i in [2, 6, 13, 22]: # [2, 4, 8, 11, 22]keep_features.append(x)global_context = list()for i, f in enumerate(keep_features):if i in [0, 1]:f = nn.AvgPool2d(kernel_size=5, stride=5)(f)if i in [2]:f = nn.AvgPool2d(kernel_size=(4, 10), stride=(4, 2))(f)f_pow = torch.pow(f, 2)f_mean = torch.mean(f_pow)f = torch.div(f, f_mean)global_context.append(f)x = torch.cat(global_context, 1)x = self.container(x)logits = torch.mean(x, dim=2)return logits

三、后处理代码
参考:https://github.com/szad670401/HyperLPR,修改https://github.com/shouxieai/tensorRT_Pro/tree/main/src/direct/direct_classifier.cpp

int direct_classifier(){std::vector<std::string> mapping_table{"京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑","苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤","桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁","新","0", "1", "2", "3", "4", "5", "6", "7", "8", "9","A", "B", "C", "D", "E", "F", "G", "H", "J", "K","L", "M", "N", "P", "Q", "R", "S", "T", "U", "V","W", "X", "Y", "Z", "I", "O", "-"};if(!iLogger::exists("Final_LPRNet_model_down.onnx")){INFOE("Final_LPRNet_model_down.onnx not found, reference: https://github.com/shouxieai/tensorrt-pro-sample-python-classifier");return -1;}TRT::set_device(0);if(!iLogger::exists("Final_LPRNet_model_down.trtmodel")){TRT::compile(TRT::Mode::FP32,1,"Final_LPRNet_model_down.onnx", "Final_LPRNet_model_down.trtmodel");INFO("Compile done");}auto engine = TRT::load_infer("Final_LPRNet_model_down.trtmodel");if(engine == nullptr){INFOE("Engine is nullptr");return -1;} auto image = cv::imread("chepai1.jpg");float mean[] = {0., 0., 0.};float std[]  = {1., 1., 1.};int sequencelength =18;int labellength = 68;engine->input()->set_norm_mat(0, image, mean, std);engine->forward();auto output = engine->output(0);for(int i = 0; i < output->count(); ++i){INFO("output[%d] = %f", i, output->cpu<float>()[i]);}// auto output_1 = engine->output(1);// for(int i = 0; i < output_1->count(); ++i)// {//      INFO("output[%d] = %f", i, output_1->cpu<float>()[i]);// }float q[1224];for(int i=0;i<18;i++){for(int j=0;j<68;j++){q[i*68+j]=output->cpu<float>()[18*j+i];}}std::string name = "";std::vector<int> seq(sequencelength);std::vector<std::pair<int,float>> seq_decode_res;for(int i = 0 ; i < sequencelength;  i++) {float *fstart = ((float *) q+ i * labellength );int id = std::max_element(fstart,fstart+labellength) - fstart;seq[i] =id;INFO("id = %d", id);name+=mapping_table[id];}std::cout<<name<<'\t';return 0;
}

车牌识别lpr tenssorrt推理(二)相关推荐

  1. 汽车车牌识别系统实现(二)--车牌定位+代码实现

    汽车车牌识别系统实现(二)-- 车牌定位 之前对这部分内容解释的不够详细,自己都看不下去了,因此重新编辑一下. 一.前言 车牌定位是汽车车牌识别能否取得成功的关键过程,车牌定位是否准确直接影响到后续的 ...

  2. 【深度学习模型】智云视图中文车牌识别源码解析(二)

    [深度学习模型]智云视图中文车牌识别源码解析(二) 感受 HyperLPR可以识别多种中文车牌包括白牌,新能源车牌,使馆车牌,教练车牌,武警车牌等. 代码不可谓不混乱(别忘了这是职业公司的准产品级代码 ...

  3. java车牌识别字符分割_车牌识别LPR(六)-- 字符分割

    第六篇:字符分割 在知道了车牌字符的规律之后,可以根据车牌的特点对字符进行分割.一般最容易想到的方法就是根据车牌投影.像素统计特征对车牌图像进行字符分割的方法.是一种最常用的.最基本的.最简单的车牌字 ...

  4. 车牌识别系统开发记录(二) 车牌定位

    这里面我要具体介绍的检测车牌方法的步骤如下: 首先利用Sobel滤波器对灰度图像进行滤波,突出图像中的垂直边缘信息 利用数学形态学方法: Close(先膨胀再腐蚀,填充内部空隙) 利用findCont ...

  5. NVIDIA中文车牌识别系列-3:使用TLT训练车牌号识别LPR模型

    预先准备 在开始建立和部署 TLT 中高准确率的车辆训练模型时,需要以下资源: NGC 账号 DeepStream SDK 我们将使用 TLT 进行训练 pip3 install nvidia-pyi ...

  6. 用于提高车牌识别的单幅噪声图像去噪和校正

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 下面要介绍的论文始发于ICCV2019,题为「SNIDER: Si ...

  7. 如何选择智能车牌识别摄像机

    当今,车牌识别相机广泛地应用在智能交通管理系统中,对车辆管理发挥了巨大的作用.众所周知,车牌识别(LPR)系统是以图像处理.模式识别等技术为基础的智能识别系统,通过摄像机拍摄道路上行驶的车辆,形成图像 ...

  8. 毕业设计-基于 MATLAB 的车牌识别系统设计

    目录 前言 课题背景和意义 实现技术思路 一.车牌识别系统总体方案设计 二.车牌识别系统硬件设计 三.车牌识别系统软件设计 四. 实验结果与分析 部分源代码 实现效果图样例 最后 前言

  9. 基于 SoC 的卷积神经网络车牌识别系统设计(4-2)基于 Verilog 的 RGB2HSV IP 设计

    引言         这是车牌识别预处理(RGB2HSV + 二值化 + 形态学)的 IP 设计之一.主要功能是针对从 OV5640 IP 输出的 RGB888 真彩色车牌识别数据(视频传输格式:64 ...

最新文章

  1. JDK5中的控制台输入
  2. 常见的前端vue面试题
  3. mfc制作登录界面mysql_MFC制作漂亮界面之登录界面
  4. String.valueOf()方法与toString()方法的区别
  5. leetcode 有效的字母异位词
  6. java冒泡排序及面向对象基本概念
  7. UPCOJ-5344 - 被子 - 瞎搞
  8. Cisco服务器硬盘状态jbod,如何为服务器硬盘配置RAID或JBOD模式
  9. 单电机板机模型,f22
  10. royer推挽自激电路
  11. turtle绘制皮卡丘
  12. 太原学院计算机科学与技术在哪个校区,太原学院有几个校区及校区地址
  13. 【C#】分享一个可携带附加消息的增强消息框MessageBoxEx
  14. ElasticSearch文档过期时间设置
  15. 《经典算法案例》01-10:如何打印质数表(六列版)
  16. 派盘与百度云同步盘哪家强?
  17. 蓝桥杯单片机省赛题目《全集》之第十届省赛
  18. webpack多页面打包
  19. theme vscode 护眼_vscode设置护眼主题
  20. 编程与哲学的奇妙联系

热门文章

  1. SMG、东方明珠新媒体战略推进一周年;百度营销联合多品牌方举办开放麦;驭势科技推出自动驾驶新产品UiBox | 全球TMT...
  2. MySQL 数据表优化设计(九):如何设计统计数据表?
  3. JAVA 建造者模式
  4. 技嘉b365dv3主板黑苹果efi_黑苹果--技嘉 z390 gaming X 究极方案
  5. Oxygen Not Included
  6. Linux大家族的血缘关系
  7. tensorflow代码学习:CTC 代码解析
  8. 富途php面试经验,忍不住想吐槽一下富途二面体验
  9. 李飞飞团队新研究登Nature子刊!实现可信 AI,数据的设计、完善、评估是关键!...
  10. 用计算机处理信息 说课,《信息和信息处理工具》说课稿范文