-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Add Nunchaku Lite single-file quantization #14100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7f4a3a0
1a66ac9
36b4fc4
db05e0b
5d4822a
c630a88
ab246af
57323cd
5fef94f
fb33430
8e14847
f5c0179
8ba15ff
661d6f7
1c58a6f
4c77a51
16a9cd0
7b186f0
452de40
b849b18
9284dd0
4806585
d687751
86cd7c8
fd58893
f6897af
3df700a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| <!--Copyright 2026 The HuggingFace Team. All rights reserved. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
| the License. You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
| an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
| specific language governing permissions and limitations under the License. | ||
|
|
||
| --> | ||
|
|
||
| # Nunchaku Lite | ||
|
|
||
| Nunchaku Lite is a quantization backend for loading prequantized checkpoints in Diffusers. Use | ||
| [`diffuse-compressor`](https://github.com/rootonchair/diffuse-compressor) to create compatible checkpoints by choosing | ||
| or adapting a target config for the model architecture, quantizing and exporting the transformer, and packaging the | ||
| result as a Diffusers pipeline repository. | ||
|
|
||
| Nunchaku Lite builds on the original [Nunchaku](https://github.com/nunchaku-ai/nunchaku) inference engine, | ||
| [DeepCompressor](https://github.com/nunchaku-ai/deepcompressor) quantization library, and | ||
| [SVDQuant paper](https://arxiv.org/abs/2411.05007). | ||
|
|
||
| ## Load a quantized pipeline | ||
|
|
||
| Load the packaged prequantized pipeline with [`~DiffusionPipeline.from_pretrained`]. Diffusers reads the quantization | ||
| config from `config.json`. | ||
|
|
||
| ```python | ||
| import torch | ||
| from diffusers import DiffusionPipeline | ||
|
|
||
| model_id = "rootonchair/ERNIE-Image-Turbo-nunchaku-lite-nvfp4" | ||
|
|
||
| pipe = DiffusionPipeline.from_pretrained( | ||
| model_id, torch_dtype=torch.bfloat16, | ||
| ).to("cuda") | ||
|
|
||
| prompt = "A modern red armchair in a quiet studio, soft window light, realistic product photography" | ||
| image = pipe( | ||
| prompt=prompt, | ||
| height=1024, | ||
| width=1024, | ||
| num_inference_steps=8, | ||
| guidance_scale=1.0, | ||
| use_pe=False, | ||
| ).images[0] | ||
| image.save("ernie-image-turbo-nunchaku-lite.png") | ||
| ``` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it compatible with offloading, too? |
||
|
|
||
| ## Using Optimized CUDA Kernels with Nunchaku Lite | ||
|
|
||
| Nunchaku Lite uses optimized CUDA kernels through the `kernels` package. The kernels are loaded automatically when you | ||
| load a Nunchaku Lite checkpoint. Install the runtime dependency before loading a Nunchaku Lite checkpoint. | ||
|
|
||
| ```bash | ||
| pip install -U kernels | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > The exported state dict must match the target Diffusers model architecture exactly. For example, a checkpoint | ||
| > quantized with fused QKV projections won't load into a model config that expects separate Q, K, and V projection | ||
| > modules. | ||
|
|
||
| ## Supported Quantization Types | ||
|
|
||
| Nunchaku Lite supports the following quantized linear layer formats. | ||
|
|
||
| > [!TIP] | ||
| > Use `nvfp4` on Blackwell GPUs. Running `int4` checkpoints on Blackwell can be slower than `nvfp4`. | ||
|
|
||
| The CUDA kernels currently support the following NVIDIA GPU architectures: | ||
|
|
||
| - `sm_75` (Turing, for example RTX 2080) | ||
| - `sm_80` (Ampere, for example A100) | ||
| - `sm_86` (Ampere, for example RTX 3090 and RTX A6000) | ||
| - `sm_89` (Ada, for example RTX 4090) | ||
| - `sm_120` (Blackwell, for example RTX 5090) | ||
|
|
||
| > [!NOTE] | ||
| > Hopper GPUs, such as `sm_90` H100 and H200, are not currently supported. | ||
|
|
||
| `nvfp4` checkpoints require a Blackwell or newer NVIDIA GPU. On Blackwell GPUs, use PyTorch >= 2.7 with CUDA >= 12.8. | ||
| `int4` checkpoints require a Turing or newer NVIDIA GPU. | ||
|
|
||
| | Method | Precision | Group size | Notes | | ||
| |---|---:|---:|---| | ||
| | `svdq_w4a4` | `nvfp4` | 16 | Uses NVFP4 runtime kernels with SVDQ low-rank correction. | | ||
| | `svdq_w4a4` | `int4` | 64 | Uses INT4 W4A4 kernels with SVDQ low-rank correction. | | ||
| | `awq_w4a16` | `int4` | 64 | Uses INT4 weight-only AWQ-style kernels. | | ||
|
|
||
| ## NunchakuLiteQuantizationConfig | ||
|
|
||
| The `config.json` file must include a compact [`NunchakuLiteQuantizationConfig`]. It defines the runtime | ||
| `compute_dtype` and the target modules for each Nunchaku Lite quantization method. | ||
|
|
||
| - `compute_dtype`: runtime dtype for floating-point buffers in quantized modules, typically `torch.bfloat16`. | ||
| - `svdq_w4a4`: SVDQ W4A4 target config with `precision`, `group_size`, `rank`, and `targets`. | ||
| - `awq_w4a16`: AWQ W4A16 target config with `precision`, `group_size`, and `targets`. | ||
|
|
||
| Each entry in `targets` must point to a linear layer. Diffusers replaces the linear layers listed under `svdq_w4a4` | ||
| with SVDQ W4A4 layers and the linear layers listed under `awq_w4a16` with AWQ W4A16 layers. The example below shows the | ||
| expected shape with shortened target lists. | ||
|
|
||
| > [!NOTE] | ||
| > A target module can only use one Nunchaku Lite quantization method. Do not list the same target under both | ||
| > `svdq_w4a4` and `awq_w4a16`. | ||
|
|
||
| ```json | ||
| { | ||
| "_class_name": "ErnieImageTransformer2DModel", | ||
| "quantization_config": { | ||
| "quant_method": "nunchaku_lite", | ||
| "compute_dtype": "bfloat16", | ||
| "svdq_w4a4": { | ||
| "precision": "nvfp4", | ||
| "group_size": 16, | ||
| "rank": 32, | ||
| "targets": ["layers.0.self_attention.to_q"] | ||
| }, | ||
| "awq_w4a16": { | ||
| "precision": "int4", | ||
| "group_size": 64, | ||
| "targets": ["final_linear"] | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we briefly summarize what would this config do? Would it apply a combination of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have updated the details |
||
|
|
||
| ## torch.compile | ||
|
|
||
| Nunchaku Lite kernels and quantized linear layers are compatible with [`torch.compile`](../optimization/fp16#torchcompile). | ||
| Compile the quantized transformer after loading the pipeline for faster inference. | ||
|
|
||
| ```python | ||
| pipe.transformer = torch.compile(pipe.transformer, mode="default", fullgraph=True) | ||
| ``` | ||
|
|
||
| An ERNIE-Image-Turbo benchmark on an RTX PRO 6000 reported that Nunchaku Lite NVFP4 with `torch.compile` reduced the full pipeline latency from 2.271s to 1.675s. Compared to the original BF16 pipeline, the compiled | ||
| Nunchaku Lite NVFP4 pipeline reached a 1.8x speedup. | ||
|
|
||
| ## Resources | ||
|
|
||
| - [diffuse-compressor](https://github.com/rootonchair/diffuse-compressor) | ||
| - [Nunchaku installation requirements](https://nunchaku.tech/docs/nunchaku/installation/installation.html) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from .nunchaku_quantizer import NunchakuLiteQuantizer |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING, Any | ||
|
|
||
| from ..base import DiffusersQuantizer | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from ...models.modeling_utils import ModelMixin | ||
|
|
||
|
|
||
| from ...utils import is_kernels_available, logging | ||
|
|
||
|
|
||
| logger = logging.get_logger(__name__) | ||
|
|
||
|
|
||
| class NunchakuLiteQuantizer(DiffusersQuantizer): | ||
| def __init__(self, quantization_config, **kwargs): | ||
| super().__init__(quantization_config, **kwargs) | ||
| self.compute_dtype = quantization_config.compute_dtype | ||
| self.pre_quantized = quantization_config.pre_quantized | ||
|
|
||
| def validate_environment(self, *args, **kwargs): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Hopper validation
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hopper validation added |
||
| if not is_kernels_available(): | ||
| raise ImportError( | ||
| "Loading Nunchaku checkpoints requires the Hugging Face `kernels` package. " | ||
| "Install it with `pip install kernels`." | ||
| ) | ||
| import torch | ||
|
|
||
| cuda_available = torch.cuda.is_available() | ||
| if not cuda_available: | ||
| raise ValueError("Loading Nunchaku checkpoints requires a CUDA-capable NVIDIA GPU.") | ||
|
|
||
| device_capability = torch.cuda.get_device_capability() | ||
|
|
||
| if device_capability[0] == 9: | ||
| raise ValueError("Loading Nunchaku checkpoints is not supported on Hopper NVIDIA GPUs.") | ||
|
|
||
| has_nvfp4_config = ( | ||
| self.quantization_config.svdq_w4a4 is not None | ||
| and self.quantization_config.svdq_w4a4["precision"] == "nvfp4" | ||
| ) | ||
| has_int4_config = any( | ||
| config is not None and config["precision"] == "int4" | ||
| for config in (self.quantization_config.svdq_w4a4, self.quantization_config.awq_w4a16) | ||
| ) | ||
| if has_nvfp4_config and device_capability < (10, 0): | ||
| raise ValueError("Loading Nunchaku NVFP4 checkpoints requires a Blackwell or newer NVIDIA GPU.") | ||
| if has_int4_config and device_capability < (7, 5): | ||
| raise ValueError("Loading Nunchaku INT4 checkpoints on CUDA requires a Turing or newer NVIDIA GPU.") | ||
|
|
||
| def update_torch_dtype(self, torch_dtype): | ||
| if torch_dtype is None: | ||
| torch_dtype = self.compute_dtype | ||
| else: | ||
| self.compute_dtype = torch_dtype | ||
| return torch_dtype | ||
|
Comment on lines
+54
to
+59
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes we should
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this is addressed?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep |
||
|
|
||
| def _process_model_before_weight_loading( | ||
| self, | ||
| model: "ModelMixin", | ||
| state_dict: dict[str, Any] | None = None, | ||
| **kwargs, | ||
| ): | ||
| from .utils import check_strict_state_dict_match, replace_with_nunchaku_linear | ||
|
|
||
| quantization_config = self.quantization_config.to_dict() | ||
| num_replaced = replace_with_nunchaku_linear(model, quantization_config, self.compute_dtype) | ||
|
|
||
| if state_dict is not None: | ||
| check_strict_state_dict_match(model, state_dict) | ||
| logger.info(f"Applied Nunchaku quantization config with {num_replaced} targets.") | ||
|
|
||
| def _process_model_after_weight_loading(self, model: "ModelMixin", **kwargs): | ||
| return model | ||
|
|
||
| @property | ||
| def is_serializable(self): | ||
| return False | ||
|
|
||
| @property | ||
|
rootonchair marked this conversation as resolved.
|
||
| def is_trainable(self) -> bool: | ||
| return False | ||
|
|
||
| @property | ||
| def is_compileable(self) -> bool: | ||
| return True | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should provide some citations to the original Nunchaku repo since Nunchaku Lite is based off of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not only the repo, I will reference their paper too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is resolved