Skip to content

Commit bc907b0

Browse files
Set environment variable on LNL CPUs before compression model compilation (#3246)
Copy of #3233 and #3247 to develop branch --------- Co-authored-by: Alexander Suslov <alexander.suslov@intel.com>
1 parent 62cb0df commit bc907b0

File tree

6 files changed

+106
-4
lines changed

6 files changed

+106
-4
lines changed

nncf/common/utils/backend.py

+16
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from enum import Enum
1313
from typing import Any, Callable, TypeVar, cast
1414

15+
from packaging import version
16+
1517
import nncf
1618
from nncf.experimental.common.check_feature import is_experimental_torch_tracing_enabled
1719

@@ -185,3 +187,17 @@ def is_openvino_available() -> bool:
185187
:return: True if openvino package is installed, False otherwise.
186188
"""
187189
return _OPENVINO_AVAILABLE
190+
191+
192+
def is_openvino_at_least(version_str: str) -> bool:
193+
"""
194+
Check if OpenVINO version is at least the specified one.
195+
196+
:param version_str: The version string to compare with the installed OpenVINO version. For example "2025.1".
197+
:return: True if the installed OpenVINO version is at least the specified one, False otherwise.
198+
"""
199+
if not _OPENVINO_AVAILABLE:
200+
return False
201+
202+
openvino_version = version.parse(openvino.__version__.split("-")[0])
203+
return version.parse(version_str) <= openvino_version

nncf/common/utils/cpu_info.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) 2025 Intel Corporation
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
import re
13+
14+
import cpuinfo # type: ignore
15+
16+
_IS_LNL_CPU = None
17+
18+
19+
def is_lnl_cpu() -> bool:
20+
global _IS_LNL_CPU
21+
if _IS_LNL_CPU is None:
22+
_IS_LNL_CPU = re.search(r"Ultra \d 2\d{2}", cpuinfo.get_cpu_info()["brand_raw"]) is not None
23+
return _IS_LNL_CPU

nncf/common/utils/helpers.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
import itertools
1313
import os
1414
import os.path as osp
15+
from contextlib import contextmanager
1516
from pathlib import Path
16-
from typing import Any, Dict, Hashable, Iterable, List, Optional, TypeVar, Union
17+
from typing import Any, Dict, Hashable, Iterable, Iterator, List, Optional, TypeVar, Union
1718

1819
from tabulate import tabulate
1920

@@ -75,3 +76,22 @@ def product_dict(d: Dict[TKey, List[Any]]) -> Iterable[Dict[TKey, Any]]:
7576
vals = d.values()
7677
for instance in itertools.product(*vals):
7778
yield dict(zip(keys, instance))
79+
80+
81+
@contextmanager
82+
def set_env_variable(key: str, value: str) -> Iterator[None]:
83+
"""
84+
Temporarily sets an environment variable.
85+
86+
:param key: Environment variable name.
87+
:param value: Environment variable value.
88+
"""
89+
old_value = os.environ.get(key)
90+
os.environ[key] = value
91+
try:
92+
yield
93+
finally:
94+
if old_value is not None:
95+
os.environ[key] = old_value
96+
else:
97+
del os.environ[key]

nncf/openvino/optimized_functions/models.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
from openvino.runtime import Node
2323
from openvino.runtime import opset13 as opset
2424

25+
from nncf.common.utils.backend import is_openvino_at_least
2526
from nncf.common.utils.caching import ResultsCache
2627
from nncf.common.utils.caching import cache_results
28+
from nncf.common.utils.cpu_info import is_lnl_cpu
29+
from nncf.common.utils.helpers import set_env_variable
2730
from nncf.openvino.graph.node_utils import convert_op
2831
from nncf.openvino.graph.node_utils import non_convertable_divide_op
2932
from nncf.quantization.algorithms.weight_compression.config import WeightCompressionConfig
@@ -115,6 +118,16 @@ def clear_ov_model_cache():
115118
OV_MODEL_CACHE.clear()
116119

117120

121+
def _compile_ov_model(model: ov.Model, device_name: str, config: Dict[str, str]) -> ov.CompiledModel:
122+
if is_lnl_cpu() and not is_openvino_at_least("2025.1"):
123+
with set_env_variable("DNNL_MAX_CPU_ISA", "AVX2_VNNI"):
124+
compiled_model = ov.compile_model(model, device_name=device_name, config=config)
125+
else:
126+
compiled_model = ov.compile_model(model, device_name=device_name, config=config)
127+
128+
return compiled_model
129+
130+
118131
def _infer_ov_model(
119132
ov_model_params: OVModelParameters, compiled_model: ov.CompiledModel, inputs: TensorList
120133
) -> TensorList:
@@ -412,7 +425,7 @@ def _build_compress_model(
412425
return ov_parameters, ov_results, ov_model_params
413426

414427
model = ov.Model(ov_results, ov_parameters)
415-
compiled_model = ov.compile_model(model, device_name="CPU", config={inference_precision(): ov.Type.f32})
428+
compiled_model = _compile_ov_model(model, device_name="CPU", config={inference_precision(): ov.Type.f32})
416429

417430
return partial(_infer_ov_model, ov_model_params, compiled_model)
418431

@@ -467,7 +480,7 @@ def _build_compress_decompress_model(
467480

468481
ov_results = [decompressed_weight] + ov_results if return_compressed_weight else [decompressed_weight]
469482
model = ov.Model(ov_results, ov_parameters)
470-
compiled_model = ov.compile_model(model, device_name="CPU", config={inference_precision(): ov.Type.f32})
483+
compiled_model = _compile_ov_model(model, device_name="CPU", config={inference_precision(): ov.Type.f32})
471484

472485
return partial(_infer_ov_model, ov_model_params, compiled_model)
473486

@@ -509,6 +522,6 @@ def _build_astype_model(ov_model_params: OVModelParameters, arg_shape: Tuple) ->
509522
arg = opset.parameter(arg_shape, dtype=DTYPE_MAP_OV[input_dtypes["input"]], name="input")
510523
res = opset.convert(arg, DTYPE_MAP_OV[output_dtypes["output"]])
511524
model = ov.Model([res], [arg])
512-
compiled_model = ov.compile_model(model, device_name="CPU", config={inference_precision(): ov.Type.f32})
525+
compiled_model = _compile_ov_model(model, device_name="CPU", config={inference_precision(): ov.Type.f32})
513526

514527
return partial(_infer_ov_model, ov_model_params, compiled_model)

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dependencies = [
4343
"packaging>=20.0",
4444
"pandas>=1.1.5,<2.3",
4545
"psutil",
46+
"py-cpuinfo>=9.0.0",
4647
"pydot>=1.4.1, <3.0.0",
4748
"pymoo>=0.6.0.1",
4849
"rich>=13.5.2",

tests/common/utils/test_helpers.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) 2025 Intel Corporation
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
import os
13+
14+
from nncf.common.utils.helpers import set_env_variable
15+
16+
17+
def test_set_env_variable():
18+
# Test the case when the variable is not set
19+
assert os.environ.get("TEST_VAR") is None
20+
with set_env_variable("TEST_VAR", "test_value"):
21+
assert os.environ.get("TEST_VAR") == "test_value"
22+
assert os.environ.get("TEST_VAR") is None
23+
24+
# Test the case when the variable is already set
25+
os.environ["TEST_VAR"] = "original_value"
26+
assert os.environ.get("TEST_VAR") == "original_value"
27+
with set_env_variable("TEST_VAR", "test_value"):
28+
assert os.environ.get("TEST_VAR") == "test_value"
29+
assert os.environ.get("TEST_VAR") == "original_value"

0 commit comments

Comments
 (0)