Skip to content
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

Dl/ov/tiny gpt2 example callbacks #20

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from

Conversation

daniil-lyakhov
Copy link
Owner

@daniil-lyakhov daniil-lyakhov commented May 31, 2023

Changes

  1. New custom forward api is introduced
  2. Adapters for tensor collectors are introduced
  3. tiny_gpt2 and mozilla_deepspeech examples are introduced

Copy link
Owner Author

Choose a reason for hiding this comment

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

@AlexKoff88 - main file

Comment on lines +122 to +134
@staticmethod
def _get_callback(model, sequence_container):
original_model_outputs_names = {op.node.friendly_name for op in model.outputs}

def complition_callback(outputs):
for op, value in outputs.items():
if op.node.friendly_name in original_model_outputs_names:
continue
if not isinstance(value, np.ndarray):
value = value.data
sequence_container[op.node.friendly_name].append(OVNNCFTensor(value))

return complition_callback
Copy link
Owner Author

Choose a reason for hiding this comment

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

@AlexKoff88 - callback creation for OpenVino

Copy link
Owner Author

Choose a reason for hiding this comment

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

@AlexKoff88 - custom inference in use here

Copy link
Owner Author

Choose a reason for hiding this comment

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

@AlexKoff88 - this example is working too

@@ -35,7 +35,7 @@ def create(model: TModel) -> NNCFGraph:
from nncf.onnx.graph.nncf_graph_builder import GraphConverter

return GraphConverter.create_nncf_graph(model)
if model_backend == BackendType.OPENVINO:
if model_backend in [BackendType.OPENVINO, BackendType.OPTIMUM]:

Choose a reason for hiding this comment

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

I didn't get why you need BackendType.OPTIMUM?

Copy link
Owner Author

Choose a reason for hiding this comment

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

This is redundant code from my previous experiments, please ignore

if self._is_custom_inference:
sequence_container = defaultdict(list)
custom_forward = self.dataset.get_custom_forward(
engine.compiled_model, self._get_callback(model, sequence_container)
Copy link
Owner Author

Choose a reason for hiding this comment

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

engine.compiled_model is supposed to be in the backend specific part


def set_ov_model_in_hf_model(hf_model, ov_model):
hf_model.model = ov_model
hf_model.request = ov_model.create_infer_request()

Choose a reason for hiding this comment

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

I assume that ov_model has a type of ov::Model. If so, .create_infer_request() works only for CompiledModel

Copy link
Owner Author

Choose a reason for hiding this comment

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

You are right

set_ov_model_in_hf_model(hf_model, ov_model)

def _callback_fn(info):
outputs = {k: v for k, v in zip(info["infer_request"].model_outputs, info["infer_request"].outputs)}

Choose a reason for hiding this comment

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

Does the InferRequest object have .model_outputs property?

Copy link
Owner Author

Choose a reason for hiding this comment

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

return data_item


dataset = nncf.CustomInferenceDataset([tokens] * 10, transform_fn, get_custom_forward)

Choose a reason for hiding this comment

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

I don't think we should make get_custom_forward a part of Dataset API. I propose:

  • rename it to get_forward_fn(model: ov.Model, output_processing_callback: Callable) -> Callable
  • make it an optional argument of nncf.quantize() API

Copy link

@alexsu52 alexsu52 May 31, 2023

Choose a reason for hiding this comment

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

I absolutely agree that it should not be part of Dataset API.

Comments from my side:
I have some concerns about get_forward_fn:

  1. output_processing_callback is not needed for Torch and Keras TF models. It can confuse developer because they will call output_processing_callback that does not do it anything.
  2. signature of output_processing_callback is not clear for different frameworks.

Proposal:

  1. Introduce get_forward_fn(model: ov.Model) -> Callable Torch and Keras TF and get_forward_fn(model: ov.Model, statistic_aggregator: StatisticsAggregator) -> Callable for OpenVINO, ONNX and TF.

Pros:

  • It is addressed to 1 via explicit introduction different signatures for different frameworks because different frameworks collect statistics with using different approaches.

  • It is addressed to 2 because methods of a class can be easily documented + sugar from IDE. It also can provide several interfaces to register model output. statistic_collector.register_model_output(name, tensor) ``statistic_collector.register_model_outputs(outputs: Dict[str, tensor])
    Request changes:

def get_custom_forward(ov_model, statistic_aggregator):
    hf_model = model_with_pkv
    set_ov_model_in_hf_model(hf_model, ov_model)

    def _callback_fn(info):
        outputs = {k.key.get_any_name(): v.value for k, v in zip(info["infer_request"].model_outputs, info["infer_request"].outputs)}
        statistic_aggregator.register_model_outputs(outputs)
  1. Introduce a different classes to join framework model and custom forward function for each framework. For examplenncf.OVModelWithCustomForward(model: ov.Model, get_forward_fn: Callable) for OV

Pros:

  • nncf.quantize and nncf.quantize_with_accuracy_control w/o extending signature
  • The class explicitly specified signature of get_forward_fn for framework model.
  • Easy reuse in other algorithms
ov_model_with_custom_forward = nncf.OVModelWithCustomForward(model_with_pkv.model, get_forward_fn)
quantized_model_with_custom_forward = nncf.quantize(ov_model_with_custom_forward, dataset, subset_size=3)
  1. IMHO: rename get_forward_fn -> make_forward_fn

Choose a reason for hiding this comment

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

To tell the truth, I am still skeptical about the whole approach of collecting recurrent states and how this is applicable to other models. Now, I am looking at the Whisper notebook and I would not use this API since it requires much more effort and code rewriting to use the proposed API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants