-
-
Notifications
You must be signed in to change notification settings - Fork 22.3k
[ROCm][Quant] Requantize serialized MXFP8 linears to FP8 PTPC #48427
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
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 | ||
|---|---|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |||
| import vllm.envs as envs | ||||
| import vllm.model_executor.layers.fused_moe.modular_kernel as mk | ||||
| from vllm.config import get_current_vllm_config | ||||
| from vllm.config.quantization import QuantizationConfigArgs | ||||
| from vllm.logger import init_logger | ||||
| from vllm.model_executor.kernels.linear import ( | ||||
| MarlinNvFp4LinearKernel, | ||||
|
|
@@ -58,6 +59,12 @@ | |||
| QuantizeMethodBase, | ||||
| ) | ||||
| from vllm.model_executor.layers.quantization.kv_cache import BaseKVCacheMethod | ||||
| from vllm.model_executor.layers.quantization.online.base import ( | ||||
| OnlineQuantizationConfig, | ||||
| ) | ||||
| from vllm.model_executor.layers.quantization.online.fp8 import ( | ||||
| Fp8PtpcOnlineLinearMethod, | ||||
| ) | ||||
| from vllm.model_executor.layers.quantization.utils.fp8_utils import ( | ||||
| process_fp8_input_tensor_strategy_moe, | ||||
| process_fp8_weight_channel_strategy, | ||||
|
|
@@ -70,6 +77,7 @@ | |||
| MXFP8_BLOCK_SIZE, | ||||
| MXFP8_SCALE_DTYPE, | ||||
| MXFP8_VALUE_DTYPE, | ||||
| dequant_mxfp8_to_bf16, | ||||
| ) | ||||
| from vllm.model_executor.layers.quantization.utils.quant_utils import ( | ||||
| GroupShape, | ||||
|
|
@@ -93,6 +101,7 @@ | |||
| PerTensorScaleParameter, | ||||
| ) | ||||
| from vllm.model_executor.utils import replace_parameter, set_weight_attrs | ||||
| from vllm.platforms import current_platform | ||||
|
|
||||
| if TYPE_CHECKING: | ||||
| from vllm.model_executor.models.utils import WeightsMapper | ||||
|
|
@@ -1714,6 +1723,40 @@ def get_name(self) -> QuantizationMethods: | |||
| def get_supported_act_dtypes(self) -> list[torch.dtype]: | ||||
| return [torch.bfloat16] | ||||
|
|
||||
| def get_quant_method( | ||||
|
Contributor
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 am not sure about most of the logic here, seems it could belong elsewhere |
||||
| self, layer: torch.nn.Module, prefix: str | ||||
| ) -> "QuantizeMethodBase | None": | ||||
| if current_platform.is_rocm() and isinstance(layer, LinearBase): | ||||
|
Contributor
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. Why the check on |
||||
| model_config = get_current_vllm_config().model_config | ||||
| args = model_config.quantization_config | ||||
| if isinstance(args, QuantizationConfigArgs) and not self.is_layer_excluded( | ||||
| prefix | ||||
| ): | ||||
| target_method = OnlineQuantizationConfig(args).get_quant_method( | ||||
| layer, prefix | ||||
| ) | ||||
| if isinstance(target_method, Fp8PtpcOnlineLinearMethod): | ||||
|
Contributor
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. else? not supported error? |
||||
| linear_backend = ( | ||||
| get_current_vllm_config().kernel_config.linear_backend | ||||
| ) | ||||
| if linear_backend not in {"auto", "aiter"}: | ||||
| raise ValueError( | ||||
| "ModelOpt MXFP8 to FP8 PTPC requantization requires " | ||||
| "the AITER linear kernel; use --linear-backend=auto " | ||||
| "or --linear-backend=aiter, got " | ||||
| f"--linear-backend={linear_backend}." | ||||
| ) | ||||
|
Comment on lines
+1740
to
+1748
Contributor
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 don't think this should be done here.
|
||||
| source_method = ModelOptMxFp8LinearMethod(self, init_kernel=False) | ||||
| target_method.set_requantization_source(source_method) | ||||
| logger.info_once( | ||||
| "ModelOpt MXFP8 linear override: checkpoint MXFP8 + " | ||||
| "E8M0 -> BF16 -> FP8 PTPC; unspecified linears and " | ||||
| "MoE retain checkpoint quantization.", | ||||
| scope="global", | ||||
| ) | ||||
| return target_method | ||||
| return super().get_quant_method(layer, prefix) | ||||
|
|
||||
| @classmethod | ||||
| def get_min_capability(cls) -> int: | ||||
| # Marlin kernel supports MXFP8 on SM80+ | ||||
|
|
@@ -1779,7 +1822,9 @@ def _from_config( | |||
| class ModelOptMxFp8LinearMethod(LinearMethodBase): | ||||
| """Linear method for ModelOpt MXFP8 quantization.""" | ||||
|
|
||||
| def __init__(self, quant_config: ModelOptMxFp8Config) -> None: | ||||
| def __init__( | ||||
| self, quant_config: ModelOptMxFp8Config, *, init_kernel: bool = True | ||||
| ) -> None: | ||||
| self.quant_config = quant_config | ||||
|
|
||||
| if not self.quant_config.is_checkpoint_mxfp8_serialized: | ||||
|
|
@@ -1788,7 +1833,7 @@ def __init__(self, quant_config: ModelOptMxFp8Config) -> None: | |||
| "Dynamic quantization is not supported." | ||||
| ) | ||||
|
|
||||
| self.kernel = init_mxfp8_linear_kernel() | ||||
| self.kernel = init_mxfp8_linear_kernel() if init_kernel else None | ||||
|
|
||||
| def create_weights( | ||||
| self, | ||||
|
|
@@ -1853,6 +1898,12 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None: | |||
| if layer.weight.element_size() >= 2: | ||||
| return | ||||
|
|
||||
| self._validate_serialized_weight(layer) | ||||
| assert self.kernel is not None | ||||
| self.kernel.process_weights_after_loading(layer) | ||||
|
|
||||
| @staticmethod | ||||
| def _validate_serialized_weight(layer: torch.nn.Module) -> None: | ||||
| # Validate weight tensor | ||||
| if layer.weight.ndim != 2: | ||||
| raise ValueError( | ||||
|
|
@@ -1876,14 +1927,20 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None: | |||
| f" got {layer.weight_scale.dtype}" | ||||
| ) | ||||
|
|
||||
| self.kernel.process_weights_after_loading(layer) | ||||
| def dequantize_weight(self, layer: torch.nn.Module) -> torch.Tensor: | ||||
| """Reconstruct the serialized MXFP8 weight for online requantization.""" | ||||
| self._validate_serialized_weight(layer) | ||||
| return dequant_mxfp8_to_bf16( | ||||
| layer.weight.contiguous(), layer.weight_scale.contiguous() | ||||
| ) | ||||
|
|
||||
| def apply( | ||||
| self, | ||||
| layer: torch.nn.Module, | ||||
| x: torch.Tensor, | ||||
| bias: torch.Tensor | None = None, | ||||
| ) -> torch.Tensor: | ||||
| assert self.kernel is not None | ||||
| return self.kernel.apply_weights(layer, x, bias) | ||||
|
|
||||
|
|
||||
|
|
||||
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.
Maybe these tests should be in
test_online.py?Can you also add a test that ensures that the MXFP8 -> BF16 -> FP8 PTPC conversion does not double memory requirement during requantization (due to BF16 dequant)? Is it indeed the case?
Maybe similar to
vllm/tests/quantization/test_online.py
Line 188 in d6dbdb9