A model that achieves state-of-the-art accuracy on a benchmark dataset does not automatically qualify for field deployment. Research models are trained and evaluated on GPU clusters with abundant memory and compute. Deployed models must run on edge hardware with strict power budgets, limited memory, and real-time latency requirements. The gap between a PyTorch training checkpoint and a production edge inference engine spans multiple optimization steps — and each step has implications for accuracy, latency, and maintainability.

ONNX (Open Neural Network Exchange) and TensorRT are the two key technologies in the model optimization pipeline for NVIDIA Jetson deployment. ONNX provides a framework-neutral intermediate representation that breaks the dependency between training framework and deployment environment. TensorRT compiles and optimizes ONNX models into device-specific inference engines that extract maximum performance from NVIDIA GPU hardware. Together, they form a reproducible, versionable optimization pipeline from research model to field-deployed inference.

The Training-to-Inference Gap

The typical research model exists as a PyTorch state dict (`.pt` file) or TensorFlow SavedModel — a collection of learned weights and a computation graph definition that depends on the training framework's runtime to execute. The training framework runtime is designed for flexibility (dynamic computation graphs, autograd, gradient checkpointing) rather than performance. Running a research model in PyTorch on an NVIDIA Jetson Orin NX without optimization produces inference at roughly 8–15 fps for a medium-complexity detection model — dramatically below the 30 fps target for real-time video analysis.

Three sources of this gap: Memory overhead. Training checkpoints include optimizer state, gradient buffers, and per-layer batch normalization statistics that are not needed for inference. A YOLOv8-medium training checkpoint is approximately 850 MB; the inference-only model weights are approximately 50 MB. Compute overhead. Dynamic execution graphs evaluated at runtime cannot be pre-compiled into static hardware-optimized execution plans. Precision mismatch. Training uses FP32 or FP16 for numerical precision; edge hardware achieves maximum throughput with INT8, but converting to INT8 requires calibration to determine appropriate quantization scales.

ONNX as Universal Interchange: Export from PyTorch

ONNX defines a standard graph-based representation of neural network architectures, independent of any particular training framework. Exporting a trained PyTorch model to ONNX produces a `.onnx` file containing the complete inference computation graph — all layers, their connections, and the learned weights — in a format that any ONNX-compatible runtime can execute.

The PyTorch ONNX export function (`torch.onnx.export`) traces the model's computation graph by running it with example input tensors and recording the resulting operations. The primary export parameters are:

opset_version: The ONNX operator set version. Higher versions support more operator types; TensorRT 8.x supports up to opset 17. Use opset 16 or 17 for maximum operator coverage with current TensorRT versions.

dynamic_axes: Specifies which tensor dimensions should be treated as variable-length (dynamic) rather than fixed. For a detection model processing video frames, the batch dimension should be dynamic to support both single-frame real-time inference (batch=1) and multi-frame batch processing. Setting dynamic batch size increases ONNX model generality but may prevent some TensorRT optimizations that require fixed shapes.

Common export pitfalls. Not all PyTorch operations have direct ONNX equivalents. Custom autograd functions, Python control flow within model forward methods (if/else branches that depend on tensor values), and operations added in recent PyTorch versions but not yet in the ONNX operator set may cause export failures or incorrect exported graphs. YOLOv8's detection head non-maximum suppression is the most common problem area — Ultralytics provides export configuration flags to use ONNX-compatible NMS implementations. Always validate the exported ONNX model against the original PyTorch model on a representative test set before proceeding to TensorRT compilation.

TensorRT Compilation: INT8 Calibration, Layer Fusion, Kernel Auto-Tuning

TensorRT takes an ONNX model as input and produces a TensorRT engine file (`.trt` or `.engine`) that is optimized for a specific target GPU architecture. The compilation process has three stages:

Network parsing and validation. TensorRT's ONNX parser reads the ONNX graph and validates that all operators are supported. Unsupported operators must be implemented as TensorRT custom plugins before compilation can proceed. For standard CNN architectures (YOLO variants, ResNet, MobileNet, EfficientDet), all operators are natively supported in TensorRT 8.x.

Optimization passes. TensorRT applies a sequence of graph-level optimizations: layer fusion (combining conv+BN+ReLU into a single operation), tensor layout optimization (choosing NCHW vs NHWC memory layouts based on which is faster for each layer on the target GPU), and operator substitution (replacing certain operation sequences with equivalent but faster alternatives available as pre-built CUDA kernels).

Precision calibration and engine compilation. For INT8 compilation, TensorRT runs a calibration procedure: it executes the model on a representative calibration dataset (typically 500–1,000 images), measures the dynamic range of activations at each layer, and determines optimal quantization scale factors. The calibration data quality directly determines INT8 accuracy — use domain-matched imagery matching your deployment sensor type and target classes.

After calibration, TensorRT evaluates multiple CUDA kernel implementations for each layer on the target device and selects the fastest. This auto-tuning step can take 30–90 minutes for a large model but runs only once — the resulting engine file is serialized and can be deployed directly to the target device without re-compilation. Engine files are device-architecture-specific: an engine compiled on one Jetson SKU (e.g., Orin NX) will not run correctly on a different SKU (e.g., AGX Orin) due to different GPU core counts.

Latency vs Throughput: Batch Size 1 for Real-Time Inference

TensorRT's optimization target can be configured for either minimum latency or maximum throughput. For real-time video analysis — where each frame must be processed and results delivered before the next frame arrives — minimum latency at batch size 1 is the correct optimization target. For offline batch processing of stored imagery, maximum throughput at a larger batch size (8–32) reduces per-frame processing time at the cost of increased latency per batch.

At batch size 1, YOLOv8-medium compiled to INT8 on Jetson AGX Orin runs at approximately 1.8ms latency (555 fps theoretical maximum). At batch size 8, latency increases to approximately 7ms per batch (8 × 0.875ms per frame) but achieves roughly 15% higher GPU utilization efficiency. For a 30fps input stream, batch size 1 with a processing latency of 1.8ms provides substantial headroom for multi-model pipelines. For a four-camera system each at 30fps, batch size 4 allows simultaneous processing of one frame from each camera stream in approximately 5ms — a practical architecture for multi-sensor platforms.

Key insight: TensorRT engine files are not portable across GPU architectures. Build your optimization pipeline to compile engines on the target device class (or a device identical to the target) rather than cross-compiling on a development workstation. Attempting to run an engine compiled for Ampere A100 on Jetson Orin (also Ampere but different SM count) will produce either a runtime error or silent accuracy degradation.

Model Versioning and Update Pipeline for Field Devices

A deployed edge AI system needs a maintainable model update pipeline. Models improve through additional training data, architectural refinements, or adaptation to new operational environments (winter vs summer terrain, new target classes). Field-deployed devices need to receive these updates reliably without requiring physical recovery of the hardware.

The update pipeline for TensorRT-deployed models differs from standard software updates in one critical respect: TensorRT compilation must be executed on the target device (or an identical device) because it includes device-specific kernel auto-tuning. A model update workflow might proceed as follows: new model trained at central facility → exported to ONNX → ONNX model pushed to device via secure update channel → TensorRT compilation executed on-device (during a maintenance window when the AI pipeline is paused) → compiled engine activated → old engine archived for rollback.

Each ONNX model release should carry a semantic version identifier, a SHA-256 content hash, and a cryptographic signature from the model provenance authority. The device-side update handler validates the signature before executing compilation. The compilation log and resulting engine hash should be reported back to the fleet management system to confirm successful update across all devices in the fleet.