UH-OH

It looks like you don’t have access to that feature yet

Contact sales to get upgraded to the full DevStudio experience.

UH-OH

It looks like you don't have access to that feature yet.

to select
to navigate
escto close
Introduction to the Chimera SDK
Chimera SDK Quick Start Guide
Chimera SDK Command Line Interface (CLI)
Tutorial: Using SDK as a Library
Tutorials & Model Demos
Model Demos
Model Demo: Llama-2 15M (Baby Llama-2)
Model Demo: QWEN3 8B End-to-End CGC and ISS Execution
Model Demo: QWEN3 Prefill All Decoders
Model Demo: DeepSeek-R1-Distill-Qwen-1.5B End-to-End CGC and ISS Execution
Model Demo: QWEN3 Single Decoder
Model Demo: Qwen2.5-0.5B INT8 Quantization Pipeline
Model Demo: ConvNeXt Detection
Model Demo: QWEN3 Prefill Decoder Validation
Model Demo: ConvNeXt Segmentation
Model Demo: Classifiers Zoo
Model Demo: Detectors Zoo - MMDetection
Model Demo: Segmentors Zoo - MMSegmentation
Model Demo: Pose Estimators Zoo - MMPose
Model Demo: Detectors3D Zoo - MMDetection3D
MODEL Demo: Optical Character Recognition (OCR) Zoo - MMOCR
Model Demo: YOLOv3 Object Detection
Model Demo: YOLOv4 Object Detection
Model Demo: YOLOv5 Detection
Model Demo: YOLOv5 Detection and Segmentation
Model Demo: YOLOR Detection
Model Demo: YOLOX End-to-End Detection
Model Demo: YOLOv7 Detection
Model Demo: YOLOv8 Detection
Model Demo: YOLOv8 Pose Estimation
Model Demo: YOLOP Detection and Segmentation
Model Demo: QAT Vision Transformer (ViT)
Model Demo: QAT Swin Transformer
Model Demo: Mediapipe Face Pipeline
Demo: DOOM Renderer on Chimera GPNPU
Model Demo: Mediapipe Hand Pipeline
Model Demo: Whisper Tiny (Encoder + Decoder)
Model Demo: L2CS Fine-Grained Gaze Estimation
Model Demo: ASVspoof2021 LA Anti-Spoofing (LFCC-LCNN-BiLSTM)
Model Demo: UNET Tumor Segmentation
Model Demo: DETR Encoder
Model Demo: FFNet Segmentation
Model Demo: Centernet Detection
Model Demo: RetinaNet End-to-End Detection
Model Demo: Blazepose Pose Estimation
Model Demo: Pose Resnet Human Pose Estimation
Model Demo: MaskRCNN Detection and Segmentation
Model Demo: Keypoint R-CNN
Model Demo: Faster R-CNN Detection
Model Demo: FCOS Detection
Model Demo: DDRNet Classificationls
Model Demo: PI0.5 End-to-End VLA Inference
Model Demo: BEVFormer End-to-End 3D Detection
Multicore Demo
Chimera LLVM C++ Compiler
Chimera SDK Licensing Policy Documentation
Glossary
Chimera Software User GuideTutorials & Model DemosModel DemosModel Demo: QAT Swin Transformer

Model Demo: QAT Swin Transformer


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/swin/QAT-Swin.ipynb.


PyTorch QAT -> ONNX Runtime Pipeline (Swin-B)

In this tutorial we use the PyTorch 2 Export (pt2e) library to perform quantization-aware training (QAT) on Swin-B, and export it such that it can be run through ONNX Runtime.

