Instance Segmentation Model Export - LTDETRv2¶
This notebook demonstrates how to export an LTDETRv2 instance segmentation model to ONNX and TensorRT.
The notebook covers the following steps:
Install LightlyTrain
Export a trained LTDETRv2 model to ONNX
Run inference with the ONNX model
Export the model to TensorRT
Run inference with the TensorRT engine
Important: When running on Google Colab make sure to select a GPU runtime. You can do this by going to
Runtime>Change runtime typeand selecting a GPU hardware accelerator.
!pip install "lightly-train[onnx,onnxruntime,onnxslim]"
Export to ONNX¶
Load the model weights¶
Load the COCO-trained LTDETRv2 instance segmentation model with LightlyTrain’s load_model function.
import lightly_train
model = lightly_train.load_model("ltdetrv2-seg-s-coco")
Download an example image¶
Download an example image for inference:
!wget -O image.jpg http://images.cocodataset.org/val2017/000000039769.jpg
Preprocessing¶
import numpy as np
import torchvision.transforms.v2 as T
from PIL import Image
from torchvision.transforms.functional import pil_to_tensor
image_pil = Image.open("image.jpg").convert("RGB")
image_tensor = pil_to_tensor(image_pil)
w, h = image_pil.size
transforms = T.Compose(
[
T.Resize(model.image_size),
T.ToTensor(),
T.Normalize(**model.image_normalize) if model.image_normalize else T.Identity(),
]
)
image_tensor_transformed = transforms(image_pil)[None]
orig_target_size = np.array([[h, w]], dtype=np.int64)
Get the model predictions for reference¶
Define a helper that displays each instance’s mask, bounding box, and class label. We will use it for the PyTorch, ONNX, and TensorRT predictions.
import matplotlib.pyplot as plt
import torch
from torchvision.utils import draw_bounding_boxes, draw_segmentation_masks
def visualize_instances(image, boxes, masks, labels, classes):
image_with_masks = draw_segmentation_masks(image, masks=masks.cpu(), alpha=0.6)
image_with_instances = draw_bounding_boxes(
image_with_masks,
boxes=boxes.cpu(),
labels=[classes[label.item()] for label in labels.cpu()],
)
fig, axs = plt.subplots(1, 2, figsize=(12, 8))
axs[0].imshow(image.permute(1, 2, 0))
axs[0].axis("off")
axs[1].imshow(image_with_instances.permute(1, 2, 0))
axs[1].axis("off")
fig.show()
results = model.predict(image_tensor, threshold=0.6)
visualize_instances(
image_tensor,
boxes=results["bboxes"],
masks=results["masks"],
labels=results["labels"],
classes=model.classes,
)
Export the model to ONNX¶
model.export_onnx(
out="model.onnx",
# precision="fp16", # Use FP16 weights for a smaller and faster model.
)
See export_onnx for all available options.
Run inference with the ONNX model¶
The exported graph takes the preprocessed image and the original image size in (height, width) order. It returns all queries, so apply the same score and mask thresholds as model.predict.
import onnxruntime as ort
import torch.nn.functional as F
sess = ort.InferenceSession("model.onnx")
input_dtype = sess.get_inputs()[0].type
input_dtype_numpy = {
"tensor(float)": "float32",
"tensor(float16)": "float16",
}[input_dtype]
labels_onnx, boxes_onnx, masks_onnx, scores_onnx = sess.run(
output_names=None,
input_feed={
"images": image_tensor_transformed.numpy().astype(input_dtype_numpy),
"orig_target_size": orig_target_size,
},
)
labels_onnx = labels_onnx[0]
boxes_onnx = boxes_onnx[0]
masks_onnx = masks_onnx[0]
scores_onnx = scores_onnx[0]
keep = scores_onnx > 0.6
labels_onnx = torch.from_numpy(labels_onnx[keep])
boxes_onnx = torch.from_numpy(boxes_onnx[keep])
masks_onnx = torch.from_numpy(masks_onnx[keep])
masks_onnx = (
F.interpolate(
masks_onnx.unsqueeze(1),
size=(h, w),
mode="bilinear",
align_corners=False,
).squeeze(1)
> 0.0
)
visualize_instances(
image_tensor,
boxes=boxes_onnx,
masks=masks_onnx,
labels=labels_onnx,
classes=model.classes,
)
Export to TensorRT¶
Requirements¶
TensorRT is not part of LightlyTrain’s dependencies and must be installed separately. Installation depends on your OS, Python version, GPU, and NVIDIA driver/CUDA setup. See the TensorRT documentation for details.
On CUDA 12.x systems, install the TensorRT version tested with this tutorial. Pinning the version prevents pip from installing TensorRT 11, which is not yet supported by LightlyTrain:
!pip install "tensorrt-cu12==10.13.3.9"
model.export_tensorrt(
out="model.trt",
# precision="fp16", # Use FP16 weights for a smaller and faster engine.
)
See export_tensorrt for all available options.
Run inference with the TensorRT engine¶
import tensorrt as trt
class TRT:
def __init__(self, engine_path: str, device: str = "cuda:0", verbose: bool = False):
self.device = torch.device(device)
logger = trt.Logger(trt.Logger.VERBOSE if verbose else trt.Logger.INFO)
trt.init_libnvinfer_plugins(logger, "")
runtime = trt.Runtime(logger)
with open(engine_path, "rb") as f:
self.engine = runtime.deserialize_cuda_engine(f.read())
self.context = self.engine.create_execution_context()
io_names = [
self.engine.get_tensor_name(i) for i in range(self.engine.num_io_tensors)
]
self.in_names = [
name
for name in io_names
if self.engine.get_tensor_mode(name) == trt.TensorIOMode.INPUT
]
self.out_names = [
name
for name in io_names
if self.engine.get_tensor_mode(name) == trt.TensorIOMode.OUTPUT
]
self.buffers = {}
self.bindings = []
for name in io_names:
shape = tuple(self.context.get_tensor_shape(name))
np_dtype = trt.nptype(self.engine.get_tensor_dtype(name))
torch_dtype = torch.from_numpy(np.empty((), dtype=np_dtype)).dtype
buffer = torch.empty(
shape, device=self.device, dtype=torch_dtype
).contiguous()
self.buffers[name] = buffer
self.bindings.append(buffer.data_ptr())
@torch.no_grad()
def __call__(self, inputs: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]:
for name in self.in_names:
self.buffers[name].copy_(inputs[name].to(self.device))
if not self.context.execute_v2(self.bindings):
raise RuntimeError("TensorRT execution failed")
return {name: self.buffers[name] for name in self.out_names}
trt_model = TRT("model.trt")
outputs_trt = trt_model(
{
"images": image_tensor_transformed,
"orig_target_size": torch.from_numpy(orig_target_size),
}
)
labels_trt = outputs_trt["labels"][0]
boxes_trt = outputs_trt["boxes"][0]
masks_trt = outputs_trt["masks"][0]
scores_trt = outputs_trt["scores"][0]
keep = scores_trt > 0.6
labels_trt = labels_trt[keep]
boxes_trt = boxes_trt[keep]
masks_trt = masks_trt[keep]
masks_trt = (
F.interpolate(
masks_trt.unsqueeze(1),
size=(h, w),
mode="bilinear",
align_corners=False,
).squeeze(1)
> 0.0
)
visualize_instances(
image_tensor,
boxes=boxes_trt,
masks=masks_trt,
labels=labels_trt,
classes=model.classes,
)