4. 使用TensorRT优化GPU推理性能
任务目标
将训练好的TensorFlow模型(以ResNet50为例)转换为TensorRT引擎,并在GPU上测量推理延迟与吞吐量,对比TensorRT与原生TensorFlow的性能差异。
环境依赖
- Ubuntu 20.04+,NVIDIA GPU(本文以T4为例),Driver ≥ 470
- TensorFlow 2.10(CPU版即可,仅用于导出模型)
- TensorRT 8.6 + TF-TRT(
pip install tensorflow[and-cuda]==2.10或使用NVIDIA官方镜像nvcr.io/nvidia/tensorflow:23.04-tf2-py3) - PyCUDA(用于精确计时)
实现步骤
整体流程:导出SavedModel → 使用TF-TRT转换为TensorRT引擎 → 加载引擎并预热 → 测量延迟与吞吐量。TF-TRT会在运行时将支持的算子融合为TensorRT引擎,不支持的算子回退到TensorFlow执行。
完整代码
import time
import numpy as np
import tensorflow as tf
from tensorflow.python.compiler.tensorrt import trt_convert as trt
# ========== 1. 导出/加载TensorFlow模型 ==========
# 使用预训练ResNet50,若已有自己的模型,替换为 tf.saved_model.load 即可
model = tf.keras.applications.ResNet50(weights='imagenet', input_shape=(224, 224, 3))
model.save('/tmp/resnet50_savedmodel')
# ========== 2. 转换为TensorRT引擎 ==========
conversion_params = trt.DEFAULT_TRT_CONVERSION_PARAMS._replace(
precision_mode='FP16', # 使用FP16精度
max_workspace_size_bytes=1 << 30, # 1GB workspace
minimum_segment_size=3, # 最小算子段大小
max_batch_size=8 # 最大批大小
)
converter = trt.TrtGraphConverterV2(
input_saved_model_dir='/tmp/resnet50_savedmodel',
conversion_params=conversion_params
)
converter.convert()
# 保存转换后的模型
trt_engine_path = '/tmp/resnet50_trt'
converter.save(output_saved_model_dir=trt_engine_path)
print('TensorRT引擎已保存至:', trt_engine_path)
# ========== 3. 加载引擎并构建推理函数 ==========
trt_model = tf.saved_model.load(trt_engine_path)
infer = trt_model.signatures['serving_default']
# 获取输入张量名称(ResNet50的输入名为'input_1')
input_name = list(infer.structured_input_signature[1].keys())[0]
print('输入张量名:', input_name)
# ========== 4. 性能测试 ==========
batch_size = 8
input_shape = (batch_size, 224, 224, 3)
dummy_input = tf.random.uniform(input_shape, minval=0, maxval=1.0, dtype=tf.float32)
# 预热(Warm-up):让TensorRT完成内核选择与显存分配
for _ in range(10):
infer(dummy_input)
# 延迟测试:单次推理耗时(毫秒)
latencies = []
n_iter = 100
for _ in range(n_iter):
start = time.perf_counter()
infer(dummy_input)
latencies.append((time.perf_counter() - start) * 1000)
latencies.sort()
avg_latency = np.mean(latencies)
p50 = latencies[n_iter // 2]
p95 = latencies[int(n_iter * 0.95)]
print(f'TensorRT 延迟 (batch={batch_size}):')
print(f' 平均: {avg_latency:.2f} ms')
print(f' P50: {p50:.2f} ms')
print(f' P95: {p95:.2f} ms')
# 吞吐量测试:每秒处理图像数
total_images = 0
start = time.perf_counter()
duration = 3.0 # 测试3秒
while time.perf_counter() - start < duration:
infer(dummy_input)
total_images += batch_size
elapsed = time.perf_counter() - start
throughput = total_images / elapsed
print(f'TensorRT 吞吐量: {throughput:.1f} images/sec')
# ========== 5. 对比原生TensorFlow ==========
# 加载原始模型(使用GPU)
gpus = tf.config.list_physical_devices('GPU')
if gpus:
tf.config.set_logical_device_configuration(
gpus[0],
[tf.config.LogicalDeviceConfiguration(memory_limit=4096)]
)
tf_model = tf.keras.models.load_model('/tmp/resnet50_savedmodel')
tf_model.compile() # 仅推理不需要compile
# 预热
for _ in range(5):
tf_model(dummy_input, training=False)
# 延迟测试
latencies_tf = []
for _ in range(50):
start = time.perf_counter()
tf_model(dummy_input, training=False)
latencies_tf.append((time.perf_counter() - start) * 1000)
avg_tf = np.mean(latencies_tf)
print(f'\n原生TensorFlow 延迟 (batch={batch_size}):')
print(f' 平均: {avg_tf:.2f} ms')
# 吞吐量测试
total_images = 0
start = time.perf_counter()
while time.perf_counter() - start < duration:
tf_model(dummy_input, training=False)
total_images += batch_size
elapsed = time.perf_counter() - start
throughput_tf = total_images / elapsed
print(f'原生TensorFlow 吞吐量: {throughput_tf:.1f} images/sec')
# ========== 6. 结果汇总 ==========
print('\n========== 性能对比 ==========')
print(f'延迟加速比: {avg_tf / avg_latency:.2f}x')
print(f'吞吐量提升: {throughput / throughput_tf:.2f}x')
运行方式
# 使用NVIDIA官方TensorFlow容器(已包含TF-TRT)
docker run --gpus all -it --rm \
-v $(pwd):/workspace \
nvcr.io/nvidia/tensorflow:23.04-tf2-py3 \
python /workspace/trt_inference.py
验证方法与判定标准
- 转换成功标志:控制台输出“TensorRT引擎已保存至: /tmp/resnet50_trt”,且该目录下存在
saved_model.pb与variables/文件夹。 - 推理正确性:对同一输入,TensorRT与原生TF的预测类别应一致(可在代码中增加
np.argmax对比,Top-1类别相同即通过)。 - 性能提升判定:在T4 GPU上,FP16精度下TensorRT延迟通常比原生TF快 1.5~3倍,吞吐量提升 2~4倍。若加速比低于1.2倍,检查是否使用了FP16、batch size是否≥4,以及GPU是否被其他进程占用。
- 无回退警告:转换时若出现大量“segment fallback”警告,说明模型中有较多不支持的算子,可尝试使用FP32精度或更新TensorRT版本。
常见问题
- 显存不足:减小
max_workspace_size_bytes或batch_size。 - 转换后精度下降:FP16可能导致个别层精度损失,若验证集准确率下降超过1%,改用FP32(
precision_mode='FP32')。 - 动态输入形状:本案例使用固定shape(224×224×3),若需动态batch,需在转换参数中设置
dynamic_shape=True并配置优化profile。