Notes:

  • Training is expected to be done with a GPU, which can be mounted to the docker container with the option --gpus all or --gpus device=0 (replace 0 with whichever device you'd like to use)
    • Original training results were produced with an NVIDIA GeForce RTX 3090
  • pt2e is still in prototype phase (as of 12/19/2024), breaking changes may occur later
  • Other PyTorch quantization libraries are available, but we currently make no guarantee the process will work as intended using them
  • Each network requires slightly different post-processing, so not all networks may be supported yet with the post-processing steps currently implemented
  • Images, labels, and models used in this notebook conform to the ImageNet-1K standard (i.e. use 224x224 image resolution) and have subjects represented in the 1000 ImageNet classes; any different input size or class labels will require user-supplied datasets

High Level Overview

  1. Set up training helper functions
  2. Define our quantization configuration
  3. Prepare the training dataset
  4. Load the model
  5. Perform QAT using the pt2e library
  6. ONNX export and post-processing
  7. Prepare the validation dataset
  8. Validate and compare against FP32 model

0. Imports and setup

%pip install -r ../../requirements_gpu.txt
%pip install yacs timm termcolor  # Used only for Swin
Requirement already satisfied: torch==2.5.0 in /usr/local/lib/python3.10/dist-packages (from -r ../../requirements_gpu.txt (line 1)) (2.5.0)
Requirement already satisfied: torchvision==0.20.0 in /usr/local/lib/python3.10/dist-packages (from -r ../../requirements_gpu.txt (line 2)) (0.20.0)
Requirement already satisfied: s3fs in /usr/local/lib/python3.10/dist-packages (from -r ../../requirements_gpu.txt (line 3)) (2026.6.0)
Requirement already satisfied: onnxscript==0.2.0 in /usr/local/lib/python3.10/dist-packages (from -r ../../requirements_gpu.txt (line 4)) (0.2.0)
Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (10.3.5.147)
Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (1.13.1)
Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.4.127)
Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.4.127)
Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (11.6.1.9)
Requirement already satisfied: typing-extensions>=4.8.0 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (4.15.0)
Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (11.2.1.3)
Requirement already satisfied: fsspec in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (2026.6.0)
Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (9.1.0.70)
Requirement already satisfied: triton==3.1.0 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (3.1.0)
Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (2.8.5)
Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (3.16.1)
Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.4.127)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (3.1.6)
Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (2.21.5)
Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.4.127)
Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.4.5.8)
Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.4.127)
Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /usr/local/lib/python3.10/dist-packages (from torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (12.3.1.170)
Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from torchvision==0.20.0->-r ../../requirements_gpu.txt (line 2)) (1.24.4)
Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /usr/local/lib/python3.10/dist-packages (from torchvision==0.20.0->-r ../../requirements_gpu.txt (line 2)) (12.2.0)
Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from onnxscript==0.2.0->-r ../../requirements_gpu.txt (line 4)) (26.2)
Requirement already satisfied: ml_dtypes in /usr/local/lib/python3.10/dist-packages (from onnxscript==0.2.0->-r ../../requirements_gpu.txt (line 4)) (0.3.2)
Requirement already satisfied: onnx>=1.16 in /usr/local/lib/python3.10/dist-packages (from onnxscript==0.2.0->-r ../../requirements_gpu.txt (line 4)) (1.16.2)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy==1.13.1->torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (1.3.0)
Requirement already satisfied: aiobotocore<4.0.0,>=2.19.0 in /usr/local/lib/python3.10/dist-packages (from s3fs->-r ../../requirements_gpu.txt (line 3)) (3.7.0)
Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0 in /usr/local/lib/python3.10/dist-packages (from s3fs->-r ../../requirements_gpu.txt (line 3)) (3.14.1)
Requirement already satisfied: aioitertools<1.0.0,>=0.5.1 in /usr/local/lib/python3.10/dist-packages (from aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (0.13.0)
Requirement already satisfied: wrapt<3.0.0,>=1.10.10 in /usr/local/lib/python3.10/dist-packages (from aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (2.2.1)
Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /usr/local/lib/python3.10/dist-packages (from aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (2.9.0.post0)
Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.1.0)
Requirement already satisfied: botocore<1.43.1,>=1.42.90 in /usr/local/lib/python3.10/dist-packages (from aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.43.0)
Requirement already satisfied: multidict<7.0.0,>=6.0.0 in /usr/local/lib/python3.10/dist-packages (from aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (6.7.1)
Requirement already satisfied: aiohappyeyeballs>=2.5.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (2.6.2)
Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.8.0)
Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (26.1.0)
Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.24.2)
Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (0.5.2)
Requirement already satisfied: aiosignal>=1.4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.4.0)
Requirement already satisfied: async-timeout<6.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (5.0.1)
Requirement already satisfied: protobuf>=3.20.2 in /usr/local/lib/python3.10/dist-packages (from onnx>=1.16->onnxscript==0.2.0->-r ../../requirements_gpu.txt (line 4)) (4.25.3)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch==2.5.0->-r ../../requirements_gpu.txt (line 1)) (3.0.3)
Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /usr/local/lib/python3.10/dist-packages (from botocore<1.43.1,>=1.42.90->aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.26.20)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil<3.0.0,>=2.1->aiobotocore<4.0.0,>=2.19.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (1.17.0)
Requirement already satisfied: idna>=2.0 in /usr/local/lib/python3.10/dist-packages (from yarl<2.0,>=1.17.0->aiohttp!=4.0.0a0,!=4.0.0a1,>=3.9.0->s3fs->-r ../../requirements_gpu.txt (line 3)) (3.18)
WARNING: 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
Note: you may need to restart the kernel to use updated packages.
Requirement already satisfied: yacs in /usr/local/lib/python3.10/dist-packages (0.1.8)
Requirement already satisfied: timm in /usr/local/lib/python3.10/dist-packages (1.0.3)
Requirement already satisfied: termcolor in /usr/local/lib/python3.10/dist-packages (3.3.0)
Requirement already satisfied: PyYAML in /usr/local/lib/python3.10/dist-packages (from yacs) (6.0)
Requirement already satisfied: huggingface_hub in /usr/local/lib/python3.10/dist-packages (from timm) (0.36.2)
Requirement already satisfied: torchvision in /usr/local/lib/python3.10/dist-packages (from timm) (0.20.0)
Requirement already satisfied: safetensors in /usr/local/lib/python3.10/dist-packages (from timm) (0.8.0)
Requirement already satisfied: torch in /usr/local/lib/python3.10/dist-packages (from timm) (2.5.0)
Requirement already satisfied: hf-xet<2.0.0,>=1.1.3 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (1.5.1)
Requirement already satisfied: packaging>=20.9 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (26.2)
Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (2026.6.0)
Requirement already satisfied: tqdm>=4.42.1 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (4.66.4)
Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (4.15.0)
Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (3.16.1)
Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from huggingface_hub->timm) (2.31.0)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (3.1.6)
Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (1.13.1)
Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.4.127)
Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.4.127)
Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (11.2.1.3)
Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.4.127)
Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (11.6.1.9)
Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.4.127)
Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (2.21.5)
Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.4.5.8)
Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch->timm) (2.8.5)
Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.4.127)
Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (9.1.0.70)
Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (10.3.5.147)
Requirement already satisfied: triton==3.1.0 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (3.1.0)
Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /usr/local/lib/python3.10/dist-packages (from torch->timm) (12.3.1.170)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy==1.13.1->torch->timm) (1.3.0)
Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /usr/local/lib/python3.10/dist-packages (from torchvision->timm) (12.2.0)
Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from torchvision->timm) (1.24.4)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch->timm) (3.0.3)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub->timm) (3.4.7)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub->timm) (3.18)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub->timm) (2026.6.17)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->huggingface_hub->timm) (1.26.20)
WARNING: 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
Note: you may need to restart the kernel to use updated packages.
import os
import sys
import time
import copy
import logging
import itertools
import warnings
import tempfile
import random
import operator
from pathlib import Path
from dataclasses import dataclass
from datasets import load_from_disk
from typing import Optional
import numpy as np
from PIL import Image
import zipfile
import matplotlib.pyplot as plt

## Add project root to sys.path so `examples` can be imported as a package
_dir = Path(os.path.abspath(""))
while _dir != _dir.parent:
    if (_dir / "setup.cfg").exists():
        sys.path.insert(0, str(_dir))
        break
    _dir = _dir.parent

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.onnx
from torch.utils.data import DataLoader, Subset
from torch.export import export
from torch.ao.quantization.quantize_pt2e import (
    prepare_qat_pt2e,
    convert_pt2e,
)
from torch.ao.quantization.quantizer import (
    Quantizer,
    QuantizationSpec,
    FixedQParamsQuantizationSpec,
    QuantizationAnnotation,
)
from torch.ao.quantization.fake_quantize import FakeQuantize
from torch.ao.quantization.quantizer import QuantizationSpec
from torch.ao.quantization.observer import MovingAverageMinMaxObserver
from torch.fx.passes.utils.source_matcher_utils import get_source_partitions

import torchvision
from torchvision.datasets import ImageFolder
from torchvision.transforms.v2 import (
    RandomResizedCrop,
    RandomHorizontalFlip,
    RandomVerticalFlip,
    CenterCrop,
    Compose,
    Normalize,
    Resize,
    ToImage,
    ToDtype,
)

from tvm.contrib.epu.chimera_job.chimera_job import ChimeraJob
from tvm.relay.backend.contrib.epu.util import logger as tvm_logger
from tvm.contrib.epu.chimera_job.constants import DEFAULT_ONNX_OPSET

import sdk_cli.lib.qat_processor as processor
from sdk_cli.lib.chimera_job import ChimeraJob
from sdk_cli.utils.dataloaders import CalibrationDataLoader
from sdk_cli.utils.datasets import ImageNet_Mini_Quadric, QuadricCalibration
from sdk_cli.utils.datasets.ImageNet import (
    IMAGENET_1K_NORMALIZATION_PARAMETERS,
    OPTIMIZED_IMAGENET_1K_LABELS,
)
from sdk_cli.utils.model_helpers import ClassifyResult
from sdk_cli.utils.performance_trackers import ClassifierPerformanceTracker
from sdk_cli.lib.quantize import (
    QuantizationExperiment,
    QuantizedONNXModel,
    run_quantization_experiment,
    compute_tensor_ranges,
)

from examples.models.zoo.zoo_utils import download_file, onnx_check_and_simplify

warnings.filterwarnings(action="ignore", category=DeprecationWarning, module=r".*")
warnings.filterwarnings(action="default", module=r"torch.ao.quantization")

## NOTE: below are manually set for reproducability
torch.manual_seed(191009)
np.random.seed(2147483648)
random.seed(2147483648)
torch.use_deterministic_algorithms(True)
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"

torch.set_default_device("cuda")

1. Set up training helper functions

These will assist us in creating our training loop, based on those provided in the pt2e documentation page listed above.

class AverageMeter(object):
    def __init__(self, name, fmt=":f"):
        self.name = name
        self.fmt = fmt
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

    def __str__(self):
        return f"{name} {val:f} ({avg:f})"


def accuracy(output, target, topk=(1,)):
    with torch.no_grad():
        maxk = max(topk)
        batch_size = target.size(0)

        _, pred = output.topk(maxk, 1, True, True)
        pred = pred.t()
        correct = pred.eq(target.view(1, -1).expand_as(pred))

        res = []
        for k in topk:
            correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True)
            res.append(correct_k.mul_(100.0 / batch_size))
        return res


