Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ wheels/
*.egg-info/
.installed.cfg
*.egg

my_project_env
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
my_project_env

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,156 @@ def extract_submodel(self, model_transformer, input_id, output_id):
output_ids=[output_id],
node_mapping=self._node_mapping,
)
# Copyright (c) 2025 Intel Corporation
# 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like some issues with the code merging, there are two different classes with the same name in the PR

# 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 Optional
import numpy as np
import openvino as ov

import nncf
from nncf.common.graph import NNCFGraph, NNCFNode
from nncf.common.graph.transformations.commands import TargetType
from nncf.common.logging import nncf_logger
from nncf.experimental.common.tensor_statistics.collectors import TensorCollector
from nncf.openvino.graph.metatypes.groups import FAKE_QUANTIZE_OPERATIONS, OPERATIONS_WITH_BIAS_REDUCED
from nncf.openvino.graph.model_builder import OVModelBuilder
from nncf.openvino.graph.node_utils import (
get_activation_channel_axis,
get_bias_value,
is_node_with_bias,
)
from nncf.openvino.graph.transformations.command_creation import OVCommandCreator
from nncf.openvino.graph.transformations.commands import (
OVBiasCorrectionCommand,
OVModelExtractionCommand,
OVTargetPoint,
)
from nncf.openvino.statistics.collectors import get_mean_statistic_collector
from nncf.quantization.algorithms.fast_bias_correction.backend import FastBiasCorrectionAlgoBackend
from nncf.tensor import Tensor


class OVFastBiasCorrectionAlgoBackend(FastBiasCorrectionAlgoBackend):
def __init__(self, model):
self._node_mapping = {op.get_friendly_name(): op for op in model.get_ops()}
self._model_builder = OVModelBuilder()

@staticmethod
def target_point(target_type: TargetType, target_node_name: str, port_id: int) -> OVTargetPoint:
return OVTargetPoint(target_type, target_node_name, port_id)

@staticmethod
def create_bias_correction_command(
node: NNCFNode, bias_value: Tensor, nncf_graph: NNCFGraph
) -> OVBiasCorrectionCommand:
return OVCommandCreator.create_command_to_update_bias(node, bias_value.data, nncf_graph)

@staticmethod
def model_extraction_command(
input_ids: list[tuple[str, int]], output_ids: list[tuple[str, int]]
) -> OVModelExtractionCommand:
return OVModelExtractionCommand(input_ids, output_ids)

@staticmethod
def mean_statistic_collector(
channel_axis: int,
inplace: bool,
num_samples: Optional[int] = None,
window_size: Optional[int] = None,
) -> TensorCollector:
return get_mean_statistic_collector(num_samples, channel_axis, window_size, inplace)

@staticmethod
def get_sub_input_output_names(subgraph: ov.Model) -> tuple[str, str]:
return subgraph.inputs[0].get_any_name(), subgraph.outputs[0].get_any_name()

@staticmethod
def create_input_data(
shape: tuple[int], data: list[Tensor], input_name: str, channel_axis: int
) -> dict[str, np.ndarray]:
"""
Create input tensor data for FastBiasCorrection.
Handles both 1D and multi-dimensional input safely.
"""
if len(shape) == 1:
nncf_logger.debug(f"Applying 1D input shape fix for FastBiasCorrection, shape={shape}")
if not data:
return {input_name: np.zeros(shape, dtype=np.float32)}
return {input_name: data[0].data}

blob = np.zeros(shape, dtype=data[0].data.dtype)
num_channels = shape[channel_axis]

if len(data) != num_channels:
nncf_logger.warning(
f"Mismatch between len(data)={len(data)} and expected channels={num_channels}. "
f"Using min(len(data), num_channels)."
)

for idx in range(min(num_channels, len(data))):
index = [slice(None)] * blob.ndim
index[channel_axis] = idx
try:
blob[tuple(index)] = data[idx].data
except Exception as e:
nncf_logger.error(
f"Error assigning channel {idx}: {e}. "
f"Shape={shape}, ChannelAxis={channel_axis}, DataShape={data[idx].data.shape}"
)
raise e

return {input_name: blob}

def get_bias_value(self, node: NNCFNode, nncf_graph: NNCFGraph, model: ov.Model) -> Tensor:
return Tensor(get_bias_value(node, nncf_graph, model, node_mapping=self._node_mapping))

@staticmethod
def get_activation_port_ids_for_bias_node(node: NNCFNode) -> tuple[int, int]:
activation_ports = [0, 1]
for weight_port in node.layer_attributes.get_const_port_ids():
activation_ports.remove(weight_port)
assert len(activation_ports) == 1
activation_port = activation_ports[0]
return activation_port, 0

@staticmethod
def is_quantized_weights(node: NNCFNode, nncf_graph: NNCFGraph) -> bool:
# Check whether the node has quantized weights
if node.layer_attributes is None:
return False
const_port_ids = node.layer_attributes.get_const_port_ids()
assert len(const_port_ids) == 1
weight_node = nncf_graph.get_input_edge_by_port_id(node, const_port_ids[0]).from_node
return weight_node.metatype in FAKE_QUANTIZE_OPERATIONS

@staticmethod
def process_model_output(raw_data: dict, output_name: str) -> Tensor:
return Tensor(raw_data[output_name])

@staticmethod
def is_node_with_bias(node: NNCFNode, nncf_graph: NNCFGraph) -> bool:
return is_node_with_bias(node, nncf_graph, OPERATIONS_WITH_BIAS_REDUCED)

@staticmethod
def get_node_names_for_input_output_statistics(node: NNCFNode, nncf_graph: NNCFGraph) -> tuple[str, str]:
return node.node_name, node.node_name

@staticmethod
def get_activation_channel_axis(node: NNCFNode, port_id: int, input_shape: tuple[int]) -> int:
return get_activation_channel_axis(node, port_id, input_shape)

def extract_submodel(self, model_transformer, input_id, output_id):
return self._model_builder.build(
input_ids=[input_id],
output_ids=[output_id],
node_mapping=self._node_mapping,
)
2 changes: 1 addition & 1 deletion src/nncf/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = "2.19.0"
__version__ = "2.19.0.dev0+1489448a3dirty"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__version__ = "2.19.0.dev0+1489448a3dirty"
__version__ = "2.19.0"



BKC_TORCH_SPEC = "==2.9.*"
Expand Down