Skip to content

Commit b28d33e

Browse files
committed
Made changes to incorporate PEFT model configs and addressed the comments on naming and ordering as well.
Signed-off-by: Dhiraj Kumar Sah <[email protected]>
1 parent daa9e24 commit b28d33e

File tree

7 files changed

+95
-65
lines changed

7 files changed

+95
-65
lines changed

QEfficient/base/modeling_qeff.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,17 @@ class QEFFBaseModel(ABC):
5353
def _transform_names(cls) -> List[str]:
5454
return [x.__name__ for x in cls._pytorch_transforms + cls._onnx_transforms]
5555

56-
def create_model_params(self, **kwargs) -> Dict:
57-
model_params = copy.deepcopy(kwargs)
58-
59-
model_params["config"] = self.model.config.to_diff_dict()
60-
model_params["_transform_names"] = self._transform_names()
61-
return model_params
62-
6356
def __init__(self, model: torch.nn.Module, **kwargs) -> None:
6457
super().__init__()
6558
self.model = model
6659
self.hash_params = self.create_model_params(**kwargs)
6760

68-
if hasattr(self.model.config, "architectures"):
69-
self.model_architecture = self.model.config.architectures[0]
7061
self.onnx_path: Optional[str] = None
7162
self.qpc_path: Optional[str] = None
7263
self.qpc_session: Optional[QAICInferenceSession] = None
7364
self.pretrained_model_name_or_path = kwargs.get("pretrained_model_name_or_path", None)
65+
if hasattr(self.model.config, "architectures"):
66+
self.model_architecture = getattr(self.model.config, "architectures", [None])[0]
7467

7568
# Apply the transformations
7669
any_transformed = False
@@ -83,6 +76,13 @@ def __init__(self, model: torch.nn.Module, **kwargs) -> None:
8376
else:
8477
logger.info(f"Pytorch transforms applied to model: {self.model_name}")
8578