def get_kd_loss(output_student, output_teacher, temp, scale):
    kl_loss = nn.KLDivLoss(reduction="batchmean")
    loss_kl = kl_loss(
        F.log_softmax(output_student / temp, dim=1),
        F.softmax(output_teacher / temp, dim=1),
    )
    return scale * loss_kl


def train_one_epoch_distill(
    teacher,
    student,
    criterion,
    optimizer,
    temp,
    kd_scale,
    loss_data,
    data_loader,
    ntrain_batches,
):
    top1 = AverageMeter("Acc@1")
    top5 = AverageMeter("Acc@5")
    avgloss = AverageMeter("Loss")

    cnt = 0
    for pair in data_loader:
        start_time = time.time()

        optimizer.zero_grad()
        image, target = pair.values()
        image = image.to("cuda")
        target = target.to("cuda")

        print(".", end="")
        cnt += 1

        student_output = student(image)
        with torch.no_grad():
            teacher_output = teacher(image)

        ce_loss = criterion(student_output, target)
        loss = ce_loss + get_kd_loss(student_output, teacher_output, temp, kd_scale)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        torch.cuda.synchronize()

        acc1, acc5 = accuracy(student_output, target, topk=(1, 5))
        top1.update(acc1[0], image.size(0))
        top5.update(acc5[0], image.size(0))
        avgloss.update(loss, image.size(0))
        if cnt >= ntrain_batches:
            print("Loss", avgloss.avg)
            loss_data.append(avgloss.avg.item())
            print(
                "Training: * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}".format(top1=top1, top5=top5)
            )
            return


def evaluate(model, data_loader, neval_batches):
    top1 = AverageMeter("Acc@1", ":6.2f")
    top5 = AverageMeter("Acc@5", ":6.2f")
    cnt = 0
    with torch.no_grad():
        for image, target in data_loader:
            image = image.cuda(non_blocking=True)
            target = target.cuda(non_blocking=True)
            output = model(image)
            cnt += 1
            acc1, acc5 = accuracy(output, target, topk=(1, 5))
            top1.update(acc1[0], image.size(0))
            top5.update(acc5[0], image.size(0))
            if cnt >= neval_batches:
                return top1, top5
    print("")

    return top1, top5


def print_data_graph(data, title, x_label, y_label):
    y_margin = 0.1 * (np.max(data) - np.min(data))
    f, ax = plt.subplots(1)
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    plt.title(title)
    ax.set_xlim(left=0, right=len(data) + 1)
    ax.set_xticks(np.linspace(0, len(data), int(len(data) / 5) + 1))
    ax.set_ylim(bottom=np.min(data) - y_margin, top=np.max(data) + y_margin)
    ax.plot(range(1, len(data) + 1), data)
    plt.show()

2. Define our quantization configuration

The pt2e quantization library is extremely flexible. It allows us to define the method of quantization for each tensor of each individual operation. Here we will define a simple quantization configuration, but you may choose to experiment with the options available.

sym_fake_quant = FakeQuantize.with_args(
    observer=MovingAverageMinMaxObserver,
    quant_min=-128,
    quant_max=127,
    dtype=torch.qint8,
    qscheme=torch.per_tensor_symmetric,
)
sym_spec = QuantizationSpec(
    observer_or_fake_quant_ctr=sym_fake_quant,
    dtype=torch.int8,
    quant_min=-128,
    quant_max=127,
    qscheme=torch.per_tensor_symmetric,
)


class QuadricQuantizer(Quantizer):
    def __init__(self):
        super().__init__()

    def annotate(self, model: torch.fx.GraphModule) -> torch.fx.GraphModule:
        self._annotate_add(model)
        self._annotate_conv2d(model)
        self._annotate_linear(model)
        self._annotate_matmul(model)
        self._annotate_average_pool(model)
        return model

    def _annotate_add(self, model: torch.fx.GraphModule):
        add_partitions = get_source_partitions(
            model.graph, [operator.add, torch.add, torch.Tensor.add, torch.Tensor.add_]
        )
        add_partitions = list(itertools.chain(*add_partitions.values()))
        for partition in add_partitions:
            add_node = partition.output_nodes[0]

            if "unsqueeze" not in add_node.args[1].name:
                continue

            # Skip mask adds (5D tensor) - only quantize bias adds (4D tensor)
            # Mask adds have shape like (1, 64, 1, 49, 49) for attention mask
            # Bias adds have shape like (1, 4, 49, 49) for relative position bias
            arg1_meta = add_node.args[1].meta.get("tensor_meta") or add_node.args[1].meta.get("val")
            if arg1_meta is not None and hasattr(arg1_meta, "shape"):
                if len(arg1_meta.shape) == 5:
                    continue

            input_qspec_map = {
                add_node.args[0]: sym_spec,
                add_node.args[1]: sym_spec,
            }
            add_node.meta["quantization_annotation"] = QuantizationAnnotation(
                input_qspec_map=input_qspec_map,
                output_qspec=sym_spec,
                _annotated=True,
            )

    def _annotate_conv2d(self, model: torch.fx.GraphModule):
        conv_partitions = get_source_partitions(model.graph, [nn.Conv2d, F.conv2d])
        conv_partitions = list(itertools.chain(*conv_partitions.values()))
        for partition in conv_partitions:
            conv_node = partition.output_nodes[0]
            input_qspec_map = {
                conv_node.args[0]: sym_spec,
                conv_node.args[1]: sym_spec,
            }
            conv_node.meta["quantization_annotation"] = QuantizationAnnotation(
                input_qspec_map=input_qspec_map,
                output_qspec=sym_spec,
                _annotated=True,
            )

    def _annotate_linear(self, model: torch.fx.GraphModule):
        linear_partitions = get_source_partitions(model.graph, [nn.Linear, F.linear])
        linear_partitions = list(itertools.chain(*linear_partitions.values()))
        for partition in linear_partitions:
            linear_node = partition.output_nodes[0]
            input_qspec_map = {
                linear_node.args[0]: sym_spec,
                linear_node.args[1]: sym_spec,
            }
            linear_node.meta["quantization_annotation"] = QuantizationAnnotation(
                input_qspec_map=input_qspec_map,
                output_qspec=sym_spec,
                _annotated=True,
            )

    def _annotate_matmul(self, model: torch.fx.GraphModule):
        matmul_partitions = get_source_partitions(
            model.graph, [operator.matmul, torch.matmul, torch.mm]
        )
        matmul_partitions = list(itertools.chain(*matmul_partitions.values()))
        for partition in matmul_partitions:
            matmul_node = partition.output_nodes[0]
            input_qspec_map = {
                matmul_node.args[0]: sym_spec,
                matmul_node.args[1]: sym_spec,
            }
            matmul_node.meta["quantization_annotation"] = QuantizationAnnotation(
                input_qspec_map=input_qspec_map,
                output_qspec=sym_spec,
                _annotated=True,
            )

    def _annotate_average_pool(self, model: torch.fx.GraphModule):
        gap_partitions = get_source_partitions(
            model.graph,
            [nn.AvgPool1d, nn.AdaptiveAvgPool1d, F.avg_pool1d, F.adaptive_avg_pool1d],
        )
        gap_partitions = list(itertools.chain(*gap_partitions.values()))
        for partition in gap_partitions:
            gap_node = partition.output_nodes[0]
            input_qspec_map = {
                gap_node.args[0]: sym_spec,
            }
            gap_node.meta["quantization_annotation"] = QuantizationAnnotation(
                input_qspec_map=input_qspec_map, output_qspec=sym_spec, _annotated=True
            )

    def validate(self, model):
        pass

    @classmethod
    def get_supported_operators(cls):
        return []

