tensorrt_python_api 加速推理

TensorRT

前言

​ TensorRT是nvidia官方开源的加速推理框架,适用于流行的深度学习框架:pytorch、tensorflow、Caffe等。TensorRT(下面简称trt)需要与nvidia提供的显卡一起使用,没有nvidia的cuda无法使用。

  	提高部署推理的方法有2种,一种是训练过程中需要进行优化加速的,比如模型压缩、模型剪枝、量化、知识蒸馏,另外一种是训练完成后通过优化计算图结构,比如torch script、tf lite、trt、onnx等。

本章根据上一章的内容:MobileNet物体分类(https://blog.csdn.net/kui9702/article/details/123463075),对结果模型进行优化。如果有疑问可以评论区询问或者查看上一篇链接。

# 20220328    begin
    Pytorch Jit的原理
    1.Jit将动态图变为静态图推理达到加速的原理。pytorch 采用动态图机制,即每次进行前向推理时会自动构建反向传播计算图,
    之后会在反向传播的时候使用这个计算图,并且用完之后进行销毁。这虽然为我们提供调试debug的方便,
    但是每一次的调用,会将结果输送到python进程中。而图执行是直接在进程外添加编译步骤,将计算图的方式推送到内核级别
    ,在执行完毕之后不会返回到python进程(静态图),这样不方便调试。但是graph execution(静态图执行)
    会比eager execution(动态图执行)快。
    2.Jit拥有c++的api,利于部署,利于移植。
    
    TensorRT的加速原理
    1.TRT支持模型参数量化,支持INT8和FP16。由于模型在推理中,不一定需要很细的精度,比如FP32,所以可以通过量化参数为FP16甚至
    INT8减少计算开销达到加速的效果。
    2.对网络结构进行重构,包括运算合并,cuda加速,网络结构层合并的方式较少对cudnn api的调用,可以将部分结构层次合并为一个层次:
    比如conv bn relu层进行合并达到加速。
# 20220328 end

Trt安装

参考我的写的文章进行安装:(https://blog.csdn.net/kui9702/article/details/123563150)

Trt加速步骤

image-20220317232317556

  1. 根据自己的需求训练模型。
  2. 获得训练后的模型、模型需要保存网络结构与网络权重参数
  3. 将模型转化为onnx中间件(不知道onnx的可以百度,后期会出)
  4. 将onnx转化为trt
  5. 代码部署trt

pytorch推理

# 自定义数据集加载类
class PredictImageDataset(Dataset):
    def __init__(self, path, classes, iftrain=False):
        super(PredictImageDataset, self).__init__()
        self.transform = Compose([
            Resize((224, 224)),
            ToTensor(),
        ])
        self.iftrain = iftrain
        self.files = glob.glob(os.path.join(path, "*", "*.jpg"))
        self.classes = classes

    def __len__(self):
        return len(self.files)

    def __getitem__(self, idx):
        image_path = self.files[idx]
        image_name = os.path.basename(image_path)
        label_id = self.classes.index(image_name.split("_")[0])
        image = Image.open(image_path)
        img = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
        img = cv2.resize(img, (224, 224))
        image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        image = self.transform(image)
        return image, label_id, image_path

 
@timespend    # 之前写的时间装饰器
def predict(model, predict_path=r"./dataset/test_data"):
    # 加载测试集
    test_loader = DataLoader(PredictImageDataset(predict_path, classes=classes, iftrain=False), batch_size=1)
    total = 0
    for images, labels, images_path in tqdm(test_loader):
        images, labels = images.cuda(), labels.cuda()
        with torch.no_grad():
            # 模型预测
            outputs = model(images)
            print(outputs)
            _, pred = torch.max(outputs, 1)
            correct = torch.sum(labels == pred)
            total += correct

    print(f"correct percent : {float(total) / (len(test_loader.dataset))}")
    return float(total) / (len(test_loader.dataset))


def pytorch_python_predict(testpath):
    # MobileNet 训练cifar10 的模型
    model_path = r"/data/kile/other/Inception/model/40_0.8137084944659287.pth"
    # 加载模型
    model = torch.load(model_path).eval().cuda()
    # 开始预测
    predict(model, testpath)

很常规的模型推理,具体可以看代码描述

pytorch转onnx

import onnx
def torch2onnx(tensor_input=None):
	# 加载魔心
    model_path = r"/data/kile/other/Inception/model/40_0.8137084944659287.pth"
    model = torch.load(model_path).eval().cuda()
    # onnx模型输入
    if tensor_input is None:
        tensor_input = torch.randn(1, 3, 224, 224)
    onnx_save_path = r"onnx_/mobilev2.onnx"
    # 模型转化
    torch.onnx.export(model, tensor_input, onnx_save_path, training=TrainingMode.EVAL)
    # 加载onnx模型 检查模型转化结果
    onnx_model = onnx.load(onnx_save_path)
    onnx.checker.check_model(onnx_model)

onnx模型推理

import onnxruntime

def python_onnx_predict(testpath):
    model_path = r"./onnx_/mobilev2.onnx"
    # 加载模型
    model = onnxruntime.InferenceSession(model_path, providers=(['CUDAExecutionProvider']))
    # onnx模型预测
    onnx_predict(model, testpath)
    
@timespend
def onnx_predict(model, predict_path=r"./dataset/test_data"):
    # 获取onnx模型输入
    input_name = model.get_inputs()[0].name
    # 获取onnx,模型输出
    output_name = model.get_outputs()[0].name
    test_loader = DataLoader(PredictImageDataset(predict_path, classes=classes, iftrain=False), batch_size=1)
    total = 0
    for images, labels, images_path in tqdm(test_loader):
        images, labels = images.cpu(), labels.cpu()
        outputs = model.run([output_name], {input_name: np.asarray(images.cpu(), dtype=np.float32)})[0]
        print(outputs)
        _, pred = torch.max(torch.tensor(outputs), 1)
        correct = torch.sum(labels == pred)
        total += correct
    print(f"correct percent : {float(total) / (len(test_loader.dataset))}")
    return float(total) / (len(test_loader.dataset))

onnx转trt

代码实现比较复杂但是Trt提供了命令转化,本次不改变模型的精度,用命令转化很方便,根据代码改变路径即可

    # onnx2trt 代码比较复杂 利用官方提供的可执行文件
    model_path = r"./onnx_/mobilev2.onnx"
    trt_path = r"./onnx_/mobilev2_onnx1.trt"
    import os
    val = os.system("/data/TensorRT-8.2.0.6/bin/trtexec --onnx="+model_path+" --saveEngine="+trt_path)
    print(val)

trt预测

def trt_pre(batch, context):
    output = np.empty(len(classes),
                      dtype=np.float32)  # 模型预测推理结果
    batch = batch.reshape(-1)
    print(batch.nbytes)
    d_input = driver.mem_alloc(1 * batch.nbytes)
    d_output = driver.mem_alloc(1 * output.nbytes)
    bindings = [int(d_input), int(d_output)]
    stream = driver.Stream()
    # 将图片数据送到cuda显存中
    driver.memcpy_htod_async(d_input, batch, stream)
    # 模型预测
    context.execute_async_v2(bindings, stream.handle, None)
    # 将结果送回内存中
    driver.memcpy_dtoh_async(output, d_output, stream)
    # 异步等待结果
    stream.synchronize()
    return output

@timespend
def trt_predict(model, predict_path=r"/data/kile/other/Inception/mobile_net/dataset/test_data"):
   test_loader = DataLoader(PredictImageDataset(predict_path, classes=classes, iftrain=False), batch_size=1)
   total = 0
   for images, labels, images_path in tqdm(test_loader):
       images, labels = images.cpu(), labels.cpu()
       outputs = trt_pre(np.asarray(images.cpu(), dtype=np.float32), model)
       # print(outputs)
       for i in outputs:
           print(i)
       _, pred = torch.max(torch.tensor(outputs).unsqueeze(0), 1)
       # print(pred)
       correct = torch.sum(labels == pred)
       total += correct
   print(f"correct percent : {float(total) / (len(test_loader.dataset))}")
   return float(total) / (len(test_loader.dataset))

def python_tensorrt_predict(testpath):
    model_path = r"./onnx_/mobilev2_onnx1.trt"
    # 加载runtime,记录log
    runtime = tensorrt.Runtime(tensorrt.Logger(tensorrt.Logger.WARNING))
    # 反序列化模型
    engine = runtime.deserialize_cuda_engine(open(model_path, "rb").read())
    # 推理上下文
    context = engine.create_execution_context()
    # 开始预测
    trt_predict(context, testpath)

总结:

​ 实在是快的多。在pth转化为onnx再转化为trt过程,精度会发生变化,由于我只单纯将模型转化,并没有对模型本身的精度做出改变,所以不影响我的分类结果,我这边对onnx、trt测试结果显示,基本不影响分类结果,精度损失控制在小数点第5、6位之后,影响很小。但是速度有大的提升。

结果:

image-20220318000655317

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
要在 Python 中推理 TensorRT 模型,您需要使用 TensorRT Python API。TensorRT Python API 是一个 Python 包,它提供了一组用于加载、优化和推理 TensorRT 模型的函数和类。 下面是一些步骤,帮助您在 Python 中推理 TensorRT 模型: 1. 安装 TensorRT Python API:您需要从 NVIDIA 的官方网站下载和安装 TensorRT Python API。请确保您的系统满足 TensorRT Python API 的要求。 2. 加载和优化 TensorRT 模型:使用 TensorRT Python API 的函数和类来加载和优化 TensorRT 模型。您可以使用 TensorRT Python API 的 Builder 类来构建和优化 TensorRT 引擎。 3. 推理 TensorRT 模型:使用 TensorRT Python API 的函数和类来推理 TensorRT 模型。您可以使用 TensorRT Python API 的 Engine 类来执行推理操作。 4. 处理输出:您可以使用 Python 来处理 TensorRT 模型的输出。您可以将 TensorRT 模型的输出转换为 NumPy 数组,并使用 NumPy 函数对其进行处理。 下面是一个简单的示例,展示如何在 Python 中推理 TensorRT 模型: ```python import tensorrt as trt import numpy as np # 加载 TensorRT 模型 TRT_LOGGER = trt.Logger(trt.Logger.WARNING) with open("model.trt", "rb") as f: engine = trt.Runtime(TRT_LOGGER).deserialize_cuda_engine(f.read()) # 创建 TensorRT 推理上下文 context = engine.create_execution_context() # 准备输入数据 input_data = np.random.normal(size=(1, 3, 224, 224)).astype(np.float32) # 执行推理操作 bindings = [None] * engine.num_bindings inputs_idx = [engine.get_binding_index(name) for name in input_names] outputs_idx = [engine.get_binding_index(name) for name in output_names] bindings[inputs_idx[0]] = input_data output_data = np.empty(shape=engine.get_binding_shape(outputs_idx[0]), dtype=np.float32) bindings[outputs_idx[0]] = output_data context.execute_v2(bindings) # 处理输出数据 output_data = output_data.reshape(1, -1) output_data = np.argmax(output_data, axis=1) print(output_data) ``` 在这个示例中,我们首先加载了一个 TensorRT 模型,并创建了一个 TensorRT 推理上下文。然后,我们准备了输入数据,并使用 TensorRT 推理上下文执行了推理操作。最后,我们将输出数据转换为 NumPy 数组,并使用 NumPy 函数对其进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kui9702

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值