NOTE: The Jupyter Notebook below is included in the Chimera SDK and can be run interactively by running the following CLI command:
$ quadric sdk notebook
From the Jupyter Notebook window in your browser, select the notebook named /quadric/sdk-cli/examples/models/ddrnet/classify/ddrnet_classify.ipynb.
DDRNet Classification
Abstract
The deep dual-resolution networks (DDRNets) are specially designed for efficient backbones of real-time semantic segmentation. The proposed networks are composed of two deep branches between which multiple bilateral fusions are performed. Additionally, a new contextual information extractor named Deep Aggregation Pyramid Pooling Module (DAPPM) is designed to enlarge effective receptive fields and fuse multi-scale context based on low-resolution feature maps. This method achieves a new state-of-the-art trade-off between accuracy and speed on both Cityscapes and CamVid dataset as backbones of Semantic segmentation.
For further details, please visit the following paper.
- Yuanduo Hong, Huihui Pan, Weichao Sun, Yisong Jia. 'Deep Dual-resolution Networks for Real-time and Accurate Semantic Segmentation of Road Scenes'
This notebook experiments DDRNets for classification.
Set-Up
!pip3 install -r ../../../requirements.txt -q
[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv[0m[33m
[0m
import matplotlib.pyplot as plt
import gdown
from matplotlib.gridspec import GridSpec
import numpy as np
import onnx
import onnxsim
import os
from pathlib import Path
from PIL import Image
import random
import torch
from torch.utils.data import Subset
from torchvision.transforms import Compose, Normalize, ToTensor, Resize
import urllib
import zipfile
from tvm.contrib.epu.chimera_job.chimera_job import ChimeraJob
import tvm.contrib.epu.chimera_job.constants as sdk_constants
from examples.models.zoo.zoo_utils import download_file, onnx_check_and_simplify
from sdk_cli.lib.inference import InferenceEngine, batch_inference
from sdk_cli.lib.quantize import (
QuantizedONNXModel,
quantize_onnx_model,
)
from sdk_cli.utils.datasets import ImageNet_Mini_Quadric
from sdk_cli.utils.datasets.ImageNet import (
IMAGENET_1K_NORMALIZATION_PARAMETERS,
OPTIMIZED_IMAGENET_1K_LABELS,
)
DDRNet.pytorch Github Clone
basename = Path("DDRNet")
## Install DDRNet.
if basename.exists():
print(f"Existing {basename} is used.")
else:
url = "https://github.com/ydhongHIT/DDRNet/archive/refs/heads/main.zip"
filename = Path(url).name
download_file(url, filename)
with zipfile.ZipFile(filename, "r") as fd:
fd.extractall()
os.rename(f"{basename}-{Path(url).stem}", basename)
print(f"{basename} is installed.")
## Make symbolic links for later experiment.
symlink_list = ["classification"]
for sym_path in symlink_list:
if not Path(sym_path).is_symlink():
os.symlink(basename / sym_path, Path(sym_path).name)
print(f"{sym_path} is symbolic")
DDRNet is installed.
classification is symbolic
Model Load
In this notebook, we are going to use DDRNet_23_slim for the experiment.
from classification import DDRNet_23_slim
MODEL_NAME = "DDRNet23_slim_classify"
weights_folder = Path("pretrained_models")
weights_folder.mkdir(exist_ok=True)
weights = weights_folder / "DDRNet23s_imagenet.pth"
DDRNet23s_imagenet_pth_url = "https://drive.google.com/uc?id=1mg5tMX7TJ9ZVcAiGSB4PEihPtrJyalB4"
gdown.download(DDRNet23s_imagenet_pth_url, str(weights), quiet=False)
model = DDRNet_23_slim.get_model()
model.load_state_dict(torch.load(weights, map_location="cpu"))
Downloading...
From: https://drive.google.com/uc?id=1mg5tMX7TJ9ZVcAiGSB4PEihPtrJyalB4
To: /quadric/sdk-cli/examples/models/ddrnet/classify/pretrained_models/DDRNet23s_imagenet.pth
100%|█████████████████████████████████████| 30.4M/30.4M [00:00<00:00, 50.3MB/s]
<All keys matched successfully>
ONNX Export
onnx_file = f"{MODEL_NAME}.onnx"
dataset_input_size = (224, 224)
dummy_data = torch.randn(1, 3, *dataset_input_size[::-1], requires_grad=False)
input_edges = ["inputs0"]
output_edges = ["outputs0"]
## Export the model
torch.onnx.export(
model, # model being run
dummy_data, # model input (or a tuple for multiple inputs)
onnx_file, # where to save the model (can be a file or file-like object)
export_params=True, # store the trained parameter weights inside the model file
do_constant_folding=True, # whether to execute constant folding for optimization
opset_version=sdk_constants.DEFAULT_ONNX_OPSET,
input_names=input_edges, # the model's input names
output_names=output_edges, # the model's output names
)
onnx_model = onnx_check_and_simplify(onnx.load(onnx_file))
onnx.save(onnx_model, onnx_file)
print(f"ONNX is exported and simplified as {onnx_file}")
ONNX is exported and simplified as DDRNet23_slim_classify.onnx
Quantization
dataset_mean = IMAGENET_1K_NORMALIZATION_PARAMETERS.channel_means
dataset_std = IMAGENET_1K_NORMALIZATION_PARAMETERS.channel_standard_deviations
transforms = Compose(
[
Resize(dataset_input_size[0]),
ToTensor(),
Normalize(dataset_mean, dataset_std),
]
)
imagenet_dataset = ImageNet_Mini_Quadric.Dataset(transform=transforms)
subset_of_dataset = Subset(imagenet_dataset, range(100))
quantized_onnx_model: QuantizedONNXModel = quantize_onnx_model(
onnx_file,
subset_of_dataset,
asymmetric_activation=False,
)
print(
f"quantized onnx: {quantized_onnx_model.model_path}, tranges file: {quantized_onnx_model.tensor_ranges_path}"
)
2026-06-19 03:53 - INFO - sdk - quantize - ONNX model shapes inferred.
2026-06-19 03:53 - DEBUG - sdk - quantize - Forcing node types: []
2026-06-19 03:53 - DEBUG - sdk - quantize - ONNX Node types excluded from quantization: ['Softmax', 'Sigmoid', 'QuadricCustomOp']
2026-06-19 03:53 - DEBUG - sdk - quantize - ONNX Node names excluded from quantization: []
2026-06-19 03:53 - INFO - sdk - quantize - Starting quantization...
WARNING:root:Please use QuantFormat.QDQ for activation type QInt8 and weight type QInt8. Or it will lead to bad performance on x64.
2026-06-19 03:53 - INFO - sdk - quantize - Quantization completed! Quantized model saved to /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q.onnx
2026-06-19 03:53 - INFO - sdk - quantize - ONNX full precision model size: 28.89MB
2026-06-19 03:53 - INFO - sdk - quantize - ONNX quantized model size: 7.32MB
2026-06-19 03:53 - INFO - sdk - quantize - ONNX model shapes inferred.
2026-06-19 03:53 - INFO - sdk - quantize - ONNX Model with well-defined shapes has been saved at `/quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.onnx`.
2026-06-19 03:53 - DEBUG - sdk - quantize - Checking for FLOAT/FLOAT16 types...
2026-06-19 03:53 - INFO - sdk - quantize - Checking for remaining FLOAT/FLOAT16 types.
2026-06-19 03:53 - INFO - sdk - quantize - Model still has FLOAT/FLOAT16 types after quantization. Creating ranges for floating point tensors using calibration data...
2026-06-19 03:54 - INFO - sdk - quantize - Saved computed tensor ranges to /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.tranges.
2026-06-19 03:54 - INFO - sdk - quantize -
╒══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│ Quantized ONNX Model │ Tensor Ranges File │
╞══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╪═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.onnx │ /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.tranges │
╘══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╧═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╛
quantized onnx: /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.onnx, tranges file: /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.tranges
Compilation
cgc_job = ChimeraJob(
model_p=str(quantized_onnx_model.model_path),
trange_file=str(quantized_onnx_model.tensor_ranges_path),
)
cgc_job.compile(quiet=True)
print(cgc_job)
╒═════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│ Module Name │ DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ONNX File │ /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.onnx │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Product Target │ QC-U │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Number of Cores │ 1 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ISS Clock Frequency │ 1.700 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ L2M Size │ 16MB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ LRM Size │ 4kB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Read BW │ 128GBps │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Write BW │ 128GBps │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ MACS per PE │ 16 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max L2M │ 3.606MB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max LRM │ 2.438kB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max Temp Ext Bytes │ 0.000MB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Network GMACs │ 0.973 │
╘═════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╛
╒════╤════════╤══════════╤══════════════════╤══════════════════════════╤═══════╕
│ │ Type │ Name │ shape │ type │ mse │
╞════╪════════╪══════════╪══════════════════╪══════════════════════════╪═══════╡
│ 0 │ Input │ inputs0 │ [1, 3, 224, 224] │ tensor[FixedPoint32<29>] │ n/a │
├────┼────────┼──────────┼──────────────────┼──────────────────────────┼───────┤
│ 1 │ Output │ outputs0 │ [1, 1000] │ tensor[FixedPoint32<26>] │ n/a │
╘════╧════════╧══════════╧══════════════════╧══════════════════════════╧═══════╛
Demo
Inference
random.seed(38)
NUM_IMAGES = 3
all_images_dict = dict(random.sample(imagenet_dataset.imgs, NUM_IMAGES))
all_image_paths = list(all_images_dict.keys())
engines = {
InferenceEngine.CHIMERA_ORT_INT8: cgc_job,
InferenceEngine.CHIMERA_ISS_INT8: cgc_job,
}
all_images = []
for image_path in all_image_paths:
all_images.append(np.expand_dims(transforms(Image.open(image_path)), axis=0))
outputs_per_inference_engine = {}
THREADS = min(NUM_IMAGES, 6)
for inference_engine, engine in engines.items():
outputs_per_inference_engine[inference_engine] = batch_inference(
inference_engine,
engine,
all_images,
threads=THREADS,
)
2026-06-19 03:57 - WARNING - epu - chimera_job - ORT is not threadsafe -- forcing single threaded batch execution
100%|████████████████████████████████████████████| 3/3 [00:00<00:00, 4.75it/s]
Processing: 100%|████████████████████████████████| 3/3 [00:12<00:00, 4.25s/it]
Run Statistics
print(cgc_job)
cgc_job.plot_run_statistics()
╒═════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│ Module Name │ DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ONNX File │ /quadric/sdk-cli/examples/models/ddrnet/classify/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped.onnx │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Product Target │ QC-U │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Number of Cores │ 1 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ISS Clock Frequency │ 1.700 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ L2M Size │ 16MB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ LRM Size │ 4kB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Read BW │ 128GBps │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Write BW │ 128GBps │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ MACS per PE │ 16 │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max L2M │ 3.606MB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max LRM │ 2.438kB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max Temp Ext Bytes │ 0.000MB │
├─────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Network GMACs │ 0.973 │
╘═════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╛
╒════╤════════╤══════════╤══════════════════╤══════════════════════════╤═══════╕
│ │ Type │ Name │ shape │ type │ mse │
╞════╪════════╪══════════╪══════════════════╪══════════════════════════╪═══════╡
│ 0 │ Input │ inputs0 │ [1, 3, 224, 224] │ tensor[FixedPoint32<29>] │ n/a │
├────┼────────┼──────────┼──────────────────┼──────────────────────────┼───────┤
│ 1 │ Output │ outputs0 │ [1, 1000] │ tensor[FixedPoint32<26>] │ 0.019 │
╘════╧════════╧══════════╧══════════════════╧══════════════════════════╧═══════╛
Post-ISS Report 1.7 GHz ***
Fully placed-and-routed gate simulation:
╒══════════════════════════════════╤═════════╕
│ Latency (ms) │ 0.30 │
├──────────────────────────────────┼─────────┤
│ FPS │ 3345.09 │
├──────────────────────────────────┼─────────┤
│ Average Power @ 3nm SSGNP (mW) │ 1343.56 │
├──────────────────────────────────┼─────────┤
│ FPS per Watt @ 3nm SSGNP (FPS/W) │ 2489.72 │
├──────────────────────────────────┼─────────┤
│ Ext Rd Bytes (MB) │ 7.97 │
├──────────────────────────────────┼─────────┤
│ Ext Wr Bytes (MB) │ 0.00 │
├──────────────────────────────────┼─────────┤
│ Avg Ext Rd BW (GBps) │ 26.04 │
├──────────────────────────────────┼─────────┤
│ Avg Ext Wr BW (GBps) │ 0.01 │
├──────────────────────────────────┼─────────┤
│ MAC Utilization │ 11.68% │
╘══════════════════════════════════╧═════════╛
*** Data generated using 7nm SSGNP gatesim and scaled to 3nm
[SDK-CLI] : TotalCycles: 508,207
[SDK-CLI] : Executions/second: 3,345.09
compute : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 105.807K
data_array : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 111.084K
mac : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 156.166K
data_external: ▇ 5.808K
data_ocm : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 129.317K
for more information check run directory: /quadric/sdk-cli/examples/models/ddrnet/classify/ccl_build/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260619_035710_9c868a
2026-06-19 03:57 - INFO - epu - chimera_job - Combined plots generated and saved to:
/quadric/sdk-cli/examples/models/ddrnet/classify/ccl_build/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260619_035710_9c868a/data/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1.combined.png
'/quadric/sdk-cli/examples/models/ddrnet/classify/ccl_build/DDRNet23_slim_classify_OpSet16_optimized_sym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260619_035710_9c868a/data'

Display Inference Results
%matplotlib inline
softmax = torch.nn.Softmax(dim=1)
for i, image_path in enumerate(all_image_paths):
idx, ax = 0, []
fig = plt.figure(constrained_layout=True, figsize=(12, 4))
gs = GridSpec(2, 3, figure=fig)
ax.append(fig.add_subplot(gs[:, 0]))
ax.append(fig.add_subplot(gs[0, 1]))
ax.append(fig.add_subplot(gs[1, 1], sharex=ax[1]))
ax[idx].imshow(np.array(Image.open(image_path)))
ax[idx].set_title(
f"{all_images_dict[image_path]}: {OPTIMIZED_IMAGENET_1K_LABELS.class_map[all_images_dict[image_path]]}"
)
ax[idx].set_axis_off()
for inference_engine in engines.keys():
idx += 1
outputs = outputs_per_inference_engine[inference_engine][i][0]
top_5 = torch.topk(softmax(torch.from_numpy(outputs)), k=5)
top5_scores = np.array(list(top_5.values[0])) * 100
top5_labels = [
OPTIMIZED_IMAGENET_1K_LABELS.class_map[int(class_id)] for class_id in top_5.indices[0]
]
if idx == 1:
bar_color = "deepskyblue"
plt.setp(ax[idx].get_xticklabels(), visible=False)
else:
bar_color = "darkviolet"
ax[idx].barh(top5_labels, top5_scores, color=bar_color)
ax[idx].set_title(f"{MODEL_NAME} Top 5 (%): {str(inference_engine)}")
fig.show()



Citation
@article{hong2021deep,
title={Deep Dual-resolution Networks for Real-time and Accurate Semantic Segmentation of Road Scenes},
author={Hong, Yuanduo and Pan, Huihui and Sun, Weichao and Jia, Yisong},
journal={arXiv preprint arXiv:2101.06085},
year={2021}
}
@article{pan2022deep,
title={Deep Dual-Resolution Networks for Real-Time and Accurate Semantic Segmentation of Traffic Scenes},
author={Pan, Huihui and Hong, Yuanduo and Sun, Weichao and Jia, Yisong},
journal={IEEE Transactions on Intelligent Transportation Systems},
year={2022},
publisher={IEEE}
}