3. Prepare the training/evaluation data

We use images from ImageNet-1K to perform the training and evaluation. All input tensors in this dataset are of dimension NCHW format [3, 224, 224] and need to be float-normalized with a mean, sigma of [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]. For training, we include the transformations RandomResizedCrop, RandomHorizontalFlip, and RandomVerticalFlip for robustness.

normalize = Normalize(
    IMAGENET_1K_NORMALIZATION_PARAMETERS.channel_means,
    IMAGENET_1K_NORMALIZATION_PARAMETERS.channel_standard_deviations,
)
to_tensor = Compose([ToImage(), ToDtype(torch.float32, scale=True)])
train_transforms = Compose(
    [
        RandomResizedCrop(224),
        RandomHorizontalFlip(),
        RandomVerticalFlip(),
        to_tensor,
        normalize,
    ]
)
test_transforms = Compose(
    [
        Resize(224),
        CenterCrop(224),
        to_tensor,
        normalize,
    ]
)


def apply_transforms(imgs):
    imgs["image"] = [train_transforms(img.convert("RGB")) for img in imgs["image"]]
    return imgs


train_set = load_from_disk(
    "s3://sdk-cli-datasets/imagenet_1k_val_train.hf/validation",
    storage_options={"anon": True},
)
train_set.set_transform(apply_transforms)
test_set = ImageFolder(
    root="../../common/validation/imagenet-mini-quadric/val", transform=test_transforms
)

train_batch_size = 1
test_batch_size = 1
generator_train = torch.Generator(device="cuda")
generator_train.manual_seed(67280421310721)
generator_test = torch.Generator(device="cuda")
generator_test.manual_seed(672804213107421)
sampler_train = torch.utils.data.RandomSampler(train_set, generator=generator_train)
sampler_test = torch.utils.data.SequentialSampler(test_set)
data_loader_train = torch.utils.data.DataLoader(
    train_set,
    batch_size=train_batch_size,
    generator=generator_train,
    sampler=sampler_train,
)
data_loader_test = torch.utils.data.DataLoader(
    test_set,
    batch_size=test_batch_size,
    generator=generator_test,
    sampler=sampler_test,
)
/usr/local/lib/python3.10/dist-packages/datasets/table.py:1421: FutureWarning: promote has been superseded by promote_options='default'.
  table = cls._concat_blocks(blocks, axis=0)

4. Load Swin from official Microsoft repository

Here we use the swin_base_patch4_window7_224_22kto1k model. The original graph goes through a 2-step process using torch.export.export_for_training and the previously defined QuadricQuantizer in order to be ready for QAT.

basename = Path("Swin-Transformer")

## Install Swin-Transformer.
if basename.exists():
    print(f"Existing {basename} is used.")
else:
    url = "https://github.com/microsoft/Swin-Transformer/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)
    os.remove(filename)
    print(f"{basename} is installed.")

## Make symbolic links for later experiment.
symlink_list = ["configs", "models", "config.py", "logger.py", "utils.py"]

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")
Swin-Transformer is installed.
configs is symbolic
models is symbolic
config.py is symbolic
logger.py is symbolic
utils.py is symbolic
MODEL_NAME = "swin_base_patch4_window7_224_22kto1k"

weights_url = (
    f"https://github.com/SwinTransformer/storage/releases/download/v1.0.0/{MODEL_NAME}.pth"
)
config = f"configs/swin/{MODEL_NAME}_finetune.yaml"

weights = Path(weights_url).name
if not Path(weights).exists():
    download_file(weights_url, weights)
    print(f"{weights} is downloaded.")
swin_base_patch4_window7_224_22kto1k.pth is downloaded.
from config import get_config
from models import build_model
from logger import create_logger
from utils import load_pretrained


class swin_args:
    def __init__(self):
        self.cfg = config
        self.opts = []
        self.pretrained = weights


os.environ["LOCAL_RANK"] = "0"

args = swin_args()
config = get_config(args)

os.makedirs(config.OUTPUT, exist_ok=True)
logger = create_logger(output_dir=config.OUTPUT, name=f"{config.MODEL.NAME}")

logger.info(f"Creating model:{config.MODEL.TYPE}/{config.MODEL.NAME}")
float_model = build_model(config)

n_parameters = sum(p.numel() for p in float_model.parameters() if p.requires_grad)
logger.info(f"number of params: {n_parameters}")
if hasattr(float_model, "flops"):
    flops = float_model.flops()
    logger.info(f"number of GFLOPs: {flops / 1e9}")

load_pretrained(config, float_model, logger)
[Warning] Fused window process have not been installed. Please refer to get_started.md for installation.
Tutel has not been installed. To use Swin-MoE, please install Tutel; otherwise, just ignore this.
=> merge config from configs/swin/swin_base_patch4_window7_224_22kto1k_finetune.yaml
[2026-06-19 06:21:07 swin_base_patch4_window7_224_22kto1k_finetune](2345668462.py 22): INFO Creating model:swin/swin_base_patch4_window7_224_22kto1k_finetune


/usr/local/lib/python3.10/dist-packages/torch/functional.py:534: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at ../aten/src/ATen/native/TensorShape.cpp:3595.)
  return _VF.meshgrid(tensors, **kwargs)  # type: ignore[attr-defined]


[2026-06-19 06:21:07 swin_base_patch4_window7_224_22kto1k_finetune](2345668462.py 26): INFO number of params: 87768224
[2026-06-19 06:21:07 swin_base_patch4_window7_224_22kto1k_finetune](2345668462.py 29): INFO number of GFLOPs: 15.438473216
[2026-06-19 06:21:07 swin_base_patch4_window7_224_22kto1k_finetune](utils.py 46): INFO ==============> Loading weight swin_base_patch4_window7_224_22kto1k.pth for fine-tuning......


/quadric/sdk-cli/examples/models/swin/utils.py:47: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.
  checkpoint = torch.load(config.MODEL.PRETRAINED, map_location='cpu')


[2026-06-19 06:21:07 swin_base_patch4_window7_224_22kto1k_finetune](utils.py 127): WARNING _IncompatibleKeys(missing_keys=['layers.0.blocks.0.attn.relative_position_index', 'layers.0.blocks.1.attn_mask', 'layers.0.blocks.1.attn.relative_position_index', 'layers.1.blocks.0.attn.relative_position_index', 'layers.1.blocks.1.attn_mask', 'layers.1.blocks.1.attn.relative_position_index', 'layers.2.blocks.0.attn.relative_position_index', 'layers.2.blocks.1.attn_mask', 'layers.2.blocks.1.attn.relative_position_index', 'layers.2.blocks.2.attn.relative_position_index', 'layers.2.blocks.3.attn_mask', 'layers.2.blocks.3.attn.relative_position_index', 'layers.2.blocks.4.attn.relative_position_index', 'layers.2.blocks.5.attn_mask', 'layers.2.blocks.5.attn.relative_position_index', 'layers.2.blocks.6.attn.relative_position_index', 'layers.2.blocks.7.attn_mask', 'layers.2.blocks.7.attn.relative_position_index', 'layers.2.blocks.8.attn.relative_position_index', 'layers.2.blocks.9.attn_mask', 'layers.2.blocks.9.attn.relative_position_index', 'layers.2.blocks.10.attn.relative_position_index', 'layers.2.blocks.11.attn_mask', 'layers.2.blocks.11.attn.relative_position_index', 'layers.2.blocks.12.attn.relative_position_index', 'layers.2.blocks.13.attn_mask', 'layers.2.blocks.13.attn.relative_position_index', 'layers.2.blocks.14.attn.relative_position_index', 'layers.2.blocks.15.attn_mask', 'layers.2.blocks.15.attn.relative_position_index', 'layers.2.blocks.16.attn.relative_position_index', 'layers.2.blocks.17.attn_mask', 'layers.2.blocks.17.attn.relative_position_index', 'layers.3.blocks.0.attn.relative_position_index', 'layers.3.blocks.1.attn.relative_position_index'], unexpected_keys=[])
[2026-06-19 06:21:07 swin_base_patch4_window7_224_22kto1k_finetune](utils.py 129): INFO => loaded successfully 'swin_base_patch4_window7_224_22kto1k.pth'
example_input = torch.rand(1, 3, 224, 224)
exported_model = torch.export.export_for_training(float_model, (example_input,)).module()

