### What does this PR do? Make the QAT/QAD guide the central place for concepts, background, and framework selection. Have the Hugging Face and Megatron Bridge tutorials link back to it instead of repeating explanations of QAT and QAD, keeping the tutorials focused on setup and execution. In main QAT/QAD guide make links to all relevant blogposts. Note: MBridge example doc is out of scope for this MR. ### Testing Doc changes only, manual check. ### Before your PR is "*Ready for review*" - Is this change backward compatible?: ✅ - Did you write any new necessary tests?: N/A docs changes only ### Additional Information <!-- E.g. related issue. --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Expanded the QAT/QAD guide with workflows, use cases, and a comparison, including QAD’s use of a frozen BF16 teacher and logit-level loss to recover accuracy after quantization. * Updated README and quick-start navigation to link to the combined QAT/QAD guide; the previous standalone QAT guide now redirects readers there. * Reorganized the LLM QAT tutorial: recipe guidance is now part of the end-to-end example, while trainer examples and Python quantize-and-fine-tune guidance are in Advanced Topics. The tutorial also notes Triton accelerated kernels. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Daniel Korzekwa <dkorzekwa@nvidia.com>
Quantization Aware Training (QAT) and Distillation (QAD)
This tutorial shows how to run QAT and QAD with Hugging Face Transformers: set up the environment, quantize a model, train it, evaluate the checkpoint, and export it for deployment.
For background on QAT and QAD and help choosing between Hugging Face, Megatron Bridge, and Megatron-LM, start with the QAT/QAD guide.
| Section | Description | Link |
|---|---|---|
| Quick Start | Prerequisites and setup | [Link] |
| End-to-End Example | Run QAT/QAD in 3 steps: quantize, train, export | [Link] |
| Arguments | Full CLI/YAML argument reference | [Link] |
| Support Matrix | Supported models, quantization formats, and backends | [Link] |
| QLoRA | Model training with reduced GPU memory | [Link] |
| Advanced Topics | Trainer APIs, FSDP2 config, YAML options | [Link] |
| Results | Accuracy benchmarks | [Link] |
| Resources | Extra links and references | [Link] |
Quick Start
Prerequisites
Please refer to hf_ptq/README.md for container recommendations and base ModelOpt installation guidance. For this QAT/QAD example, install the Hugging Face dependencies and the example-specific requirements:
pip install -U nvidia-modelopt[hf]
pip install -r examples/llm_qat/requirements.txt
The Qwen3-8B example below requires a minimum of 2 x 80GB GPUs.
ModelOpt provides accelerated quantization kernels using Triton for NVFP4 QAT. See the installation guide.
Run End-to-End QAT/QAD Example
All arguments can be set via YAML, CLI, or both (CLI overrides YAML). See
ARGUMENTS.md, --help, and Configuration.
Quantization Recipes
Recipes are declarative YAML files that specify the quantization configuration. Built-in recipes are available in modelopt_recipes/:
# From the Model-Optimizer repository root, list available built-in recipes
ls modelopt_recipes/general/ptq/
See custom calibration for creating your own recipe.
QAT
Quantize, fine-tune on labeled data, and export:
# 1. Quantize
python quantize.py \
--model_name_or_path Qwen/Qwen3-8B \
--dataset_config configs/dataset/blend.yaml \
--recipe general/ptq/nvfp4_default-kv_fp8 \
--output_dir qwen3-8b-quantized
# 2. Train
accelerate launch --config-file configs/accelerate/fsdp2.yaml train.py \
--config configs/train/qat_nvfp4.yaml \
--model_name_or_path qwen3-8b-quantized \
--output_dir qwen3-8b-qat-nvfp4
# 3. Export
python export.py --pyt_ckpt_path qwen3-8b-qat-nvfp4 --export_path qwen3-8b-qat-deploy
QAD
Quantize, recover accuracy using the original model as teacher, and export:
# 1. Quantize
python quantize.py \
--model_name_or_path Qwen/Qwen3-8B \
--dataset_config configs/dataset/blend.yaml \
--recipe general/ptq/nvfp4_default-kv_fp8 \
--output_dir qwen3-8b-quantized
# 2. Train with distillation
accelerate launch --config-file configs/accelerate/fsdp2.yaml train.py \
--config configs/train/qad_nvfp4.yaml \
--model_name_or_path qwen3-8b-quantized \
--teacher_model Qwen/Qwen3-8B \
--output_dir qwen3-8b-qad-nvfp4
# 3. Export
python export.py --pyt_ckpt_path qwen3-8b-qad-nvfp4 --export_path qwen3-8b-qad-deploy
Exported checkpoints can be deployed on TensorRT-LLM, vLLM, or SGLang. See hf_ptq/README.md for deployment instructions. For quick accuracy evaluation without exporting, see Native Fake-Quantized Evaluation.
Note
For a minimal end-to-end demo (quantize + train + save in one script), see simple_qat_train.py. It runs on a single GPU only and is intended as a quick introduction to the QAT flow (without transformer trainer)—not for distributed training.
python simple_qat_train.py --model-path meta-llama/Llama-3.2-3B --recipe general/ptq/nvfp4_default-kv_fp8For multi-GPU training (FSDP2, DDP, DeepSpeed), use train.py with
accelerate launchas shown in the commands above.
Tip
For more performant QAD, please refer to examples/megatron_bridge/README.md for example scripts for PTQ / QAD with Megatron-Bridge which is generally more performant than the Hugging Face scripts.
Support Matrix
Supported Models
| Model | Chat Template | Support |
|---|---|---|
| Qwen2, 2.5, 3, 3.5 dense models; Nemotron ChatML models | ChatML | Yes (chat + assistant-only labels + pretrain) |
Models with {% generation %} chat templates |
Model-specific | Yes (chat + assistant-only labels + pretrain) |
| Other models with HuggingFace chat templates, including Llama 2, 3, 3.1 | Model-specific | Yes (chat full-label + pretrain) |
Note:
apply_chat_templatecontrols chat formatting.train_only_assistant_tokenscontrols label masking:autouses assistant-only labels when native{% generation %}masks or the tested Qwen/Nemotron ChatML heuristic is available, then falls back to all non-padding chat-template tokens; settrain_only_assistant_tokens: trueto require native or ChatML assistant-only labels, orfalseto always train on all chat-template tokens.
Supported Quantization Formats
Built-in recipes support full-model, partial-layer, and mixed-precision quantization. Common entry points:
| Format | Precision | Example Recipe | Use Case |
|---|---|---|---|
| NVFP4 | W4A4 + FP8 KV | general/ptq/nvfp4_default-kv_fp8 |
FP4 compute and compression on Blackwell GPUs |
| FP8 | W8A8 + FP8 KV | general/ptq/fp8_default-kv_fp8 |
Near-BF16 accuracy on Hopper or later GPUs |
| INT4 weight-only | W4A16 | general/ptq/int4_blockwise_weight_only |
Deployable on all Ampere or later GPUs |
| Partial / mixed | Pattern-specific | general/ptq/nvfp4_mlp_only-kv_fp8 |
Quantize selected layers or combine precisions |
Recipes can target different layers or GEMMs with different precisions, such as NVFP4 for MLP/MoE GEMMs and FP8 for attention GEMMs or KV cache. See
modelopt_recipes/general/ptq/andmodelopt_recipes/configs/ptq/for built-in options and reusable recipe units.
Supported Backends
| Backend | Config File | Notes |
|---|---|---|
| FSDP2 | configs/accelerate/fsdp2.yaml |
Recommended |
| DDP | configs/accelerate/ddp.yaml |
Add --gradient_checkpointing True |
| DeepSpeed | configs/accelerate/deepspeed.yaml |
Add --gradient_checkpointing True |
Replace --config-file configs/accelerate/fsdp2.yaml with the desired backend config in any of the commands above.
QLoRA (Real Quantization)
QLoRA reduces training memory by quantizing LoRA backbone weights with real quantization via mtq.compress().
# 1. Quantize with compression
python quantize.py \
--model_name_or_path Qwen/Qwen3-8B \
--dataset_config configs/dataset/blend.yaml \
--recipe general/ptq/nvfp4_default-kv_fp8 \
--compress True \
--output_dir qwen3-8b-quantized
# 2. Train with QLoRA
accelerate launch --config-file configs/accelerate/ddp.yaml train.py \
--config configs/train/qlora_nvfp4.yaml \
--model_name_or_path qwen3-8b-quantized \
--output_dir qwen3-8b-fp4-qlora
# 3. Export
python export.py \
--pyt_ckpt_path qwen3-8b-fp4-qlora \
--export_path qwen3-8b-fp4-qlora-hf
# 4. Serve with vLLM
vllm serve qwen3-8b-fp4-qlora-hf/base_model --enable-lora \
--lora-modules adapter=qwen3-8b-fp4-qlora-hf --port 8000 \
--tokenizer qwen3-8b-fp4-qlora-hf
QLoRA export is not currently supported with FSDP2.
Advanced Topics
Quantize and Fine-Tune with Python
import modelopt.torch.quantization as mtq
from modelopt.recipe import load_recipe
# 1. Load a quantization recipe
recipe = load_recipe("general/ptq/nvfp4_default-kv_fp8")
# 2. Quantize the model in-place
model = mtq.quantize(model, recipe.quantize, forward_loop)
# 3. Fine-tune the quantized model
trainer.train()
trainer.save_model()
Using QATTrainer and QADTrainer
QATTrainer is a drop-in replacement for HuggingFace's Trainer that handles quantization-aware training seamlessly with various distributed backends (FSDP2, DeepSpeed, DDP):
from modelopt.torch.quantization.plugins.transformers_trainer import QATTrainer
trainer = QATTrainer(
model=model, # pre-quantized model
processing_class=tokenizer,
args=training_args,
**data_module,
)
trainer.train()
trainer.save_model()
QADTrainer extends QATTrainer with distillation. Pass the teacher model and a DistillArguments instance:
from modelopt.torch.distill.plugins.huggingface import DistillArguments
from modelopt.torch.quantization.plugins.transformers_trainer import QADTrainer
distill_args = DistillArguments(
distill=True,
teacher_model="Qwen/Qwen3-8B",
criterion="logits_loss",
)
trainer = QADTrainer(
model=model, # pre-quantized model
processing_class=tokenizer,
args=training_args,
distill_args=distill_args,
**data_module,
)
trainer.train()
trainer.save_model()
FSDP2 and Model-Specific Layer Wrapping
The default fsdp2.yaml uses TRANSFORMER_BASED_WRAP with fsdp_transformer_layer_cls_to_wrap: Qwen3DecoderLayer. This setting is model-specific — if you are training a different model architecture, you must update it to match your model's decoder layer class.
You can either:
-
Override via CLI (recommended for one-off runs):
accelerate launch --config-file configs/accelerate/fsdp2.yaml \ --fsdp_transformer_layer_cls_to_wrap LlamaDecoderLayer \ train.py --config configs/train/qat_nvfp4.yaml ... -
Create a custom config (recommended for repeated use):
cp configs/accelerate/fsdp2.yaml configs/accelerate/fsdp2_llama.yaml # Edit fsdp2_llama.yaml: change Qwen3DecoderLayer -> LlamaDecoderLayer
Common layer class names:
| Model Family | fsdp_transformer_layer_cls_to_wrap |
|---|---|
| Qwen2, Qwen2.5, Qwen3 | Qwen3DecoderLayer (or Qwen2DecoderLayer) |
| Llama 2, 3, 3.1 | LlamaDecoderLayer |
Configuration
There are two types of configs:
- Dataset configs (
configs/dataset/): Define the dataset blend — sources,blend_size(total samples), andsplits(train/eval/test ratios). These are self-contained and determine what gets cached. - Training configs (
configs/train/): Define training hyperparameters plus runtime caps (train_samples,eval_samples) that subset the pre-built dataset without retriggering caching.
quantize.py only needs --dataset_config and --recipe. train.py uses a full training config via --config. All arguments can be specified via YAML, CLI flags, or both (CLI overrides YAML). See ARGUMENTS.md for the full reference, regenerated with python_pwd examples/llm_qat/arguments.py --generate_docs examples/llm_qat/ARGUMENTS.md.
# YAML + CLI override
accelerate launch --config-file configs/accelerate/fsdp2.yaml train.py \
--config configs/train/qat_nvfp4.yaml --learning_rate 5e-5
See Dataset Configuration for custom dataset blends and adding new datasets.
Pre-Building the Dataset
You can pre-tokenize and cache the dataset before training using dataset_utils.py. This is useful for large blends or multi-node setups where you want to build the cache once and reuse it across experiments.
python dataset_utils.py \
--dataset_config configs/dataset/blend.yaml \
--model_name_or_path Qwen/Qwen3-8B
The cached dataset is stored under .dataset_cache/tokenized/ by default (configurable via --dataset_cache_dir). The cache key depends on the dataset config (blend_size, splits, sources) and tokenizer — changing train_samples or eval_samples in the training config does not invalidate the cache.
Results
[Coming Soon]
Native Fake-Quantized Evaluation
ModelOpt quantized models can be saved and restored without exporting to a deployment platform. This is useful for fast evaluation with fake quantization using standard LLM benchmarks (MMLU, WikiText, etc.). See HuggingFace checkpointing for details.
cd ../llm_eval
python lm_eval_hf.py --model hf \
--tasks mmlu,wikitext \
--model_args pretrained=../llm_qat/qwen3-8b-qat-nvfp4 \
--batch_size 4
See llm_eval/README.md for supported tasks.
Pre-Quantized Checkpoints
- Ready-to-deploy checkpoints: Hugging Face - NVIDIA Model Optimizer Collection
- Deployable on TensorRT-LLM, vLLM and SGLang