Python Migration Patterns for TensorRT 11.x#
Migrating from Weak Typing to Strong Typing#
TensorRT 11.x removes all precision-enabling builder flags such as BuilderFlag.FP16 and BuilderFlag.INT8. Use ModelOpt AutoCast to convert your ONNX model to mixed precision before building.
Migrating from Weak Typing to Strong Typing (Before / After / Summary)
Before (TensorRT 10.x)
1 import tensorrt as trt
2
3 logger = trt.Logger(trt.Logger.WARNING)
4 builder = trt.Builder(logger)
5 network = builder.create_network()
6 config = builder.create_builder_config()
7
8 # Weak typing: TensorRT automatically considers FP16 kernels
9 config.set_flag(trt.BuilderFlag.FP16)
10
11 parser = trt.OnnxParser(network, logger)
12 with open("model.onnx", "rb") as f:
13 parser.parse(f.read())
14
15 engine_bytes = builder.build_serialized_network(network, config)
In TensorRT 11.x, the BuilderFlag.FP16 flag has been removed along with all other weak typing flags. Use ModelOpt AutoCast to convert your FP32 ONNX model to mixed precision before building, then build with a strongly typed network.
After (TensorRT 11.x)
Install ModelOpt, and convert the model before running the TensorRT build code:
pip3 install --no-cache-dir --extra-index-url https://pypi.nvidia.com "nvidia-modelopt[all]"
python -m modelopt.onnx.autocast --onnx_path model.onnx --output_path model_fp16.onnx
1 import tensorrt as trt
2
3 # Build with the converted model. Strong typing is always on in 11.x.
4 logger = trt.Logger(trt.Logger.WARNING)
5 builder = trt.Builder(logger)
6 network = builder.create_network()
7 config = builder.create_builder_config()
8
9 parser = trt.OnnxParser(network, logger)
10 with open("model_fp16.onnx", "rb") as f:
11 parser.parse(f.read())
12
13 engine_bytes = builder.build_serialized_network(network, config)
Summary of Changes
Removed
config.set_flag(trt.BuilderFlag.FP16)and all other precision-enabling builder flagsAdded a preprocessing step using ModelOpt AutoCast to convert the model to mixed precision
The
STRONGLY_TYPEDnetwork definition creation flag is no longer needed: all networks are strongly typed by default
Migrating INT8 Calibration to Explicit Quantization#
TensorRT 11.x removes IInt8Calibrator and all its subclasses. Use ModelOpt or manual Q/DQ nodes for explicit quantization instead of runtime calibration.
Migrating INT8 Calibration to Explicit Quantization (Before / After / Summary)
Before (TensorRT 10.x)
1 import tensorrt as trt
2
3 class MyCalibrator(trt.IInt8EntropyCalibrator2):
4 def __init__(self, data_loader):
5 super().__init__()
6 self.data_loader = data_loader
7 self.batch_iter = iter(data_loader)
8
9 def get_batch_size(self):
10 return 1
11
12 def get_batch(self, names):
13 try:
14 batch = next(self.batch_iter)
15 # Copy batch to device and return device pointers
16 return [int(batch.data_ptr())]
17 except StopIteration:
18 return None
19
20 def read_calibration_cache(self):
21 return None
22
23 def write_calibration_cache(self, cache):
24 pass
25
26 logger = trt.Logger(trt.Logger.WARNING)
27 builder = trt.Builder(logger)
28 network = builder.create_network()
29 config = builder.create_builder_config()
30
31 # Implicit quantization through calibrator
32 config.set_flag(trt.BuilderFlag.INT8)
33 config.int8_calibrator = MyCalibrator(data_loader)
34
35 parser = trt.OnnxParser(network, logger)
36 with open("model.onnx", "rb") as f:
37 parser.parse(f.read())
38
39 engine_bytes = builder.build_serialized_network(network, config)
In TensorRT 11.x, IInt8Calibrator and all its subclasses have been removed. Use ModelOpt or manual Q/DQ nodes for explicit quantization.
After (TensorRT 11.x)
1 import tensorrt as trt
2
3 # Step 1: Quantize the model offline using ModelOpt (recommended)
4 # python -m modelopt.onnx.quantization --onnx_path model.onnx --calibration_data data.npz
5
6 # Step 2: Build the quantized model (Q/DQ nodes are already in the ONNX graph)
7 logger = trt.Logger(trt.Logger.WARNING)
8 builder = trt.Builder(logger)
9 network = builder.create_network()
10 config = builder.create_builder_config()
11
12 parser = trt.OnnxParser(network, logger)
13 with open("model_quantized.onnx", "rb") as f:
14 parser.parse(f.read())
15
16 engine_bytes = builder.build_serialized_network(network, config)
Summary of Changes
Removed the IInt8Calibrator subclass and all calibration-related code
Removed
config.set_flag(trt.BuilderFlag.INT8)andconfig.int8_calibratorassignmentQuantization is now applied to the model itself (through Q/DQ nodes) before building, not during building
Migrating Plugins from V2 to V3#
The entire V2 plugin family is deprecated: IPluginV2 and
IPluginV2Ext have been deprecated since TensorRT 8.5, and
IPluginV2IOExt, IPluginV2DynamicExt, IPluginCreator, and
IPluginV2Layer are deprecated as of TensorRT 10.0. These types and
INetworkDefinition.add_plugin_v2() are still exposed by the
TensorRT 11.x Python bindings, so existing V2 plugins continue to run;
plan for removal in a future major release. Port V2 plugins to
IPluginV3 with IPluginCreatorV3One. Related earlier removals include the
implicit-batch broadcast helpers on IPluginV2Ext /
IPluginV2DynamicExt and the legacy IPluginRegistry overloads
that took IPluginCreator. New plugins should use the IPluginV3
interface with IPluginCreatorV3One. Refer to the
sample_plugin_v2_to_v3_migration
sample and to Extending
TensorRT with Custom Layers in the companion Developer Guide for the
V2 to V3 mapping tables.
See also
- Side-by-Side V2 ↔ V3 API Mapping
Method-by-method mapping table grouped by lifecycle phase (core, build, runtime, serialization, network attachment).
- Known Migration Issues
Known issues encountered when porting V2 plugins, including the empty
PluginFieldinitializer crash and the strongly-typed network requirement.- Performance: Resolving V2 → V3 Regressions
Checklist for resolving performance regressions after migrating a plugin from
IPluginV2DynamicExttoIPluginV3.
Migrating Plugins from V2 to V3 (Before / After / Summary)
Before (TensorRT 10.x)
1 import tensorrt as trt
2
3 class MyPluginV2(trt.IPluginV2DynamicExt):
4 def __init__(self):
5 super().__init__()
6 self.plugin_namespace = ""
7 self.plugin_type = "MyPlugin"
8 self.plugin_version = "1"
9 self.num_outputs = 1
10
11 def get_output_dimensions(self, output_index, inputs, exprBuilder):
12 return inputs[0] # Same shape as input
13
14 def configure_plugin(self, inp, out):
15 pass
16
17 def supports_format_combination(self, pos, in_out, num_inputs):
18 return in_out[pos].format == trt.TensorFormat.LINEAR and \
19 in_out[pos].type == trt.DataType.FLOAT
20
21 def enqueue(self, input_desc, output_desc, inputs, outputs, workspace, stream):
22 # Kernel execution
23 pass
24
25 def clone(self):
26 return MyPluginV2()
27
28 def serialize(self):
29 return b""
30
31 # Creator
32 class MyPluginCreatorV2(trt.IPluginCreator):
33 def __init__(self):
34 super().__init__()
35 self.name = "MyPlugin"
36 self.plugin_namespace = ""
37 self.plugin_version = "1"
38 self.field_names = trt.PluginFieldCollection([])
39
40 def create_plugin(self, name, fc):
41 return MyPluginV2()
42
43 def deserialize_plugin(self, name, data):
44 return MyPluginV2()
45
46 # Usage
47 trt.get_plugin_registry().register_creator(MyPluginCreatorV2())
48 plugin = MyPluginV2()
49 layer = network.add_plugin_v2([input_tensor], plugin)
After (TensorRT 11.x)
1 import tensorrt as trt
2
3 class MyPluginV3(trt.IPluginV3, trt.IPluginV3OneCore,
4 trt.IPluginV3OneBuild, trt.IPluginV3OneRuntime):
5 def __init__(self):
6 trt.IPluginV3.__init__(self)
7 trt.IPluginV3OneCore.__init__(self)
8 trt.IPluginV3OneBuild.__init__(self)
9 trt.IPluginV3OneRuntime.__init__(self)
10 self.num_outputs = 1
11 self.plugin_namespace = ""
12 self.plugin_name = "MyPlugin"
13 self.plugin_version = "1"
14
15 def get_capability_interface(self, type):
16 return self
17
18 def get_output_data_types(self, input_types):
19 return [input_types[0]] # Same type as input
20
21 def get_output_shapes(self, inputs, shape_inputs, exprBuilder):
22 # Return a list of DimsExprs, one per output
23 output = trt.DimsExprs(len(inputs[0]))
24 for i in range(len(inputs[0])):
25 output[i] = inputs[0][i]
26 return [output]
27
28 def supports_format_combination(self, pos, in_out, num_inputs):
29 return in_out[pos].format == trt.TensorFormat.LINEAR and \
30 in_out[pos].type == trt.DataType.FLOAT
31
32 def configure_plugin(self, inp, out):
33 pass
34
35 def on_shape_change(self, inp, out):
36 return 0
37
38 def enqueue(self, input_desc, output_desc, inputs, outputs, workspace, stream):
39 # Kernel execution
40 pass
41
42 def get_fields_to_serialize(self):
43 return trt.PluginFieldCollection([])
44
45 def get_valid_tactics(self):
46 return []
47
48 def set_tactic(self, tactic):
49 return 0
50
51 def clone(self):
52 cloned_plugin = MyPluginV3()
53 cloned_plugin.__dict__.update(self.__dict__)
54 return cloned_plugin
55
56 def attach_to_context(self, context):
57 return self.clone()
58
59 # Creator
60 class MyPluginCreatorV3(trt.IPluginCreatorV3One):
61 def __init__(self):
62 trt.IPluginCreatorV3One.__init__(self)
63 self.name = "MyPlugin"
64 self.plugin_namespace = ""
65 self.plugin_version = "1"
66 self.field_names = trt.PluginFieldCollection([])
67
68 def create_plugin(self, name, fc, phase):
69 return MyPluginV3()
70
71 # Usage
72 trt.get_plugin_registry().register_creator(MyPluginCreatorV3())
73 plugin = MyPluginV3()
74 layer = network.add_plugin_v3([input_tensor], [], plugin)
Summary of Changes
Plugin class now inherits from
IPluginV3,IPluginV3OneCore,IPluginV3OneBuild, andIPluginV3OneRuntimeinstead ofIPluginV2DynamicExtAdded
get_capability_interface()to return the appropriate capability for each phaseget_output_dimensions()replaced byget_output_shapes(), which receives both data inputs and shape inputs and returns a list ofDimsExprsget_output_data_types()is a new required methodserialize()replaced byget_fields_to_serialize(), which returns aPluginFieldCollectionclone()is still required and returns the new plugin instance.attach_to_context()is a clone-and-attach operation that returns a cloned pluginCreator inherits from
IPluginCreatorV3Oneinstead ofIPluginCreator;create_plugin()receives an additionalphaseparameter anddeserialize_plugin()is no longer needednetwork.add_plugin_v2()replaced bynetwork.add_plugin_v3(), which accepts an additional list of shape inputs
Known Issues When Migrating Plugins
Empty PluginField initializers can crash V3 dispatch. When a plugin advertises a
PluginFieldwhosedatais empty (b""or a zero-length array), the V3 creator dispatch path can crash during build or deserialization. Populate every entry with a non-empty sentinel value, even when it is unused at runtime:import numpy as np import tensorrt as trt # Bad: empty initializer fields = trt.PluginFieldCollection([ trt.PluginField("flag", b"", trt.PluginFieldType.INT32), ]) # Good: non-empty sentinel keeps the dispatch path safe fields = trt.PluginFieldCollection([ trt.PluginField("flag", np.array([0], dtype=np.int32), trt.PluginFieldType.INT32), ])
Use strongly-typed networks with IPluginV3. Mixing
IPluginV3plugins with weakly-typed networks can hit fusion paths that were not exercised byIPluginV2DynamicExtand trigger crashes. In TensorRT 11.0.0 all precision-enabling builder flags (BuilderFlag.FP16,INT8,BF16,FP8,INT4,FP4) have been removed, so any network you build is strongly typed by default; no action required for fresh 11.x builds. Authors back-porting V3 plugins to a 10.x build for evaluation must explicitly opt in withbuilder.create_network(int(trt.NetworkDefinitionCreationFlag.STRONGLY_TYPED)).
Migrating Weight Streaming APIs#
The weight streaming API has been updated in TensorRT 11.x. The minimum_weight_streaming_budget property has been removed; compute a budget from streamable_weights_size and available device memory instead.
Migrating Weight Streaming APIs (Before / After / Summary)
Before (TensorRT 10.x)
1 import tensorrt as trt
2
3 logger = trt.Logger(trt.Logger.WARNING)
4 runtime = trt.Runtime(logger)
5 with open("model.engine", "rb") as engine_file:
6 engine_bytes = engine_file.read()
7 engine = runtime.deserialize_cuda_engine(engine_bytes)
8
9 # Old API
10 budget = engine.minimum_weight_streaming_budget
11 engine.weight_streaming_budget = budget
12 current = engine.weight_streaming_budget
After (TensorRT 11.x)
1 import tensorrt as trt
2 from cuda.bindings import runtime as cudart
3
4 logger = trt.Logger(trt.Logger.WARNING)
5 runtime = trt.Runtime(logger)
6 with open("model.engine", "rb") as engine_file:
7 engine_bytes = engine_file.read()
8 engine = runtime.deserialize_cuda_engine(engine_bytes)
9
10 # V2 API
11 err, free, total = cudart.cudaMemGetInfo()
12 if err != cudart.cudaError_t.cudaSuccess:
13 raise RuntimeError(f"cudaMemGetInfo failed: {err}")
14 weights_size = engine.streamable_weights_size
15 budget = min(free // 2, weights_size // 2)
16 engine.weight_streaming_budget_v2 = budget
17 current = engine.weight_streaming_budget_v2
Summary of Changes
weight_streaming_budgetreplaced byweight_streaming_budget_v2get_minimum_weight_streaming_budgetremoved: compute your own budget based on available memory andstreamable_weights_size
Migrating Memory Management APIs#
TensorRT 11.x replaces device_memory_size with device_memory_size_v2 (which returns int64) and removes create_execution_context_without_device_memory().
Migrating Memory Management APIs (Before / After / Summary)
Before (TensorRT 10.x)
1 import tensorrt as trt
2
3 logger = trt.Logger(trt.Logger.WARNING)
4 runtime = trt.Runtime(logger)
5 with open("model.engine", "rb") as engine_file:
6 engine_bytes = engine_file.read()
7 engine = runtime.deserialize_cuda_engine(engine_bytes)
8
9 # Old API
10 mem_size = engine.device_memory_size
11 context = engine.create_execution_context_without_device_memory()
After (TensorRT 11.x)
1 import tensorrt as trt
2
3 logger = trt.Logger(trt.Logger.WARNING)
4 runtime = trt.Runtime(logger)
5 with open("model.engine", "rb") as engine_file:
6 engine_bytes = engine_file.read()
7 engine = runtime.deserialize_cuda_engine(engine_bytes)
8
9 # V2 API (returns int64)
10 mem_size = engine.device_memory_size_v2
11 context = engine.create_execution_context()
Summary of Changes
device_memory_sizereplaced bydevice_memory_size_v2(returnsint64instead ofsize_t)create_execution_context_without_device_memory()removed: usecreate_execution_context()with appropriate runtime configuration