quantizer = QuadricQuantizer()
prepared_model = prepare_qat_pt2e(exported_model, quantizer)
for n in prepared_model.graph.nodes:
    if n.target == torch.ops.aten._native_batch_norm_legit.default:
        n.target = torch.ops.aten.cudnn_batch_norm.default
_ = prepared_model.recompile()

_ = float_model.eval()
/usr/local/lib/python3.10/dist-packages/onnxscript/converter.py:823: FutureWarning: 'onnxscript.values.Op.param_schemas' is deprecated in version 0.1 and will be removed in the future. Please use '.op_signature' instead.
  param_schemas = callee.param_schemas()
/usr/local/lib/python3.10/dist-packages/onnxscript/converter.py:823: FutureWarning: 'onnxscript.values.OnnxFunction.param_schemas' is deprecated in version 0.1 and will be removed in the future. Please use '.op_signature' instead.
  param_schemas = callee.param_schemas()

5. Perform QAT using the pt2e library

We follow the documentation given here. We start by defining some hyperparameters here, which can be altered to experiment with different setups.

num_epochs = 40
num_train_batches = 32
num_eval_batches = 1500
final_num_eval_batches = 3500
num_epochs_between_evals = 10
num_observer_update_epochs = 1000
num_batch_norm_update_epochs = 0

num_warmup_epochs = 5
temp = 3
kd_scale = 0.3

checkpoints = []
lr_data = []
loss_data = []
eval_data = []

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(prepared_model.parameters(), lr=2e-6, weight_decay=1e-5, amsgrad=True)

warmup_scheduler = torch.optim.lr_scheduler.LinearLR(
    optimizer, start_factor=1e-3, total_iters=num_warmup_epochs
)
cosine_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
    optimizer, T_max=num_epochs - num_warmup_epochs, eta_min=1e-9
)
scheduler = torch.optim.lr_scheduler.SequentialLR(
    optimizer,
    schedulers=[warmup_scheduler, cosine_scheduler],
    milestones=[num_warmup_epochs],
)
num_observer_update_flag = True
num_batch_norm_update_flag = True

for epoch in range(num_epochs):
    if epoch + 1 >= num_observer_update_epochs and num_observer_update_flag:
        print("Disabling observer for subseq epochs, epoch = ", epoch)
        prepared_model.apply(torch.ao.quantization.disable_observer)
        num_observer_update_flag = False

    if epoch + 1 >= num_batch_norm_update_epochs and num_batch_norm_update_flag:
        print("Freezing BN for subseq epochs, epoch = ", epoch)
        for n in prepared_model.graph.nodes:
            if n.target in [
                torch.ops.aten._native_batch_norm_legit.default,
                torch.ops.aten.cudnn_batch_norm.default,
            ]:
                new_args = list(n.args)
                new_args[5] = False
                n.args = tuple(new_args)
        prepared_model.recompile()
        num_batch_norm_update_flag = False

    train_one_epoch_distill(
        float_model,
        prepared_model,
        criterion,
        optimizer,
        temp,
        kd_scale,
        loss_data,
        data_loader_train,
        num_train_batches,
    )

    print("^ Epoch: %d" % (epoch + 1))
    current_lr = optimizer.param_groups[0]["lr"]
    lr_data.append(current_lr)
    print(f"^ LR = {current_lr:.8f}")

    if (epoch + 1) % num_epochs_between_evals == 0:
        checkpoints.append(copy.deepcopy(prepared_model.state_dict()))
        prepared_model_copy = copy.deepcopy(prepared_model)
        quantized_model = convert_pt2e(prepared_model_copy)
        torch.ao.quantization.move_exported_model_to_eval(quantized_model)

        top1, top5 = evaluate(
            quantized_model,
            data_loader_test,
            neval_batches=num_eval_batches,
        )
        eval_data.append(top1.avg.item())
        print(
            "Epoch %d: Evaluation accuracy on %d images, %2.2f\n"
            % (epoch + 1, num_eval_batches * test_batch_size, top1.avg)
        )
        del prepared_model_copy
        del quantized_model

    scheduler.step()
