上海网站建设公司电话,wordpress站点费用,好用的在线设计网站,免费图片链接生成器如果还未配置TensorRT#xff0c;请看这篇博文#xff1a;Win11下TensorRT环境部署
这里使用TensorRT对Yolov5进行部署流程比较固定#xff1a;先将pt模型转换为onnx#xff0c;再将onnx模型转为engine#xff0c;所以在执行export.py时要将onnx、engine给到include。
P…如果还未配置TensorRT请看这篇博文Win11下TensorRT环境部署
这里使用TensorRT对Yolov5进行部署流程比较固定先将pt模型转换为onnx再将onnx模型转为engine所以在执行export.py时要将onnx、engine给到include。
PT模型转换为ONNX模型
PT模型地址
方法一
python path/to/export.py --weights yolov5s.pt --include torchscript onnx coreml saved_model pb tflite tfjs方法二 我们可以看到
–weight 使用的是我们需要优化的权重我这里yolov5s.pt为例–opset 这里的参数如果你报错的话可以试着改小一点–include 填写的是我们第一步生成的onnx文件
下面我们介绍以下ONNX的构建流程 这里介绍一下其中每个参数的含义
model就是需要转为ONNX的pth模型只有源模型的结构和权重才能转化为有效的ONNX模型。model.cpu() if dynamic else model如果启用了动态模式dynamicTrue则将模型转移到CPU上进行导出否则使用原始的模型。im.cpu() if dynamic else im: 如果启用了动态模式将输入张量转移到CPU上进行导出否则使用原始的输入张量。 为什么要把模型和输入数据转移到CPU上 CPU 是所有计算环境中最通用和兼容的硬件。当你将一个模型导出为一个通用格式如 ONNX目的通常是确保它可以在不同的环境和硬件上运行。使用 CPU 可以确保最大程度的兼容性因为不是所有的环境都有 GPU 支持。这有助于确保模型能够在各种不同的硬件和软件环境中一致和可靠地工作。 f这是输出文件的路径或文件对象表示ONNX模型应该保存的位置verbose False这个参数控制是否打印出详细的导出信息opset_versionopset指定ONNX的操作集版本不同的版本的ONNX支持不同的特性集do_constant_foldingTrue控制是否进行常量折叠。表示常量折叠优化默认为 False。如果为 True则在导出时进行常量折叠优化。常量折叠优化将用预先计算的常量节点来替换那些所有都是常量输入的操作在torch1.12版本中进行DNN推理可能需要将do_constant_folding设置为False。这是因为在这个版本中对一些操作进行了更多的优化。input_names[‘images’]: 定义输入节点的名称。output_namesoutput_names: 定义输出节点的名称列表。dynamic_axesdynamic or None: 如果 dynamic 为真则启用动态轴特性。动态轴允许模型在不同的推理请求中处理不同大小的输入。keep_initializers_as_inputs默认为 None。如果为 True那么就导出图中的所有初始值的设定项一般对应到参数最后也会作为输入添加到图中。如果为 False那么初始值的设定项就不会作为输入添加到图中而只是将非参数作为输入进行添加。custom_opsets用于在导出时指示自定义 opset 域和版本的字典。如果模型包含自定义的操作集那么就可以选择在字典中指定域和操作集版本其中KEY为操作集域名它的 VALUE为操作集版本。注意的是如果在这个字典中没有提供自定义的操作集那么操作集版本就默认设置为1。enable_onnx_checker默认为 True。如果为 Trueonnx 模型检查器将作为导出的一部分运行以确保导出的模型是没有问题的 ONNX 模型。use_external_data_format默认为 False。如果为 True那么模型就会以 ONNX 外部数据格式导出比方说有些模型的参数是存储在二进制文件中的而不是存储在 ONNX 模型文件中。
onnxsim的使用 如果要精简onnx就可以将simplify设置为True。设置为True就会调用onnxsim来对原来onnx去除不必要的op操作也叫去除胶水在使用之前需要安装onnx-simplifer。
精简完之后可以把简化前和简化后的模型放进netron看优化了哪些地方。netron 就是一个网络结构的可视化神器。我们可以通过它来查看网络的结构。因为这里的模型太大会占用较长的篇幅所以本文就不展示了。
构建TensorRT引擎
构建完onnx后就开始从onnx转为engine。在TensorRT上主要存在以下几个对象
builder用于创建 config、network、engine 等其它对象。network在其它框架的模型解析之后就会被用于填充到网络 network中去。config主要用于配置builder。OnnxParser用于解析onnx的模型文件对 ONNX 进行解析并填充到 tensorrt network 的结构当中。engine根据特定的config 与特定的硬件上编译出来的引擎只能应用于特定的 config 与硬件上。此外引擎可以持久化保存到本地以节省下次使用时不必要的编译时间。engine 集成了模型结构、模型参数 与可以实现最优计算 的kernel 配置。但是于此同时engine 与硬件和 TensorRT的版本有着强绑定所以要求进行engine编译与执行的硬件上的TensorRT 版本要保持一致。engine根据特定的config 与特定的硬件上编译出来的引擎只能应用于特定的 config 与硬件上。此外引擎可以持久化保存到本地以节省下次使用时不必要的编译时间。engine 集成了模型结构、模型参数 与可以实现最优计算 的kernel 配置。但是于此同时engine 与硬件和 TensorRT的版本有着强绑定所以要求进行engine编译与执行的硬件上的TensorRT 版本要保持一致。
LOGGER.info(f\n{prefix} starting export with TensorRT {trt.__version__}...)assert onnx.exists(), ffailed to export ONNX file: {onnx}f file.with_suffix(.engine) # TensorRT engine filelogger trt.Logger(trt.Logger.INFO)if verbose:logger.min_severity trt.Logger.Severity.VERBOSEbuilder trt.Builder(logger)config builder.create_builder_config()config.max_workspace_size workspace * 1 30# config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, workspace 30) # fix TRT 8.4 deprecation noticeflag (1 int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))network builder.create_network(flag)parser trt.OnnxParser(network, logger)if not parser.parse_from_file(str(onnx)):raise RuntimeError(ffailed to load ONNX file: {onnx})inputs [network.get_input(i) for i in range(network.num_inputs)]outputs [network.get_output(i) for i in range(network.num_outputs)]for inp in inputs:LOGGER.info(f{prefix} input {inp.name} with shape{inp.shape} {inp.dtype})for out in outputs:LOGGER.info(f{prefix} output {out.name} with shape{out.shape} {out.dtype})if dynamic:if im.shape[0] 1:LOGGER.warning(f{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument)profile builder.create_optimization_profile()for inp in inputs:profile.set_shape(inp.name, (1, *im.shape[1:]), (max(1, im.shape[0] // 2), *im.shape[1:]), im.shape)config.add_optimization_profile(profile)LOGGER.info(f{prefix} building FP{16 if builder.platform_has_fast_fp16 and half else 32} engine as {f})if builder.platform_has_fast_fp16 and half:config.set_flag(trt.BuilderFlag.FP16)with builder.build_engine(network, config) as engine, open(f, wb) as t:t.write(engine.serialize())return f, None推理代码
使用engine推理和使用pt推理的流程是大同小异的同样是使用detect.py。区别就在于model DetectMultiBackend(weights, devicedevice, dnndnn)中的weight是pt模型还是onnx模型还是engine模型
进入到DetectMultiBackend这个类中查看直接跳转【ctrl click】到构建engine的部分 elif engine: # TensorRTLOGGER.info(fLoading {w} for TensorRT inference...)import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-downloadcheck_version(trt.__version__, 7.0.0, hardTrue) # require tensorrt7.0.0if device.type cpu:device torch.device(cuda:0)Binding namedtuple(Binding, (name, dtype, shape, data, ptr))logger trt.Logger(trt.Logger.INFO)with open(w, rb) as f, trt.Runtime(logger) as runtime:model runtime.deserialize_cuda_engine(f.read())context model.create_execution_context()bindings OrderedDict()output_names []fp16 False # default updated belowdynamic Falsefor i in range(model.num_bindings):name model.get_binding_name(i)dtype trt.nptype(model.get_binding_dtype(i))if model.binding_is_input(i):if -1 in tuple(model.get_binding_shape(i)): # dynamicdynamic Truecontext.set_binding_shape(i, tuple(model.get_profile_shape(0, i)[2]))if dtype np.float16:fp16 Trueelse: # outputoutput_names.append(name)shape tuple(context.get_binding_shape(i))im torch.from_numpy(np.empty(shape, dtypedtype)).to(device)bindings[name] Binding(name, dtype, shape, im, int(im.data_ptr()))binding_addrs OrderedDict((n, d.ptr) for n, d in bindings.items())batch_size bindings[images].shape[0] # if dynamic, this is instead max batch size在进行前向推理时就会调用DetectMultiBackend的forward方法:
其中y返回的就是推理结果。这个结果会返回到detect.py中当detect.py捕获到结果之后就正常走目标检测的后处理流程了。
最后
–weight填写 yolov5s.onnx
–include 填写 engine
注如果输入.onnx生成engine报错的话可以直接在–weight填我们需要优化的权重
–include 直接填写engine因为直接生成engine的过程中也会升成一个.onnx。
参考链接
https://zhuanlan.zhihu.com/p/607601799
https://blog.csdn.net/m0_64524798/article/details/129187608