79+
def create_model_params(self, **kwargs) -> Dict:
80+
model_params = copy.deepcopy(kwargs)
81+
model_params["config"] = self.model.config.to_diff_dict()
82+
model_params["peft_config"] = getattr(self.model, "active_peft_config", None)
83+
model_params["applied_transform_names"] = self._transform_names()
84+
return model_params
85+
8686
@property
8787
@abstractmethod
8888
def model_name(self) -> str: ...
@@ -150,17 +150,15 @@ def _export(
150150
:onnx_transform_kwargs (dict): Additional arguments to be passed to `Transform.apply` for this class.
151151
:export_dir (str): Specify the export directory. The export_dir will be suffixed with a hash corresponding to current model.
152152
"""
153-
154-
export_dir = Path(export_dir or (QEFF_HOME / self.model_architecture / self.model_name))
153+
parent_dir = self.model_architecture or self.model_name
154+
export_dir = Path(export_dir or (QEFF_HOME / parent_dir / self.model_name))
155155
export_hash, filtered_hash_params = filter_and_create_export_hash(
156156
model_params=self.hash_params,
157157
output_names=output_names,
158158
dynamic_axes=dynamic_axes,
159159
export_kwargs=export_kwargs,
160160
onnx_transform_kwargs=onnx_transform_kwargs,
161-
export_dir=export_dir,
162161
)
163-
164162
export_dir = export_dir.with_name(export_dir.name + "-" + export_hash)
165163
onnx_path = export_dir / f"{self.model_name}.onnx"
166164
if onnx_path.is_file():
@@ -237,7 +235,7 @@ def _export(
237235
shutil.rmtree(tmp_onnx_dir, ignore_errors=True)
238236

239237
# Dump JSON file with hashed parameters
240-
hashed_params_export_path = export_dir / "hashed_model_params.json"
238+
hashed_params_export_path = export_dir / "hashed_export_params.json"
241239
create_json(hashed_params_export_path, filtered_hash_params)
242240
logger.info("Hashed parameters exported successfully.")
243241

QEfficient/transformers/models/modeling_auto.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def __init__(self, model: nn.Module, pooling=None, **kwargs):
169169
self.model, _ = PoolingTransform.apply(self.model, pooling)
170170

171171
self.model.base_model.config.use_cache = True
172-
self.hash_params["qeff_class"] = self.__class__.__name__
172+
self.hash_params["qeff_auto_class"] = self.__class__.__name__
173173

174174
@classmethod
175175
@with_replaced_quantizers
@@ -430,7 +430,7 @@ class QEffVisionEncoderForTextImageToTextModel(QEFFBaseModel):
430430
def __init__(self, model: nn.modules, **kwargs):
431431
super().__init__(model, **kwargs)
432432
self.model = model.get_qeff_vision_encoder()
433-
self.hash_params["qeff_class"] = self.__class__.__name__
433+
self.hash_params["qeff_auto_class"] = self.__class__.__name__
434434

435435
def export(self, inputs, output_names, dynamic_axes, export_dir=None):
436436
return self._export(inputs, output_names, dynamic_axes, export_dir)
@@ -485,7 +485,7 @@ class QEffCausalLMForTextImageToTextModel(QEFFBaseModel):
485485
def __init__(self, model, **kwargs):
486486
super().__init__(model, **kwargs)
487487
self.model = model.get_qeff_language_decoder()
488-
self.hash_params["qeff_class"] = self.__class__.__name__
488+
self.hash_params["qeff_auto_class"] = self.__class__.__name__
489489

490490
def export(self, inputs, output_names, dynamic_axes, export_dir=None):
491491
return self._export(inputs, output_names, dynamic_axes, export_dir)
@@ -773,7 +773,7 @@ def kv_offload_generate(
773773
inputs["input_ids"],
774774
(0, padded_len - input_ids_length),
775775
"constant",
776-
1,
776+
pad_token_id,
777777
)
778778
inputs["attention_mask"] = torch.nn.functional.pad(
779779
inputs["attention_mask"], (0, padded_len - input_ids_length), "constant", 0
@@ -911,7 +911,7 @@ def __init__(
911911
self.model.config.vision_config.use_flash_attn = "false"
912912
else:
913913
self.model.config.text_config.use_cache = True
914-
self.hash_params["qeff_class"] = self.__class__.__name__
914+
self.hash_params["qeff_auto_class"] = self.__class__.__name__
915915

916916
@classmethod
917917
def from_pretrained(
@@ -1091,7 +1091,7 @@ def cloud_ai_100_generate(
10911091
inputs["input_ids"],
10921092
(0, padded_len - input_ids_length),
10931093
"constant",
1094-
1,
1094+
pad_token_id,
10951095
)
10961096
inputs["attention_mask"] = torch.nn.functional.pad(
10971097
inputs["attention_mask"], (0, padded_len - input_ids_length), "constant", 0
@@ -1360,7 +1360,7 @@ def __init__(
13601360
self.pretrained_model_name_or_path = kwargs.get("pretrained_model_name_or_path", None)
13611361
self.model, transformed = SpDTransform.apply(self.model, qaic_config, **kwargs)
13621362
self.is_tlm = transformed
1363-
self.hash_params["qeff_class"] = self.__class__.__name__
1363+
self.hash_params["qeff_auto_class"] = self.__class__.__name__
13641364
# ---Sampling---
13651365
# Note: SamplerTransform should be applied after all other transforms
13661366
# are done. The role of the sampler is to just add nodes at the output of the
@@ -1901,7 +1901,7 @@ def __init__(self, model: nn.Module, **kwargs):
19011901
super().__init__(model, **kwargs)
19021902
self.model.config.use_cache = True
19031903
self.num_layers = model.config.num_hidden_layers
1904-
self.hash_params["qeff_class"] = self.__class__.__name__
1904+
self.hash_params["qeff_auto_class"] = self.__class__.__name__
19051905

19061906
@property
19071907
def get_model_config(self) -> dict:

QEfficient/utils/_utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
PreTrainedTokenizerFast,
2626
)
2727

28-
from QEfficient.utils.cache import hash_dict_params
2928
from QEfficient.utils.constants import KWARGS_EXCLUSION_LIST, QEFF_MODELS_DIR, Constants, QnnConstants
29+
from QEfficient.utils.hash_utils import hash_dict_params
3030
from QEfficient.utils.logging_utils import logger
3131

3232

@@ -564,7 +564,7 @@ def create_json(file_path: str, json_data: object):
564564
"""
565565
try:
566566
with open(file_path, "w") as file:
567-
json.dump(json_data, file, indent=4)
567+
json.dump(make_serializable(json_data), file, indent=4)
568568
except Exception as e:
569569
print(f"Failed to create JSON File {file_path}: {e}")
570570

@@ -772,6 +772,8 @@ def filter_and_create_export_hash(**kwargs):
772772
onnx_transform_kwargs = kwargs.get("onnx_transform_kwargs")
773773
if onnx_transform_kwargs:
774774
filtered_params.update(onnx_transform_kwargs)
775+
if filtered_params.get("peft_config") is not None:
776+
filtered_params["peft_config"] = filtered_params["peft_config"].to_dict()
775777

776778
return hash_dict_params(filtered_params), filtered_params
777779

QEfficient/utils/cache.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@
55
#
66
# ----------------------------------------------------------------------------
77

8-
import hashlib
9-
import json
108
import os
119
from pathlib import Path
12-
from typing import Dict
13-
14-
from QEfficient.utils.constants import HASH_HEXDIGEST_STR_LEN
1510

1611
QEFF_HOME: Path = None
1712
if "QEFF_HOME" in os.environ:
@@ -20,34 +15,3 @@
2015
QEFF_HOME = Path(os.environ["XDG_CACHE_HOME"]) / "qeff_models"
2116
else:
2217
QEFF_HOME = Path("~/.cache/qeff_models").expanduser()
23-
24-
25-
def json_serializable(obj):
26-
if isinstance(obj, set):
27-
return sorted(obj)
28-
raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable")
29-
30-
31-
def to_hashable(obj) -> bytes:
32-
"""
33-
Converts obj to bytes such that same object will result in same hash
34-
"""
35-
return json.dumps(
36-
obj,
37-
skipkeys=False,
38-
ensure_ascii=True,
39-
check_circular=True,
40-
allow_nan=False,
41-
indent=None,
42-
separators=(",", ":"),
43-
default=json_serializable,
44-
sort_keys=True,
45-
).encode()
46-
47-
48-
def hash_dict_params(dict_items: Dict, hash_string_size: int = HASH_HEXDIGEST_STR_LEN):
49-
"""
50-
Takes a dictionary of items and returns a SHA256 hash object
51-
"""
52-
mhash = hashlib.sha256(to_hashable(dict_items))
53-
return mhash.hexdigest()[:hash_string_size]

QEfficient/utils/hash_utils.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# -----------------------------------------------------------------------------
2+
#
3+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4+
# SPDX-License-Identifier: BSD-3-Clause
5+
#
6+
# ----------------------------------------------------------------------------
7+
8+
import hashlib
9+
import json
10+
from typing import Dict
11+
12+
from QEfficient.utils.constants import HASH_HEXDIGEST_STR_LEN
13+
14+
15+
def json_serializable(obj):
16+
if isinstance(obj, set):
17+
return sorted(obj)
18+
raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable")
19+
20+
21+
def to_hashable(obj) -> bytes:
22+
"""
23+
Converts obj to bytes such that same object will result in same hash
24+
"""
25+
return json.dumps(
26+
obj,
27+
skipkeys=False,
28+
ensure_ascii=True,
29+
check_circular=True,
30+
allow_nan=False,
31+
indent=None,
32+
separators=(",", ":"),
33+
default=json_serializable,
34+
sort_keys=True,
35+
).encode()
36+
37+
38+
def hash_dict_params(dict_items: Dict, hash_string_size: int = HASH_HEXDIGEST_STR_LEN):
39+
"""
40+
Takes a dictionary of items and returns a SHA256 hash object
41+
"""
42+
mhash = hashlib.sha256(to_hashable(dict_items))
43+
return mhash.hexdigest()[:hash_string_size]

tests/peft/lora/test_lora_model.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,24 @@
2121
configs = [
2222
pytest.param(
2323
AutoConfig.for_model(
24-
"llama", num_hidden_layers=2, num_attention_heads=4, num_key_value_heads=2, hidden_size=128
24+
"llama",
25+
num_hidden_layers=2,
26+
num_attention_heads=4,
27+
num_key_value_heads=2,
28+
hidden_size=128,
29+
architectures=["LlamaForCausalLM"],
2530
),
2631
LoraConfig(target_modules=["q_proj", "v_proj"], task_type="CAUSAL_LM", lora_alpha=8),
2732
id="llama-2l-4h-2kvh-128d-qv",
2833
),
2934
pytest.param(
3035
AutoConfig.for_model(
31-
"mistral", num_hidden_layers=2, num_attention_heads=4, num_key_value_heads=2, hidden_size=128
36+
"mistral",
37+
num_hidden_layers=2,
38+
num_attention_heads=4,
39+
num_key_value_heads=2,
40+
hidden_size=128,
41+
architectures=["MistralForCausalLM"],
3242
),
3343
LoraConfig(target_modules=["q_proj", "v_proj"], task_type="CAUSAL_LM", lora_alpha=6),
3444
id="mistral-2l-4h-128d-qv",

tests/peft/test_peft_model.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,24 @@
2020
configs = [
2121
pytest.param(
2222
AutoConfig.for_model(
23-
"llama", num_hidden_layers=2, num_attention_heads=4, num_key_value_heads=2, hidden_size=128
23+
"llama",
24+
num_hidden_layers=2,
25+
num_attention_heads=4,
26+
num_key_value_heads=2,
27+
hidden_size=128,
28+
architectures=["LlamaForCausalLM"],
2429
),
2530
LoraConfig(target_modules=["q_proj", "v_proj"], task_type="CAUSAL_LM"),
2631
id="llama-2l-4h-2kvh-128d-qv",
2732
),
2833
pytest.param(
2934
AutoConfig.for_model(
30-
"mistral", num_hidden_layers=2, num_attention_heads=4, num_key_value_heads=2, hidden_size=128
35+
"mistral",
36+
num_hidden_layers=2,
37+
num_attention_heads=4,
38+
num_key_value_heads=2,
39+
hidden_size=128,
40+
architectures=["MistralForCausalLM"],
3141
),
3242
LoraConfig(target_modules=["q_proj", "k_proj", "v_proj"], task_type="CAUSAL_LM"),
3343
id="mistral-2l-4h-128d-qkv",
@@ -83,6 +93,9 @@ def test_auto_peft_model_for_causal_lm_from_pretrained(base_config, adapter_conf
8393
QEffAutoPeftModelForCausalLM.from_pretrained(adapter_path / adapter_name, full_batch_size=4)
8494

8595

96+
# This test isn't required anymore as different adapter names should generate different hashes. We'll
97+
# phase out this test in some time.
98+
@pytest.mark.skip(reason="Different adapter names will create different hashes so we'll skip this test.")
8699
def test_auto_peft_model_for_causal_lm_hash():
87100
base_config_0, adapter_config_0 = configs[0].values
88101
base_config_1, adapter_config_1 = configs[1].values
@@ -129,7 +142,7 @@ def test_auto_peft_model_for_causal_lm_export(base_config, adapter_config, tmp_p
129142
qeff_model.export(tmp_path)
130143
end = perf_counter()
131144
export_time_0 = end - start
132-
model_path = tmp_path.with_name(tmp_path.name + "-" + qeff_model.model_hash)
145+
model_path = tmp_path.with_name(tmp_path.name + "-" + qeff_model.export_hash)
133146
assert model_path.is_dir()
134147
assert qeff_model.onnx_path.is_file()
135148

0 commit comments

Comments
 (0)