# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # 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. from typing import Any import torch from calib.plugin_calib import PercentileCalibrator from utils import filter_func from modelopt.torch.quantization.config import NVFP4_FP8_MHA_CONFIG # noqa: F401 FP8_DEFAULT_CONFIG = { "quant_cfg": { "*weight_quantizer": {"num_bits": (4, 3), "axis": None}, "*input_quantizer": {"num_bits": (4, 3), "axis": None}, "*output_quantizer": {"enable": False}, "*[qkv]_bmm_quantizer": {"num_bits": (4, 3), "axis": None}, "*softmax_quantizer": { "num_bits": (4, 3), "axis": None, }, "default": {"enable": False}, }, "algorithm": "max", } NVFP4_DEFAULT_CONFIG = { "quant_cfg": { "*weight_quantizer": { "num_bits": (2, 1), "block_sizes": {-1: 16, "type": "dynamic", "scale_bits": (4, 3)}, "axis": None, "enable": True, }, "*input_quantizer": { "num_bits": (2, 1), "block_sizes": {-1: 16, "type": "dynamic", "scale_bits": (4, 3)}, "axis": None, "enable": True, }, "*output_quantizer": {"enable": False}, "*[qkv]_bmm_quantizer": {"num_bits": (4, 3), "axis": None}, "*softmax_quantizer": { "num_bits": (4, 3), "axis": None, }, "default": {"enable": False}, }, "algorithm": "max", } NVFP4_FP8_MHA_FLUX_CONFIG = { "quant_cfg": { "*transformer_blocks*weight_quantizer": { "num_bits": (2, 1), "block_sizes": {-1: 16, "type": "dynamic", "scale_bits": (4, 3)}, "axis": None, "enable": True, }, "*transformer_blocks*input_quantizer": { "num_bits": (2, 1), "block_sizes": {-1: 16, "type": "dynamic", "scale_bits": (4, 3)}, "axis": None, "enable": True, }, "*output_quantizer": {"enable": False}, "*[qkv]_bmm_quantizer": { "num_bits": (4, 3), "axis": None, }, "*softmax_quantizer": { "num_bits": (4, 3), "axis": None, }, "*bmm2_output_quantizer": { "num_bits": (4, 3), "axis": None, }, "default": {"enable": False}, }, "algorithm": {"method": "svdquant", "lowrank": 32}, } def get_int8_config( model, quant_level=3, percentile=1.0, num_inference_steps=20, collect_method="global_min", ): quant_config: dict[str, dict[str, Any]] = { "quant_cfg": { "*output_quantizer": {"enable": False}, "default": {"enable": False}, } } for name, module in model.named_modules(): w_name = f"{name}*weight_quantizer" i_name = f"{name}*input_quantizer" if w_name in quant_config["quant_cfg"] or i_name in quant_config["quant_cfg"]: continue if filter_func(name): continue if isinstance(module, torch.nn.Linear): if ( (quant_level >= 2 and "ff.net" in name) or (quant_level >= 2.5 and ("to_q" in name or "to_k" in name or "to_v" in name)) or quant_level == 3 ): quant_config["quant_cfg"][w_name] = { "num_bits": 8, "axis": 0, } quant_config["quant_cfg"][i_name] = { "num_bits": 8, "axis": -1, } elif isinstance(module, torch.nn.Conv2d): quant_config["quant_cfg"][w_name] = { "num_bits": 8, "axis": 0, } quant_config["quant_cfg"][i_name] = { "num_bits": 8, "axis": None, "calibrator": ( PercentileCalibrator, (), { "num_bits": 8, "axis": None, "percentile": percentile, "total_step": num_inference_steps, "collect_method": collect_method, }, ), } return quant_config def get_fp4_config(model, fp4_linear_only=False): """fp4 for linear, optionally fp8 for conv""" quant_config = { "quant_cfg": {}, "algorithm": "max", } for name, module in model.named_modules(): w_name = f"{name}*weight_quantizer" i_name = f"{name}*input_quantizer" if w_name in quant_config["quant_cfg"] or i_name in quant_config["quant_cfg"]: continue if isinstance(module, torch.nn.Linear): quant_config["quant_cfg"][w_name] = { # type: ignore[index] "num_bits": (2, 1), "block_sizes": {-1: 16, "type": "dynamic", "scale_bits": (4, 3)}, "axis": None, } quant_config["quant_cfg"][i_name] = { # type: ignore[index] "num_bits": (2, 1), "block_sizes": {-1: 16, "type": "dynamic", "scale_bits": (4, 3)}, "axis": None, } elif isinstance(module, torch.nn.Conv2d): if fp4_linear_only: quant_config["quant_cfg"][w_name] = {"enable": False} # type: ignore[index] quant_config["quant_cfg"][i_name] = {"enable": False} # type: ignore[index] else: # fp8 for conv quant_config["quant_cfg"][w_name] = {"num_bits": (4, 3), "axis": None} # type: ignore[index] quant_config["quant_cfg"][i_name] = {"num_bits": (4, 3), "axis": None} # type: ignore[index] return quant_config def set_quant_config_attr(quant_config, trt_high_precision_dtype, quant_algo, **kwargs): algo_cfg = {"method": quant_algo} if quant_algo == "smoothquant" and "alpha" in kwargs: algo_cfg["alpha"] = kwargs["alpha"] elif quant_algo == "svdquant" and "lowrank" in kwargs: algo_cfg["lowrank"] = kwargs["lowrank"] quant_config["algorithm"] = algo_cfg for p in quant_config["quant_cfg"].values(): if "num_bits" in p and "trt_high_precision_dtype" not in p: p["trt_high_precision_dtype"] = trt_high_precision_dtype