CPU-Only AOT and TensorRT-RTX Engines#
The CPU-only ahead-of-time (AOT) feature is enabled by default. When you build an engine, TensorRT-RTX does not require a GPU device to be present. The engine is portable to both Windows and Linux operating systems with RTX GPUs that have compute capability 8.6 or later (Ampere and later).
All model weights are stored inside the engine by default. NVIDIA Turing devices are not supported without further configuration. This section provides details about the Compute Capability API and instructions for building a weightless engine for deployment with minimal storage footprint.
Engine type |
GPU at AOT build |
Weights in serialized file |
When to use |
|---|---|---|---|
Default CPU-only AOT |
Not required |
Full weights embedded |
Standard RTX deployment; portable engine for Ampere and later (8.6+) by default |
Explicit compute capability |
Not required (unless |
Full weights embedded |
Target Turing (7.5) or lock to specific CC list; see Support Matrix for precision limits |
Weightless + refit ( |
Required; at most one CC |
Stripped; refit at first launch |
Minimal installer footprint; distribute small engine and restore weights on the client |
Compute Capability#
Compute capability defines the hardware features and supported instructions for each NVIDIA GPU architecture. For information regarding the compute capability of your GPU, refer to NVIDIA CUDA GPU Compute Capability.
By default, an engine built by TensorRT-RTX can be run on GPU devices with compute capability 8.6, 8.9, 12.0, 12.1, and later. To build engines for Turing devices, a compute capability of 7.5 needs to be specified through the API.
Specifying Target Compute Capabilities#
You can specify one or more compute capabilities through IBuilderConfig. The following example shows how to set a single target compute capability of 7.5 for Turing RTX devices.
1IBuilderConfig* config = builder->createBuilderConfig();
2config->setNbComputeCapabilities(1);
3config->setComputeCapability(ComputeCapability::kSM75, 0);
1import tensorrt_rtx as trt
2
3builder_config = builder.create_builder_config()
4builder_config.num_compute_capabilities = 1
5builder_config.set_compute_capability(trt.ComputeCapability.SM75, 0)
Configuration |
AOT build behavior |
When to use |
|---|---|---|
Default (no CC set) |
CPU-only AOT; engine runs on CC 8.6, 8.9, 12.0, 12.1, and later |
Most RTX apps without Turing-only requirements |
Explicit CC list ( |
Engine limited to listed architectures |
Turing (7.5) support or multi-arch targeting with known trade-offs |
`ComputeCapability::kCURRENT` / |
Requires GPU; compiles for the device in the build environment |
Development tuning on a specific GPU; must be the only CC target |
You can use the ComputeCapability::kCURRENT flag to turn off CPU-only AOT and use the current GPU device in the environment as the target to compile an engine. ComputeCapability::kCURRENT is supported only when it is the sole target compute capability.
When you set one or multiple compute capabilities, the engine you build can only run on specified target devices.
Warning
If you specify Turing (compute capability 7.5) as one of multiple targets, the resulting engine is not guaranteed to be performant on Ampere or later devices. Build separate engines per architecture for best performance.
The tensorrt_rtx tool provides the flag --useGpu to be equivalent to setting ComputeCapability::kCURRENT; and option --computeCapabilities=<list_of_CCs> to accept one or multiple compute capabilities.
Compile Models with Hardware-Specific Data Types#
When hardware-specific data types appear in the network definition, TensorRT-RTX will either emit a warning message or an error based on how the API is called by users. For per-architecture precision support, refer to the Support Matrix. If you are porting a model that uses reduced-precision types, also refer to Work With Quantized Types.
Commonly used hardware-specific data types include FP4, FP8, BF16, and INT4. FP16, FP32, and other integer types are supported on all supported hardware.
The behavior of TensorRT-RTX depends on whether one or more compute capabilities are specified:
CC configuration |
Default precision behavior |
Failure mode |
|---|---|---|
Default (none specified) |
FP8 models: Ada and later (8.9+). FP4 models: Blackwell and later (12.0+). All other models: Ampere and later (8.6+). |
Runtime failure on hardware below the implied minimum |
One or more CCs specified |
Engine is limited to the specified compute capabilities |
Build error recorded by |
Weightless Engines#
An engine without weights helps minimize the storage footprint for deployment. Weight-stripping build configuration can be enabled, so that TensorRT-RTX enables refit only for constant weights that do not impact the builder’s ability to optimize and produce an engine with the same runtime performance as a non-refittable engine. Those weights are then omitted from the serialized engine, resulting in a small engine file that can be refitted at runtime using custom weights or weights from the ONNX model.
Note
When weight-stripping build configuration is enabled, a GPU device is required for the AOT build and at most one compute capability can be set through the builder config.
Building a Weightless Engine#
The tensorrt_rtx tool provides flags --stripWeights and --refit to enable the weight-stripping build configuration. The corresponding builder flags are kSTRIP_PLAN and kREFIT.
1...
2config->setFlag(BuilderFlag::kSTRIP_PLAN);
3config->setFlag(BuilderFlag::kREFIT);
4builder->buildSerializedNetwork(*network, *config);
1...
2config.flags |= 1 << int(trt.BuilderFlag.STRIP_PLAN)
3config.flags |= 1 << int(trt.BuilderFlag.REFIT)
4builder.build_serialized_network(network, config)
After the engine is built, save the engine file and distribute it to the installer.
Refitting a Weightless Engine#
On the client side, when launching the network for the first time, the user can refit all the weights back to the engine. Since all the weights in the engine were removed, each weight needs to be updated one by one. After all weights are updated, save the full TensorRT-RTX engine file to be used in the application for future inference.
1IRefitter* refitter = createInferRefitter(*engine, gLogger);
2int32_t const n = refitter->getAllWeights(0, nullptr);
3for (int32_t i = 0; i < n; ++i) {
4 refitter->setNamedWeights(weightsNames[i], Weights{...});
5}
6auto serializationConfig = SampleUniquePtr<nvinfer1::ISerializationConfig>(cudaEngine->createSerializationConfig());
7auto serializationFlag = serializationConfig->getFlags()
8serializationFlag &= ~(1<<static_cast<uint32_t>(nvinfer1::SerializationFlag::kEXCLUDE_WEIGHTS));
9serializationConfig->setFlags(serializationFlag);
10// hostMemory will contain the full engine
11auto hostMemory = SampleUniquePtr<nvinfer1::IHostMemory>(cudaEngine->serializeWithConfig(*serializationConfig));
1refitter = trt.Refitter(engine, TRT_LOGGER)
2all_weights = refitter.get_all()
3for name in all_weights:
4 refitter.set_named_weights(name, weights[name])
5serialization_config = engine.create_serialization_config()
6serialization_config.flags &= ~(1 << int(trt.SerializationFlag.EXCLUDE_WEIGHTS))
7binary = engine.serialize_with_config(serialization_config)
Refitting a Weightless Engine Directly with ONNX Models
When working with weight-stripped engines created from ONNX models, the refit process can be done automatically with the IParserRefitter class from the ONNX parser library. The following code shows how to create the class and run the refit process.
1IRefitter* refitter = createInferRefitter(*engine, gLogger);
2IParserRefitter* parserRefitter = createParserRefitter(*refitter, gLogger);
3bool result = parserRefitter->refitFromFile("path_to_onnx_model");
4refitSuccess = refitter->refitCudaEngine();
1refitter = trt.Refitter(engine, TRT_LOGGER)
2parser_refitter = trt.OnnxParserRefitter(refitter, TRT_LOGGER)
3result = parser_refitter.refit_from_file("path_to_onnx_model")
4refit_success = refitter.refit_cuda_engine()
Deferred Weights Loading#
Use deferred weights loading to deserialize a TensorRT-RTX engine without allocating the engine weights in host or GPU memory. During execution context creation, TensorRT-RTX just-in-time (JIT) compiles the required kernels from the metadata in the weightless engine. This behavior lowers peak host and GPU memory use during deserialization. It is useful when an application deserializes several engines before running any of them, such as a multi-model application that keeps many engines resident.
Warning
Deferred weights loading and weight streaming are mutually exclusive in the current release. Enabling both features results in an API usage error.
Because JIT compilation runs during createExecutionContext(), you can
optionally attach an IRuntimeCache to the runtime configuration and
serialize the compiled kernels to disk. This approach lets multiple models
populate runtime caches in parallel without loading weights into host or GPU
memory. The optional cache steps are marked in the following example. Keep the
IRuntimeConfig and IRuntimeCache alive while contexts created from them
are in use. For more information, refer to
Working with Runtime Cache.
1IRuntime* runtime = createInferRuntime(gLogger);
2runtime->setDeferredWeightsLoading(true);
3ICudaEngine* engine = runtime->deserializeCudaEngine(blob, size);
4
5// [Optional] Attach a runtime cache to save the JIT-compiled
6// kernels without loading weights. The config and cache must
7// outlive contexts created from them.
8IRuntimeConfig* config = engine->createRuntimeConfig();
9IRuntimeCache* cache = config->createRuntimeCache();
10config->setRuntimeCache(*cache);
11
12IExecutionContext* context = engine->createExecutionContext(config);
13
14// [Optional] Serialize the runtime cache into host memory for
15// saving to disk.
16IHostMemory* hostMemory = cache->serialize();
17
18// Before the first inference, load the weights into GPU memory
19// from the same plan blob.
20engine->loadWeights(blob, size);
21context->enqueueV3(stream);
1runtime = trt.Runtime(TRT_LOGGER)
2runtime.defer_weights_loading = True
3engine = runtime.deserialize_cuda_engine(blob)
4
5# [Optional] Attach a runtime cache to save the JIT-compiled
6# kernels without loading weights. Keep config and cache alive
7# while contexts created from them are in use.
8config = engine.create_runtime_config()
9cache = config.create_runtime_cache()
10config.set_runtime_cache(cache)
11
12context = engine.create_execution_context(config)
13
14# [Optional] Save the compiled kernels to disk.
15with cache.serialize() as serialized_cache:
16 with open("runtime.cache", "wb") as cache_file:
17 cache_file.write(serialized_cache)
18
19# Before the first inference, load the weights into GPU memory
20# from the same plan blob.
21engine.load_weights(blob)
22assert engine.weights_loaded
23context.execute_async_v3(stream)
Loading Weights Directly to the GPU
To transfer weights directly from storage to the GPU without staging a
complete copy in host memory, use loadWeightsAsync() with an
IStreamReaderV2 that serves the engine plan bytes on demand.
loadWeightsAsync() does not synchronize the stream. Enqueue dependent
work on the same stream, and synchronize the stream explicitly when needed.
1// myReader implements IStreamReaderV2 and serves the engine plan
2// bytes on demand.
3engine->loadWeightsAsync(myReader, stream);
4context->enqueueV3(stream);
5// ...
6cudaStreamSynchronize(stream);
1engine.load_weights_async(my_reader, int(stream))
2context.execute_async_v3(int(stream))
3# ...
4cudart.cudaStreamSynchronize(stream)
Next Steps#
Porting from TensorRT: Deploying CPU-only ahead-of-time engines in your application
Simultaneous Compute and Graphics: Running inference alongside graphics workloads
Best Practices: Measuring and optimizing inference performance