@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / c31246800c
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 14, 05:30 UTC

Support RL online quantization with torchao (#23014)

Signed-off-by: Jerry Zhang <jerryzh168@gmail.com>

Jerry Zhang committed Oct 1, 2025 at 16:39 UTC c31246800c98272ab28b7d454d6b72f38e396972
6 files changed +465 -16
tests/quantization/test_torchao.py
+121 -5
@@ -20,7 +20,6 @@ def test_pre_quantized_model(vllm_runner):
20 output = llm.generate_greedy(["The capital of France is"],
21 max_tokens=32)
22 assert output
23 - print(output)
23
24
25 @pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
@@ -42,7 +41,6 @@ def test_opt_125m_int8wo_model_loading_with_params(vllm_runner,
41 max_tokens=32)
42
43 assert output
45 - print(output)
44
45
46 @pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
@@ -57,7 +55,6 @@ def test_opt_125m_int4wo_model_per_module_quant(vllm_runner):
55 max_tokens=32)
56
57 assert output
60 - print(output)
58
59
60 @pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
@@ -72,7 +69,6 @@ def test_qwenvl_int8wo_model_loading_with_params(vllm_runner):
69 max_tokens=32)
70
71 assert output
75 - print(output)
72
73
74 @pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
@@ -92,7 +88,127 @@ def test_opt_125m_awq_int4wo_model_loading_with_params(vllm_runner):
88 max_tokens=32)
89
90 assert output
95 - print(output)
91 +
92 +
93 +@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
94 +def test_on_the_fly_quant_config_dict_json(vllm_runner):
95 + """Testing on the fly quantization, load_weights integration point,
96 + with config dict serialized to json string
97 + """
98 + torch._dynamo.reset()
99 + model_name = "facebook/opt-125m"
100 +
101 + import json
102 +
103 + from torchao.core.config import config_to_dict
104 + from torchao.quantization import (
105 + Float8DynamicActivationFloat8WeightConfig, PerRow)
106 +
107 + torchao_quant_config = Float8DynamicActivationFloat8WeightConfig(
108 + granularity=PerRow())
109 + hf_overrides = {
110 + "quantization_config_dict_json":
111 + json.dumps(config_to_dict(torchao_quant_config))
112 + }
113 + with vllm_runner(model_name=model_name,
114 + dtype="bfloat16",
115 + pt_load_map_location="cuda:0",
116 + quantization="torchao",
117 + hf_overrides=hf_overrides) as llm:
118 + output = llm.generate_greedy(["The capital of France is"],
119 + max_tokens=32)
120 +
121 + assert output
122 +
123 +
124 +@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
125 +def test_on_the_fly_quant_config_file(vllm_runner):
126 + """Testing on the fly quantization, load_weights integration point,
127 + with config file
128 + """
129 + torch._dynamo.reset()
130 + model_name = "facebook/opt-125m"
131 + import json
132 + from tempfile import NamedTemporaryFile
133 +
134 + from torchao.core.config import config_to_dict
135 + from torchao.quantization import (
136 + Float8DynamicActivationFloat8WeightConfig, PerRow)
137 +
138 + config = Float8DynamicActivationFloat8WeightConfig(granularity=PerRow())
139 +
140 + with NamedTemporaryFile(mode="w", delete=False) as f:
141 + f.write(json.dumps(config_to_dict(config)))
142 + # close the file to save it
143 + f.close()
144 + config_file_name = str(f.name)
145 +
146 + hf_overrides = {"quantization_config_file": config_file_name}
147 + with vllm_runner(model_name=model_name,
148 + dtype="bfloat16",
149 + pt_load_map_location="cuda:0",
150 + quantization="torchao",
151 + hf_overrides=hf_overrides) as llm:
152 + output = llm.generate_greedy(["The capital of France is"],
153 + max_tokens=32)
154 +
155 + assert output
156 +
157 +
158 +@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
159 +def test_reload_weights():
160 + import json
161 +
162 + from torchao.core.config import config_to_dict
163 + from torchao.quantization import (
164 + Float8DynamicActivationFloat8WeightConfig, PerRow)
165 +
166 + from vllm import LLM, SamplingParams
167 +
168 + torchao_quant_config = Float8DynamicActivationFloat8WeightConfig(
169 + granularity=PerRow())
170 +
171 + hf_overrides = {
172 + "quantization_config_dict_json":
173 + json.dumps(config_to_dict(torchao_quant_config))
174 + }
175 +
176 + llm = LLM(
177 + model="Qwen/Qwen3-0.6B",
178 + dtype="bfloat16",
179 + load_format="dummy",
180 + enforce_eager=True,
181 + quantization="torchao",
182 + hf_overrides=hf_overrides,
183 + )
184 + # Update load format from `dummy` to `auto`
185 + llm.collective_rpc("update_config",
186 + args=({
187 + "load_config": {
188 + "load_format": "auto"
189 + }
190 + }, ))
191 + # Now reload real weights inplace
192 + llm.collective_rpc("reload_weights")
193 + prompts = [
194 + "Hello, my name is",
195 + "The president of the United States is",
196 + "The capital of France is",
197 + "The future of AI is",
198 + ]
199 + # Create a sampling params object.
200 + sampling_params = SamplingParams(temperature=0, top_p=0.95)
201 + outputs = llm.generate(prompts, sampling_params)
202 + # make sure it runs
203 + for output in outputs:
204 + generated_text = output.outputs[0].text
205 + assert generated_text
206 + # can also uncomment locally to make sure the generated
207 + # output makes sense
208 + # prompt = output.prompt
209 + # print(f"Prompt: {prompt!r}")
210 + # print(f"Output: {generated_text!r}")
211 + # print("-" * 60)
212
213
214 if __name__ == "__main__":
vllm/model_executor/layers/quantization/torchao.py
+64 -8
@@ -1,5 +1,6 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +import json
4 from typing import Any, Optional
5
6 import torch
@@ -40,7 +41,8 @@ class TorchAOConfig(QuantizationConfig):
41
42 def __init__(self,
43 torchao_config,
43 - skip_modules: Optional[list[str]] = None) -> None:
44 + skip_modules: Optional[list[str]] = None,
45 + is_checkpoint_torchao_serialized: bool = False) -> None:
46 """
47 # TorchAO quantization relies on tensor subclasses. In order,
48 # to enable proper caching this needs standalone compile
@@ -58,9 +60,11 @@ class TorchAOConfig(QuantizationConfig):
60 super().__init__()
61 self.torchao_config = torchao_config
62 self.skip_modules = skip_modules or []
63 + self.is_checkpoint_torchao_serialized = is_checkpoint_torchao_serialized
64
65 def __repr__(self) -> str:
63 - return f"TorchAOConfig({self.torchao_config})"
66 + return f"TorchAOConfig({self.torchao_config=}, {self.skip_modules=}, " \
67 + f"{self.is_checkpoint_torchao_serialized=})"
68
69 def get_name(self) -> QuantizationMethods:
70 return "torchao"
@@ -74,7 +78,10 @@ class TorchAOConfig(QuantizationConfig):
78
79 @staticmethod
80 def get_config_filenames() -> list[str]:
77 - return ["config.json"]
81 + """torchao doesn't require additional config files, we use
82 + `config.json` from huggingface: `model_config.hf_config`
83 + """
84 + return []
85
86 @classmethod
87 def from_config(cls, config: dict[str, Any]) -> "TorchAOConfig":
@@ -87,6 +94,10 @@ class TorchAOConfig(QuantizationConfig):
94 "`pip install torchao>=0.10.0` to use torchao quantization."
95 ) from err
96
97 + quant_method = cls.get_from_keys_or(config, ["quant_method"], None)
98 + is_checkpoint_torchao_serialized = (quant_method is not None
99 + and "torchao" in quant_method)
100 +
101 hf_config = cls.get_from_keys_or(config, ["quant_type"], None)
102 assert hf_config is not None, "quant_type must be specified"
103 assert len(hf_config) == 1 and "default" in hf_config, (
@@ -110,7 +121,38 @@ class TorchAOConfig(QuantizationConfig):
121 if layer_cfg is None:
122 skip_modules.append(layer)
123
113 - return cls(ao_config, skip_modules)
124 + return cls(ao_config, skip_modules, is_checkpoint_torchao_serialized)
125 +
126 + @classmethod
127 + def from_config_file(cls, config_file: str) -> "TorchAOConfig":
128 + """Initialize class from a config file. Example:
129 + ```
130 + config = (
131 + Float8DynamicActivationFloat8WeightConfig(granularity=PerRow())
132 + )
133 + fn = "torchao_config.json"
134 +
135 + with open(fn, "w") as f:
136 + f.write(json.dumps(config_to_dict(config)))
137 + ```
138 + """
139 + with open(config_file) as f:
140 + f.seek(0)
141 + f_read = f.read()
142 + config_dict = json.loads(f_read)
143 +
144 + hf_config = {"quant_type": {"default": config_dict}}
145 + return cls.from_config(hf_config)
146 +
147 + @classmethod
148 + def from_config_dict_json(cls, config_dict_json: str) -> "TorchAOConfig":
149 + """Iniitalize class from a config_dict json string, got from
150 + torchao_config_object = some AOBaseConfig object
151 + json.dumps(config_to_dict(torchao_config_object))
152 + """
153 + config_dict = json.loads(config_dict_json)
154 + hf_config = {"quant_type": {"default": config_dict}}
155 + return cls.from_config(hf_config)
156
157 def get_quant_method(self, layer: torch.nn.Module,
158 prefix: str) -> Optional["QuantizeMethodBase"]:
@@ -128,7 +170,9 @@ class TorchAOConfig(QuantizationConfig):
170 c = module_fqn_to_config.get(
171 module_fqn) or module_fqn_to_config.get("_default", None)
172 if c is not None:
131 - current_torchao_config = TorchAOConfig(c, self.skip_modules)
173 + current_torchao_config = TorchAOConfig(
174 + c, self.skip_modules,
175 + self.is_checkpoint_torchao_serialized)
176 return TorchAOLinearMethod(current_torchao_config)
177 else:
178 return UnquantizedLinearMethod()
@@ -172,7 +216,7 @@ class TorchAOLinearMethod(LinearMethodBase):
216 """Linear method for torchao.
217
218 Args:
175 - quant_config: The torchao quantization config, a string that encodes
219 + quant_config: The torchao quantization config, a string that encodes
220 the type of quantization and all relevant arguments.
221 """
222
@@ -197,8 +241,9 @@ class TorchAOLinearMethod(LinearMethodBase):
241 ),
242 requires_grad=False,
243 )
200 - weight = torchao_quantize_param_data(weight,
201 - self.quant_config.torchao_config)
244 + if self.quant_config.is_checkpoint_torchao_serialized:
245 + weight = torchao_quantize_param_data(
246 + weight, self.quant_config.torchao_config)
247
248 set_weight_attrs(weight, {"input_dim": 1, "output_dim": 0})
249
@@ -212,3 +257,14 @@ class TorchAOLinearMethod(LinearMethodBase):
257 bias: Optional[torch.Tensor] = None,
258 ) -> torch.Tensor:
259 return F.linear(x, layer.weight, bias)
260 +
261 + def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
262 + if self.quant_config.is_checkpoint_torchao_serialized:
263 + return
264 +
265 + # quantize the weight on the fly if the checkpoint is not already
266 + # quantized by torchao
267 + weight = torchao_quantize_param_data(layer.weight,
268 + self.quant_config.torchao_config)
269 + set_weight_attrs(weight, {"input_dim": 1, "output_dim": 0})
270 + layer.register_parameter("weight", weight)
vllm/model_executor/model_loader/default_loader.py
+29 -2
@@ -261,8 +261,35 @@ class DefaultModelLoader(BaseModelLoader):
261 def load_weights(self, model: nn.Module,
262 model_config: ModelConfig) -> None:
263 weights_to_load = {name for name, _ in model.named_parameters()}
264 - loaded_weights = model.load_weights(
265 - self.get_all_weights(model_config, model))
264 +
265 + # if we don't have `model.weight_metadata_and_attr_saved` defined and
266 + # set to True, it means that this is either offline quantization case
267 + # or the first run of online quantization
268 + # see online_quantization.py for detailed notes
269 + offline_quantization_or_first_run_of_online_quantization = not getattr(
270 + model, "weight_metadata_and_attr_saved", False)
271 +
272 + if model_config.quantization is None:
273 + # model is not quantized
274 + loaded_weights = model.load_weights(
275 + self.get_all_weights(model_config, model))
276 + elif offline_quantization_or_first_run_of_online_quantization:
277 + # case 1: offline quantized checkpoint
278 + # case 2: Step I1 first run of weight loading with
279 + # online quantization
280 + # see online_quantization.py for detailed notes
281 + loaded_weights = model.load_weights(
282 + self.get_all_weights(model_config, model))
283 + else:
284 + # to avoid circular dependency
285 + from vllm.model_executor.model_loader.online_quantization import (
286 + load_weights_and_online_quantize)
287 +
288 + # subsequent runs of weight loading with online
289 + # quantization
290 + loaded_weights = load_weights_and_online_quantize(
291 + self, model, model_config)
292 +
293 self.counter_after_loading_weights = time.perf_counter()
294 logger.info(
295 "Loading weights took %.2f seconds",
vllm/model_executor/model_loader/online_quantization.py new
+217
@@ -0,0 +1,217 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +
4 +import types
5 +
6 +import torch
7 +from torch import nn
8 +
9 +from vllm.config import ModelConfig
10 +from vllm.logger import init_logger
11 +from vllm.model_executor.model_loader.default_loader import DefaultModelLoader
12 +from vllm.model_executor.model_loader.utils import (
13 + process_weights_after_loading)
14 +
15 +logger = init_logger(__name__)
16 +
17 +# Notes for Online Quantization
18 +# In terms of state of checkpoints, quantization config and their
19 +# correspondance to online quantization:
20 +# | Use Case | Checkpoints | model_config.quantization |
21 +# | no quant | high precision | None |
22 +# | offline quant | quantized | fp8, torchao etc. |
23 +# | online quant | high precision | torchao etc. |
24 +#
25 +# The process for loading non-quantized checkpoint
26 +# 1. load non-quantized weights (load_weights)
27 +# 2. do any additional post processing (process_weights_after_loading)
28 +#
29 +# The process for loading offline quantized checkpoint
30 +# 1. load offline-quantized weights (load_weights)
31 +# 2. do any additional post processing (process_weights_after_loading)
32 +
33 +# The process for unquantized model reloading
34 +# (repeated run in RL training loop)
35 +# first run
36 +# UI1. load_weights: load bfloat16 weights
37 +# UI2. process_weights_after_loading: any additional post processing
38 +# subsequent run
39 +# UC1: load_weights: load bfloat16 weights
40 +# (shouldn't be any issues since we didn't change any attributes
41 +# of the weights)
42 +# UC2: process_weights_after_loading: any additional post processing
43 +
44 +# The process for weight reloading with online quantization
45 +# (repeated run in RL training loop)
46 +# first run
47 +# I1. load_weights: load bfloat16 weights
48 +# I2. process_weights_after_loading:
49 +# record weight metadata and attributes for R1 and R2
50 +# quantize weights to fp8
51 +# subsequent run
52 +# (beginning model weight is in fp8)
53 +# load_weights:
54 +# R1. restore bfloat16 model weight metadata
55 +# R2. restore the model weight attributes
56 +# R3. reload bfloat16 weights
57 +# R4. quantize weights (by calling process_weights_after_loading),
58 +# also set `process_weights_after_loading_already_called` to
59 +# True to stop it from running again
60 +# process_weights_after_loading (if called):
61 +# this will be skipped since it's already ran in
62 +# load_weights
63 +
64 +
65 +def maybe_save_metadata_and_attributes_for_weight_reloading(
66 + model: nn.Module, model_config: ModelConfig):
67 + # following is to support on the fly quantization, currently only supported
68 + # for torchao
69 + if model_config.quantization != "torchao":
70 + return
71 +
72 + if getattr(model, "process_weights_after_loading_already_called", False):
73 + # In case `process_weights_after_loading` is called multiple times
74 + # we'll skip it at later times
75 + logger.warning(
76 + "process_weights_after_loading already called for model %s", model)
77 + return
78 +
79 + from vllm.model_executor.model_loader.weight_utils import get_quant_config
80 + quant_config = get_quant_config(model_config, None)
81 +
82 + # If checkpoint is already torchao serialized, this means it's
83 + # pre-quantized quantization case, we'll skip saving the metadata
84 + # Otherwise, this is Step I2 of initialization steps of
85 + # online quantization
86 + # This step record the weights metadata and weight attributes so we can
87 + # restore the bfloat16 model weights during the relad step (R1 and R2)
88 + # see Notes in online_quantization.py for more details
89 + if not (hasattr(quant_config, "is_checkpoint_torchao_serialized") and \
90 + not quant_config.is_checkpoint_torchao_serialized):
91 + return
92 +
93 + # This is the I2 step of online quantiztion that saves
94 + # metadata and attributes of weights so they can be used in R1 and
95 + # R2 step, note that we only save these during initialization
96 +
97 + # Includes two things
98 + # 1. save floating point metadata (shape, dtype, device) for init
99 + # 2. save weight attributes, e.g. `output_dim`, `weight_loader` for init
100 +
101 + if getattr(model, "weight_metadata_and_attr_saved", False):
102 + return
103 +
104 + # save the dtype, shape and device for model parameter, used for
105 + # restoring the model high precision parameters before
106 + # reloading the weights
107 + assert not hasattr(model, "original_weights_rebuild_keys")
108 + model.original_weights_rebuild_keys = {}
109 + for name, p in model.named_parameters():
110 + model.original_weights_rebuild_keys[name] = {
111 + "shape": p.shape,
112 + "dtype": p.dtype,
113 + "device": p.device,
114 + }
115 +
116 + # record the weight attributes (loader functions etc.)
117 + # so these can be recovered later when we reload the weights
118 + # structure: {"weight_name": {"weight_attr_key": attr}}
119 + assert not hasattr(model, "recorded_weight_attr")
120 + model.recorded_weight_attr = {}
121 + for name, param in model.named_parameters():
122 + model.recorded_weight_attr[name] = {}
123 + for key in param.__dict__:
124 + if hasattr(param, key):
125 + attr = getattr(param, key)
126 + if not callable(attr):
127 + model.recorded_weight_attr[name][key] = attr
128 + elif hasattr(attr, "__self__") and param is attr.__self__:
129 + # if attr is a bonded method for an instance, and
130 + # attr.__self__ points to the instance (param)
131 + # we'll record the underlying function object
132 + model.recorded_weight_attr[name][key] = attr.__func__
133 + else:
134 + model.recorded_weight_attr[name][key] = attr
135 + # mark the metadata and attributes saved so we don't run it again
136 + model.weight_metadata_and_attr_saved = True
137 +
138 +
139 +def _bond_method_to_cls(func, obj):
140 + if hasattr(func, "__self__") or not callable(func):
141 + # If the function is already bound to an instance, return it as is
142 + return func
143 + else:
144 + return types.MethodType(func, obj)
145 +
146 +
147 +def load_weights_and_online_quantize(model_loader: DefaultModelLoader,
148 + model: nn.Module,
149 + model_config: ModelConfig) -> set[str]:
150 + # online quantization, right now only enabled for
151 + # torchao
152 + # R1, R2, R3, R4 in the Notes
153 +
154 + # TODO: Add fp8 support
155 + assert model_config.quantization == "torchao", "online " \
156 + "quantization is only enabled for torchao currently"
157 + # TODO: use create_weights to restore the weights to original state
158 +
159 + # Step R1: First restore the quantized weights to original bfloat16
160 + # weights, with original metadata (shape, dtype, device)
161 + # and attributes, so that bfloat16 weights can be loaded properly
162 + existing_param_names = dict(
163 + model.named_parameters(remove_duplicate=False)).keys()
164 + named_modules = dict(model.named_modules(remove_duplicate=False))
165 + model_device = None
166 +
167 + # Step R2: recover the parameter to the state before first loading
168 + for name, d in model.original_weights_rebuild_keys.items():
169 + _shape = d["shape"]
170 + _dtype = d["dtype"]
171 + _device = d["device"]
172 + if model_device is not None:
173 + assert model_device == _device, "Expecting all weights " \
174 + "to be in the same device for now, got both: " \
175 + f"{model_device} and {_device}"
176 + else:
177 + model_device = _device
178 +
179 + if name in existing_param_names:
180 + module_name, weight_name = name.rsplit(".", 1)
181 + module = named_modules[module_name]
182 + setattr(
183 + module, weight_name,
184 + torch.nn.Parameter(
185 + torch.empty(_shape, dtype=_dtype, device=_device)))
186 +
187 + # recorded_weight_attr is
188 + # {"weight_name": {"weight_attr_key": attr}}
189 + # e.g.
190 + # {
191 + # {
192 + # "layer.0.weight": {
193 + # "weight_loader": weight_loader_function_object,
194 + # "input_dim": 0, ...
195 + # },
196 + # "layer.1.weight": ...,
197 + # }
198 + # }
199 + for full_weight_name, weight_attr_dict in \
200 + model.recorded_weight_attr.items():
201 + for attr_name, attr in weight_attr_dict.items():
202 + module_name, weight_name = full_weight_name.rsplit(".", 1)
203 + module = named_modules[module_name]
204 + weight = getattr(module, weight_name)
205 + if not hasattr(weight, attr_name):
206 + setattr(weight, attr_name, _bond_method_to_cls(attr, weight))
207 +
208 + # Step I1: reload bfloat16 / high precision weights
209 + loaded_weights = model.load_weights(
210 + model_loader.get_all_weights(model_config, model))
211 +
212 + # Step I2: online quantize the weights
213 + # manually process weights after loading
214 + model.process_weights_after_loading_already_called = False
215 + process_weights_after_loading(model, model_config, model_device)
216 + model.process_weights_after_loading_already_called = True
217 + return loaded_weights
vllm/model_executor/model_loader/utils.py
+8 -1
@@ -95,6 +95,13 @@ def initialize_model(
95
96 def process_weights_after_loading(model: nn.Module, model_config: ModelConfig,
97 target_device: torch.device) -> None:
98 +
99 + # to avoid circular dependency
100 + from vllm.model_executor.model_loader.online_quantization import (
101 + maybe_save_metadata_and_attributes_for_weight_reloading)
102 + maybe_save_metadata_and_attributes_for_weight_reloading(
103 + model, model_config)
104 +
105 for _, module in model.named_modules():
106 if isinstance(module, QKVCrossParallelLinear):
107 # NOTE(Isotr0py): special case for cross QKV layer because
@@ -243,7 +250,7 @@ def get_architecture_class_name(model_config: ModelConfig) -> str:
250 class ParamMapping:
251 """
252 A class to handle parameter mapping for model weight loading.
246 - It creates a bidirectional mapping between packed parameters and their
253 + It creates a bidirectional mapping between packed parameters and their
254 constituent parts.
255 """
256 packed_mapping: dict[str, list[str]]
vllm/model_executor/model_loader/weight_utils.py
+26
@@ -246,8 +246,34 @@ def get_quant_config(model_config: ModelConfig,
246 # compressed-tensors uses a compressions_config
247 hf_quant_config = getattr(model_config.hf_config, "compression_config",
248 None)
249 +
250 if hf_quant_config is not None:
251 return quant_cls.from_config(hf_quant_config)
252 +
253 + # if hf_quant_config is None, we will try to get config from
254 + # hf_overrides
255 + hf_overrides = model_config.hf_overrides
256 + quantization_config_file = hf_overrides.get("quantization_config_file",
257 + None)
258 + if quantization_config_file is not None:
259 + if hasattr(quant_cls, "from_config_file"):
260 + return quant_cls.from_config_file(quantization_config_file)
261 + else:
262 + raise NotImplementedError(
263 + "from_config_file is specified in hf_override config, "
264 + "but quant_cls.from_config_file is not implemented in "
265 + f"{quant_cls}")
266 + quantization_config_json = hf_overrides.get(
267 + "quantization_config_dict_json", None)
268 + if quantization_config_json is not None:
269 + if hasattr(quant_cls, "from_config_dict_json"):
270 + return quant_cls.from_config_dict_json(quantization_config_json)
271 + else:
272 + raise NotImplementedError(
273 + "from_config_dict_json is specified in hf_override config, "
274 + "but quant_cls.from_config_dict_json is not implemented in "
275 + f"{quant_cls}")
276 +
277 # Inflight BNB quantization
278 if model_config.quantization == "bitsandbytes":
279 return quant_cls.from_config({})