Freezing BN for subseq epochs, epoch =  0
................................Loss tensor(1.6335, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 87.500
^ Epoch: 1
^ LR = 0.00000000
................................Loss tensor(1.3526, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 90.625
^ Epoch: 2
^ LR = 0.00000040
................................Loss tensor(1.1511, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 96.875
^ Epoch: 3
^ LR = 0.00000080
................................Loss tensor(1.0684, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 84.375 Acc@5 93.750
^ Epoch: 4
^ LR = 0.00000120
................................Loss tensor(1.1151, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 93.750
^ Epoch: 5
^ LR = 0.00000160


/usr/local/lib/python3.10/dist-packages/torch/optim/lr_scheduler.py:240: UserWarning: The epoch parameter in `scheduler.step()` was not necessary and is being deprecated where possible. Please use `scheduler.step()` to step the scheduler. During the deprecation, if epoch is different from None, the closed form is used instead of the new chainable form, where available. Please open an issue if you are unable to replicate your use case: https://github.com/pytorch/pytorch/issues/new/choose.
  warnings.warn(EPOCH_DEPRECATION_WARNING, UserWarning)


................................Loss tensor(1.8048, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 84.375
^ Epoch: 6
^ LR = 0.00000200
................................Loss tensor(1.3107, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 81.250 Acc@5 90.625
^ Epoch: 7
^ LR = 0.00000200
................................Loss tensor(0.8758, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 84.375 Acc@5 93.750
^ Epoch: 8
^ LR = 0.00000198
................................Loss tensor(1.7778, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 87.500
^ Epoch: 9
^ LR = 0.00000196
................................Loss tensor(0.9489, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 81.250 Acc@5 100.000
^ Epoch: 10
^ LR = 0.00000194


W0619 06:22:30.514000 30879 torch/_export/__init__.py:64] +============================+
W0619 06:22:30.514000 30879 torch/_export/__init__.py:65] |     !!!   WARNING   !!!    |
W0619 06:22:30.515000 30879 torch/_export/__init__.py:66] +============================+
W0619 06:22:30.515000 30879 torch/_export/__init__.py:67] capture_pre_autograd_graph() is deprecated and doesn't provide any function guarantee moving forward.
W0619 06:22:30.515000 30879 torch/_export/__init__.py:68] Please switch to use torch.export.export_for_training instead.


Epoch 10: Evaluation accuracy on 1500 images, 81.27

................................Loss tensor(1.6679, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 68.750 Acc@5 84.375
^ Epoch: 11
^ LR = 0.00000190
................................Loss tensor(1.3037, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 68.750 Acc@5 93.750
^ Epoch: 12
^ LR = 0.00000186
................................Loss tensor(1.4886, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 87.500
^ Epoch: 13
^ LR = 0.00000181
................................Loss tensor(1.5117, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 71.875 Acc@5 84.375
^ Epoch: 14
^ LR = 0.00000175
................................Loss tensor(1.6722, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 78.125
^ Epoch: 15
^ LR = 0.00000169
................................Loss tensor(1.3512, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 84.375
^ Epoch: 16
^ LR = 0.00000162
................................Loss tensor(1.6839, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 84.375
^ Epoch: 17
^ LR = 0.00000155
................................Loss tensor(1.7368, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 84.375
^ Epoch: 18
^ LR = 0.00000147
................................Loss tensor(1.5558, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 90.625
^ Epoch: 19
^ LR = 0.00000139
................................Loss tensor(1.1229, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 78.125 Acc@5 93.750
^ Epoch: 20
^ LR = 0.00000131
Epoch 20: Evaluation accuracy on 1500 images, 81.73

................................Loss tensor(1.4364, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 71.875 Acc@5 90.625
^ Epoch: 21
^ LR = 0.00000122
................................Loss tensor(1.0169, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 93.750
^ Epoch: 22
^ LR = 0.00000113
................................Loss tensor(1.6169, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 81.250
^ Epoch: 23
^ LR = 0.00000105
................................Loss tensor(1.1480, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 90.625
^ Epoch: 24
^ LR = 0.00000096
................................Loss tensor(1.5082, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 68.750 Acc@5 87.500
^ Epoch: 25
^ LR = 0.00000087
................................Loss tensor(1.9860, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 59.375 Acc@5 78.125
^ Epoch: 26
^ LR = 0.00000078
................................Loss tensor(1.3548, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 93.750
^ Epoch: 27
^ LR = 0.00000069
................................Loss tensor(1.8283, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 78.125
^ Epoch: 28
^ LR = 0.00000061
................................Loss tensor(1.8307, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 56.250 Acc@5 84.375
^ Epoch: 29
^ LR = 0.00000053
................................Loss tensor(1.8659, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 53.125 Acc@5 78.125
^ Epoch: 30
^ LR = 0.00000045
Epoch 30: Evaluation accuracy on 1500 images, 81.67

................................Loss tensor(0.9725, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 78.125 Acc@5 96.875
^ Epoch: 31
^ LR = 0.00000038
................................Loss tensor(1.3465, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 78.125 Acc@5 84.375
^ Epoch: 32
^ LR = 0.00000031
................................Loss tensor(1.7764, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 87.500
^ Epoch: 33
^ LR = 0.00000025
................................Loss tensor(0.8728, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 84.375 Acc@5 96.875
^ Epoch: 34
^ LR = 0.00000019
................................Loss tensor(1.5865, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 62.500 Acc@5 84.375
^ Epoch: 35
^ LR = 0.00000014
................................Loss tensor(0.9351, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 81.250 Acc@5 93.750
^ Epoch: 36
^ LR = 0.00000010
................................Loss tensor(1.9387, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 65.625 Acc@5 75.000
^ Epoch: 37
^ LR = 0.00000006
................................Loss tensor(1.1755, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 71.875 Acc@5 93.750
^ Epoch: 38
^ LR = 0.00000004
................................Loss tensor(0.8961, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 75.000 Acc@5 96.875
^ Epoch: 39
^ LR = 0.00000002
................................Loss tensor(1.5234, device='cuda:0', grad_fn=<DivBackward0>)
Training: * Acc@1 71.875 Acc@5 90.625
^ Epoch: 40
^ LR = 0.00000001
Epoch 40: Evaluation accuracy on 1500 images, 83.20

6. ONNX export and post-processing

We use torch.onnx.dynamo_export() to export the graph from PyTorch to ONNX and use Quadric's QAT post-processor in order to clean up the graph and format it nicely. We start here with the conversion from PyTorch to ONNX.

<div class="alert alert-block alert-warning"> <b>Note:</b> Because torch.onnx.dynamo_export is a work in progress, there will be many warnings generated for now. There are no adverse effects. These are just remnants from other functionalities, so they can be ignored. But they cannot be suppressed as they are thrown by the underlying C++. </div>

print_data_graph(lr_data, "LR data", "Epochs", "LR")
print_data_graph(loss_data, "Loss data", "Epochs", "CCE Loss")
print_data_graph(eval_data, "Eval data", f"Epochs / {num_epochs_between_evals}", "T1 Accuracy")

quantized_model = convert_pt2e(prepared_model)
torch.ao.quantization.move_exported_model_to_eval(quantized_model)
top1, top5 = evaluate(quantized_model, data_loader_test, neval_batches=final_num_eval_batches)
print(
    "Final evaluation accuracy on %d images, (Top-1): %2.2f"
    % (final_num_eval_batches * test_batch_size, top1.avg)
)
print(
    "Final evaluation accuracy on %d images, (Top-5): %2.2f"
    % (final_num_eval_batches * test_batch_size, top5.avg)
)

onnx_program = torch.onnx.dynamo_export(quantized_model, example_input)
onnx_program.save("swin-unprocessed.onnx")

Final evaluation accuracy on 3500 images, (Top-1): 80.89
Final evaluation accuracy on 3500 images, (Top-5): 95.89


/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/_exporter_legacy.py:116: UserWarning: torch.onnx.dynamo_export only implements opset version 18 for now. If you need to use a different opset version, please register them with register_custom_op.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/passes/readability.py:52: UserWarning: Attempted to insert a get_attr Node with no underlying reference in the owning GraphModule! Call GraphModule.add_submodule to add the necessary submodule, GraphModule.add_parameter to add the necessary Parameter, or nn.Module.register_buffer to add the necessary buffer
  new_node = self.module.graph.get_attr(normalized_name)
/usr/local/lib/python3.10/dist-packages/torch/fx/graph.py:1586: UserWarning: Node _frozen_param0 target _frozen_param0 _frozen_param0 of  does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target
  warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '
/usr/local/lib/python3.10/dist-packages/torch/fx/graph.py:1586: UserWarning: Node _frozen_param1 target _frozen_param1 _frozen_param1 of  does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target
  warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '
/usr/local/lib/python3.10/dist-packages/torch/fx/graph.py:1586: UserWarning: Node _frozen_param2 target _frozen_param2 _frozen_param2 of  does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target
  warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '
/usr/local/lib/python3.10/dist-packages/torch/fx/graph.py:1586: UserWarning: Node _frozen_param3 target _frozen_param3 _frozen_param3 of  does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target
  warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '
/usr/local/lib/python3.10/dist-packages/torch/fx/graph.py:1586: UserWarning: Node _frozen_param4 target _frozen_param4 _frozen_param4 of  does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target
  warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '
/usr/local/lib/python3.10/dist-packages/torch/fx/graph.py:1593: UserWarning: Additional 131 warnings suppressed about get_attr references
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/torch/onnx/_internal/fx/onnxfunction_dispatcher.py:503: FutureWarning: 'onnxscript.values.TracedOnnxFunction.param_schemas' is deprecated in version 0.1 and will be removed in the future. Please use '.op_signature' instead.
  self.param_schema = self.onnxfunction.param_schemas()
Skipping constant folding for op SequenceEmpty with multiple outputs.


Applied 171 of general pattern rewrite rules.


Skipping constant folding for op SequenceEmpty with multiple outputs.

The next step uses Quadric's PyTorch graph post-processor. We avoid quantizing residual adds here for accuracy preservation

Handled ops/patterns:

  • Conv (+ BatchNormalization + activation)
  • Gemm
  • MatMul
  • Add
  • GlobalAveragePool
  • MHA (limited to ViT and Swin examples)
  • aten_bernoulli_p
  • aten_gelu_approximate_none
  • aten_roll_shift_and_dim
  • aten_as_strided
  • aten_constant_pad_nd
torch.set_default_device("cpu")
output_path = "./swin-processed.onnx"
qat_processor = processor.QATProcessor()
qat_processor.process(
    "swin-unprocessed.onnx",
    ptq_sym_act=True,
    strip_onnx=False,
    output_path=output_path,
)
2026-06-19 06:33 - DEBUG - epu - qat_processor - Preparing calibration data
/usr/local/lib/python3.10/dist-packages/datasets/table.py:1421: FutureWarning: promote has been superseded by promote_options='default'.
  table = cls._concat_blocks(blocks, axis=0)
2026-06-19 06:33 - DEBUG - epu - qat_processor - Fixing PyTorch exported Unsqueeze axes arg
2026-06-19 06:33 - DEBUG - epu - qat_processor - Removing aten.bernoulli ops
2026-06-19 06:33 - DEBUG - epu - qat_processor - Removing NOP aten.pad ops
2026-06-19 06:33 - DEBUG - epu - qat_processor - Removing aten.as_strided ops
2026-06-19 06:33 - DEBUG - epu - qat_processor - Swapping aten.gelu ops for ONNX equivalent
2026-06-19 06:33 - DEBUG - epu - qat_processor - Swapping aten.roll ops for ONNX equivalent
2026-06-19 06:33 - DEBUG - epu - qat_processor - Swapping ReduceMean for GlobalAveragePool
2026-06-19 06:33 - DEBUG - epu - qat_processor - Removing Dropout ops with rate=0
2026-06-19 06:33 - DEBUG - epu - qat_processor - Removing redundant QDQs
2026-06-19 06:33 - DEBUG - epu - qat_processor - Folding Div into BatchNormalization
2026-06-19 06:33 - DEBUG - epu - qat_processor - Folding BatchNormalization into Conv nodes with biases
2026-06-19 06:33 - DEBUG - epu - qat_processor - Folding BatchNormalization into Conv nodes without biases
2026-06-19 06:33 - DEBUG - epu - qat_processor - Quantizing Swin MHA blocks
WARNING:root:Please use QuantFormat.QDQ for activation type QInt8 and weight type QInt8. Or it will lead to bad performance on x64.
WARNING:root:Please check if the model is already quantized. Note you don't need to quantize a QAT model. OnnxRuntime support to run QAT model directly.
2026-06-19 06:39 - DEBUG - epu - qat_processor - Quantizing FC layers
WARNING:root:Please use QuantFormat.QDQ for activation type QInt8 and weight type QInt8. Or it will lead to bad performance on x64.
WARNING:root:Please check if the model is already quantized. Note you don't need to quantize a QAT model. OnnxRuntime support to run QAT model directly.
2026-06-19 06:46 - DEBUG - epu - qat_processor - Quantizing QKV MatMul ops
2026-06-19 06:46 - DEBUG - epu - qat_processor - Changing to Opset 17
2026-06-19 06:46 - DEBUG - epu - qat_processor - Performing ORT optimizations
2026-06-19 06:46 - DEBUG - epu - qat_processor - Unfolding QLinearSoftmax to avoid inaccurate LUT
2026-06-19 06:46 - DEBUG - epu - qat_processor - Fusing QLinearConv
2026-06-19 06:46 - DEBUG - epu - qat_processor - Fusing QGemm
2026-06-19 06:46 - DEBUG - epu - qat_processor - Folding DQ into MatMul ops where ORT does not
2026-06-19 06:46 - DEBUG - epu - qat_processor - Moving DQ outside of Roll patterns
2026-06-19 06:46 - DEBUG - epu - qat_processor - Moving from uint8 to int8

7. Prepare the validation dataset

Now that the QAT model has been saved to disk, we will compare it to the original pretrained FP32 model from PyTorch. Here we use a set of 3500 images in our validation of the model.

torch.set_default_device("cpu")
MAX_NUM_SAMPLES_FOR_ACCURACY_CALCULATION = 3500

graph_input_name = "l_x_"
assert isinstance(graph_input_name, str)

normalize = Normalize(
    IMAGENET_1K_NORMALIZATION_PARAMETERS.channel_means,
    IMAGENET_1K_NORMALIZATION_PARAMETERS.channel_standard_deviations,
)
to_tensor = Compose([ToImage(), ToDtype(torch.float32, scale=True)])
test_transforms = Compose(
    [
        Resize(224),
        CenterCrop(224),
        to_tensor,
        normalize,
    ]
)

dataset = ImageNet_Mini_Quadric.Dataset(transform=test_transforms)
subset_of_dataset = Subset(dataset, range(MAX_NUM_SAMPLES_FOR_ACCURACY_CALCULATION))
calibration_dataloader = CalibrationDataLoader(
    DataLoader(subset_of_dataset, batch_size=1, shuffle=True), [graph_input_name]
)

8. Validate and compare against FP32 model

Now we want to make sure that quantization was done succesfully by checking the performance of the original model against the quantized model.

fp32_path = "./swin_base_float32.onnx"
int8_path = output_path

torch.onnx.export(
    float_model,
    example_input,
    fp32_path,
    input_names=[graph_input_name],
    export_params=True,
    opset_version=17,
)

onnx_model_path = Path(fp32_path)
quantized_onnx_model = QuantizedONNXModel(int8_path, None)

## Evaluation
quantization_experiment = QuantizationExperiment(
    floating_point_onnx_model_path=onnx_model_path,
    quantized_onnx_model=quantized_onnx_model,
    performance_tracker=ClassifierPerformanceTracker(),
    disable_opt=True,
)
run_quantization_experiment(
    quantization_experiment,
    calibration_dataloader,
    export_path=None,
    max_num_samples=MAX_NUM_SAMPLES_FOR_ACCURACY_CALCULATION,
)
3500: FP3284.03% <> INT877.83%: 100%|██████████| 3500/3500 [17:59<00:00,  3.24it/s]


Used 3500 image samples for model accuracy comparison.
Original FP32 model accuracy (Top-1): 84.03%
Quantized INT8 model accuracy (Top-1): 77.83%
Change in Top-1 model accuracy due to quantization: 6.20%

9. Lower the graph in CGC

We first create the tensor-ranges file, then lower the graph.

warnings.filterwarnings(action="ignore")
tvm_logger.setLevel(logging.WARNING)

MAX_NUM_SAMPLES_FOR_CALIBRATION = 1000
calibration_dataset = ImageNet_Mini_Quadric.Dataset(transform=test_transforms)
calibration_dataset = Subset(calibration_dataset, range(MAX_NUM_SAMPLES_FOR_CALIBRATION))
trange_path = f"{int8_path}.tranges"

_ = compute_tensor_ranges(
    onnx_model_path=int8_path,
    calibration_dataloader=CalibrationDataLoader(calibration_dataset, [graph_input_name]),
    tensor_ranges_export_path=trange_path,
)
2026-06-19 07:09 - INFO - sdk - quantize - Saved computed tensor ranges to ./swin-processed.onnx.tranges.
from tvm.contrib.epu.chimera_job.hw_config import DEFAULT_32_ARRAY_SIZE_8MAC

hw_cfg = DEFAULT_32_ARRAY_SIZE_8MAC

cgc_job = ChimeraJob(
    hw_config=hw_cfg,
    model_p=int8_path,
    onnx_ort_override_p=int8_path,
    trange_file=trange_path,
)
from tvm.relay.backend.contrib.epu.directives import generate_patch_merge_directives

## Add directives to skip quantizing patch merge
span_directives, _ = generate_patch_merge_directives(int8_path)
cgc_job.span_directives = span_directives

cgc_job.compile(quiet=True)
print(cgc_job)
╒═════════════════════╤══════════════════════════════════════════════════════════════╕
│ Module Name         │ swin_processed_QC_U_1d7_16MB_4kB_128GBps_128GBps_8_OFF_x1_x1 │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ ONNX File           │ ./swin-processed.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         │ 8                                                            │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ Max L2M             │ 14.839MB                                                     │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ Max LRM             │ 3.000kB                                                      │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ Max Temp Ext Bytes  │ 0.000MB                                                      │
├─────────────────────┼──────────────────────────────────────────────────────────────┤
│ Network GMACs       │ 15.431                                                       │
╘═════════════════════╧══════════════════════════════════════════════════════════════╛

╒════╤════════╤═══════════════════════════╤══════════════════╤══════════════════════════╤═══════╕
│    │ Type   │ Name                      │ shape            │ type                     │ mse   │
╞════╪════════╪═══════════════════════════╪══════════════════╪══════════════════════════╪═══════╡
│  0 │ Input  │ l_x_                      │ [1, 3, 224, 224] │ tensor[FixedPoint32<29>] │ n/a   │
├────┼────────┼───────────────────────────┼──────────────────┼──────────────────────────┼───────┤
│  1 │ Output │ dequantize_per_tensor_496 │ [1, 1000]        │ tensor[FixedPoint32<27>] │ n/a   │
╘════╧════════╧═══════════════════════════╧══════════════════╧══════════════════════════╧═══════╛

10. Demo

We first run inference, then show the statistics collected.

from sdk_cli.lib.inference import InferenceEngine, batch_inference

IMAGENET_DATA_DIR = Path("../../common/validation/imagenet-mini-quadric/val")
all_images_dict = {
    str(IMAGENET_DATA_DIR / "n03777568" / "ILSVRC2012_val_00049034.JPEG"): 661,
    str(IMAGENET_DATA_DIR / "n02877765" / "ILSVRC2012_val_00049979.JPEG"): 455,
    str(IMAGENET_DATA_DIR / "n02125311" / "ILSVRC2012_val_00015558.JPEG"): 286,
}
all_image_paths = list(all_images_dict.keys())
NUM_IMAGES = len(all_image_paths)

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(test_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 07:19 - WARNING - epu - chimera_job - ORT is not threadsafe -- forcing single threaded batch execution
100%|██████████| 3/3 [00:03<00:00,  1.07s/it]
Processing: 100%|██████████| 3/3 [03:44<00:00, 74.74s/it]
from sdk_cli.utils.datasets.ImageNet import OPTIMIZED_IMAGENET_1K_LABELS
from sdk_cli.visualizers.layouter import ClassifierLayouter

%matplotlib inline

for i, image_path in enumerate(all_image_paths):
    title = f"{all_images_dict[image_path]}: {OPTIMIZED_IMAGENET_1K_LABELS.class_map[all_images_dict[image_path]]}"
    classifier_layouter = ClassifierLayouter(image_path, title)

    for inference_engine, all_outputs in outputs_per_inference_engine.items():
        classifier_layouter.add_data(all_outputs[i][0], f"Swin Top 5 (%): {str(inference_engine)}")
    classifier_layouter.display()

cgc_job.plot_run_statistics();
2026-06-19 07:23 - INFO - epu - chimera_job - Combined plots generated and saved to: 
/quadric/sdk-cli/examples/models/swin/ccl_build/swin_processed_QC_U_1d7_16MB_4kB_128GBps_128GBps_8_OFF_x1_x1/run/20260619_071916_f21c35/data/swin_processed_QC_U_1d7_16MB_4kB_128GBps_128GBps_8_OFF_x1_x1.combined.png


Table of Contents
Introduction to the Chimera SDK
Chimera SDK Quick Start Guide
Chimera SDK Command Line Interface (CLI)
Tutorial: Using SDK as a Library
Tutorials & Model Demos
Model Demos
Model Demo: Llama-2 15M (Baby Llama-2)
Model Demo: QWEN3 8B End-to-End CGC and ISS Execution
Model Demo: QWEN3 Prefill All Decoders
Model Demo: DeepSeek-R1-Distill-Qwen-1.5B End-to-End CGC and ISS Execution
Model Demo: QWEN3 Single Decoder
Model Demo: Qwen2.5-0.5B INT8 Quantization Pipeline
Model Demo: ConvNeXt Detection
Model Demo: QWEN3 Prefill Decoder Validation
Model Demo: ConvNeXt Segmentation
Model Demo: Classifiers Zoo
Model Demo: Detectors Zoo - MMDetection
Model Demo: Segmentors Zoo - MMSegmentation
Model Demo: Pose Estimators Zoo - MMPose
Model Demo: Detectors3D Zoo - MMDetection3D
MODEL Demo: Optical Character Recognition (OCR) Zoo - MMOCR
Model Demo: YOLOv3 Object Detection
Model Demo: YOLOv4 Object Detection
Model Demo: YOLOv5 Detection
Model Demo: YOLOv5 Detection and Segmentation
Model Demo: YOLOR Detection
Model Demo: YOLOX End-to-End Detection
Model Demo: YOLOv7 Detection
Model Demo: YOLOv8 Detection
Model Demo: YOLOv8 Pose Estimation
Model Demo: YOLOP Detection and Segmentation
Model Demo: QAT Vision Transformer (ViT)
Model Demo: QAT Swin Transformer
Model Demo: Mediapipe Face Pipeline
Demo: DOOM Renderer on Chimera GPNPU
Model Demo: Mediapipe Hand Pipeline
Model Demo: Whisper Tiny (Encoder + Decoder)
Model Demo: L2CS Fine-Grained Gaze Estimation
Model Demo: ASVspoof2021 LA Anti-Spoofing (LFCC-LCNN-BiLSTM)
Model Demo: UNET Tumor Segmentation
Model Demo: DETR Encoder
Model Demo: FFNet Segmentation
Model Demo: Centernet Detection
Model Demo: RetinaNet End-to-End Detection
Model Demo: Blazepose Pose Estimation
Model Demo: Pose Resnet Human Pose Estimation
Model Demo: MaskRCNN Detection and Segmentation
Model Demo: Keypoint R-CNN
Model Demo: Faster R-CNN Detection
Model Demo: FCOS Detection
Model Demo: DDRNet Classificationls
Model Demo: PI0.5 End-to-End VLA Inference
Model Demo: BEVFormer End-to-End 3D Detection
Multicore Demo
Chimera LLVM C++ Compiler
Chimera SDK Licensing Policy Documentation
Glossary


© Copyright 2026 Quadric All Rights Reserved • Privacy Policy
This documentation is preliminary and confidential. It is subject to change. Quadric does not give any warranty express or implied that the contents will be complete or accurate or up to date. The company shall not be liable for any loss, actions, claims, proceedings, demands or costs or damages whatsoever or howsoever caused arising directly or indirectly in connection with or arising out of the use of this material.

Sign in to your account

Don't have an account? Create an Account
By signing in, you are agreeing to our Terms of Use and Privacy Policy.

Develop.

Simulate.

Profile.

Collaborate.

We use cookies to enhance your browsing experience, and analyze our traffic.
By clicking "Accept All", you consent to our use of cookies.