# Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. import copy import unittest import torch from executorch import exir from executorch.backends.example.example_partitioner import ExamplePartitioner from executorch.backends.example.example_quantizer import ExampleQuantizer from executorch.exir import to_edge from executorch.exir.backend.canonical_partitioners.duplicate_dequant_node_pass import ( DuplicateDequantNodePass, ) from executorch.exir.delegate import executorch_call_delegate from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e from torch.export import export from torchvision.models.quantization import mobilenet_v2 class TestExampleDelegate(unittest.TestCase): def test_delegate_linear(self): class Conv2dModule(torch.nn.Module): def __init__(self): super().__init__() self.conv2d = torch.nn.Conv2d(16, 33, 3) def forward(self, arg): return self.conv2d(arg) @staticmethod def get_example_inputs(): return (torch.randn(20, 16, 50, 100),) model = Conv2dModule() example_inputs = Conv2dModule.get_example_inputs() EDGE_COMPILE_CONFIG = exir.EdgeCompileConfig( _check_ir_validity=False, _skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend. ) m = model.eval() m = torch.export.export_for_training(m, copy.deepcopy(example_inputs)).module() # print("original model:", m) quantizer = ExampleQuantizer() # quantizer = XNNPACKQuantizer() # if we set is_per_channel to True, we also need to add out_variant of quantize_per_channel/dequantize_per_channel # operator_config = get_symmetric_quantization_config(is_per_channel=False) # quantizer.set_global(operator_config) m = prepare_pt2e(m, quantizer) # calibration m(*example_inputs) m = convert_pt2e(m) quantized_gm = m exported_program = to_edge( export(quantized_gm, copy.deepcopy(example_inputs)), compile_config=EDGE_COMPILE_CONFIG, ) lowered_export_program = exported_program.to_backend( ExamplePartitioner(), ) print("After lowering to qnn backend: ") lowered_export_program.exported_program().graph.print_tabular() def test_delegate_mobilenet_v2(self): model = mobilenet_v2(num_classes=3) model.eval() example_inputs = (torch.rand(1, 3, 320, 240),) EDGE_COMPILE_CONFIG = exir.EdgeCompileConfig( _check_ir_validity=False, _skip_dim_order=True, # TODO(T182928844): Delegate dim order op to backend. ) m = model.eval() m = torch.export.export_for_training(m, copy.deepcopy(example_inputs)).module() quantizer = ExampleQuantizer() m = prepare_pt2e(m, quantizer) # calibration m(*example_inputs) m = convert_pt2e(m) quantized_gm = m exported_program = to_edge( export(quantized_gm, copy.deepcopy(example_inputs)), compile_config=EDGE_COMPILE_CONFIG, ) lowered_export_program = exported_program.transform( [DuplicateDequantNodePass()] ).to_backend( ExamplePartitioner(), ) lowered_export_program.exported_program().graph.print_tabular() call_deleage_node = [ node for node in lowered_export_program.exported_program().graph.nodes if node.target == executorch_call_delegate ] self.assertEqual(len(call_deleage_node), 1)