예제 #1
0
def test_find_node_in_nx_graph_by_scope():
    model = TwoConvTestModel()
    nncf_model = NNCFNetwork(deepcopy(model),
                             input_infos=[ModelInputInfo([1, 1, 4, 4])
                                          ])  # type: NNCFNetwork
    nncf_graph = nncf_model.get_original_graph()

    # Valid scopes should be successfully found
    valid_nncf_modules = nncf_model.get_nncf_modules()
    nodes_list = list(nncf_graph._nx_graph.nodes)
    for module_scope, _ in valid_nncf_modules.items():
        graph_node = nncf_graph.find_node_in_nx_graph_by_scope(module_scope)
        assert graph_node is not None
        assert isinstance(graph_node, dict)
        assert graph_node['key'] in nodes_list

    fake_model = BasicConvTestModel()
    fake_nncf_model = NNCFNetwork(deepcopy(fake_model),
                                  input_infos=[ModelInputInfo([1, 1, 4, 4])])

    # Not valid scopes shouldn't be found
    fake_nncf_modules = fake_nncf_model.get_nncf_modules()
    for module_scope, _ in fake_nncf_modules.items():
        graph_node = nncf_graph.find_node_in_nx_graph_by_scope(module_scope)
        assert graph_node is None
예제 #2
0
def test_activation_shape_tracing(input_shape: Tuple):
    model = ModelForTest()
    input_info = ModelInputInfo(input_shape)
    graph_builder = GraphBuilder(create_dummy_forward_fn([
        input_info,
    ]))
    graph = graph_builder.build_graph(model)

    shape1 = (input_shape[0], ModelForTest.CONV1_OUT_CHANNELS, input_shape[2],
              input_shape[3])
    ref_node_ids_and_output_shapes = [
        # TODO: extend with checking input tensor size once proper input node marking is implemented
        ("0 ModelForTest/Conv2d[conv1]/conv2d", [shape1]),
        ("1 ModelForTest/BatchNorm2d[bn1]/batch_norm", [shape1]),
        ("2 ModelForTest/ReLU[relu1]/RELU", [shape1, shape1]),
        ("3 ModelForTest/max_pool2d",
         [(shape1[0], shape1[1], shape1[2] // ModelForTest.MAXPOOL_SIZE,
           shape1[3] // ModelForTest.MAXPOOL_SIZE)]),
        ("4 ModelForTest/ConvTranspose2d[convt1]/conv_transpose2d",
         [input_shape]),
        ("5 ModelForTest/cat",
         [(input_shape[0], ModelForTest.CONV2_IN_CHANNELS, input_shape[2],
           input_shape[3])])

        # TODO: extend with checking output tensor size once proper output node marking is implemented
    ]
    for node_id, ref_output_shapes in ref_node_ids_and_output_shapes:
        # pylint:disable=protected-access
        output_edges = graph._get_nncf_graph_pattern_input_output([
            node_id,
        ]).output_edges
        output_shapes = [x.tensor_shape for x in output_edges]
        assert output_shapes == ref_output_shapes, "Failed for {}".format(
            node_id)
 def test_build_graph(self, desc: ModelDesc):
     net = desc.model_builder()
     input_sample_sizes = desc.input_sample_sizes
     if isinstance(input_sample_sizes, tuple):
         input_info_list = [
             ModelInputInfo(sample_size)
             for sample_size in input_sample_sizes
         ]
     else:
         input_info_list = [ModelInputInfo(input_sample_sizes)]
     dummy_forward_fn = desc.dummy_forward_fn
     if not dummy_forward_fn:
         dummy_forward_fn = create_dummy_forward_fn(input_info_list)
     graph_builder = GraphBuilder(custom_forward_fn=dummy_forward_fn)
     graph = graph_builder.build_graph(net)
     check_graph(graph, desc.dot_filename, 'original')
예제 #4
0
def test_check_correct_modules_replacement():
    model = TwoConvTestModel()
    nncf_model = NNCFNetwork(TwoConvTestModel(),
                             input_infos=[ModelInputInfo([1, 1, 4, 4])
                                          ])  # type: NNCFNetwork

    _, nncf_modules = check_correct_nncf_modules_replacement(model, nncf_model)
    assert set(nncf_modules) == set(nncf_model.get_nncf_modules())
예제 #5
0
    def test_operator_metatype_marking(self):
        from nncf.dynamic_graph.operator_metatypes import Conv2dMetatype, BatchNormMetatype, RELUMetatype, \
            MaxPool2dMetatype, \
            ConvTranspose2dMetatype, DepthwiseConv2dSubtype, AddMetatype, AvgPool2dMetatype, LinearMetatype
        ref_scope_vs_metatype_dict = {
            "/" + MODEL_INPUT_OP_NAME + "_0": NoopMetatype,
            "ModelForMetatypeTesting/NNCFConv2d[conv_regular]/conv2d_0": Conv2dMetatype,
            "ModelForMetatypeTesting/BatchNorm2d[bn]/batch_norm_0": BatchNormMetatype,
            "ModelForMetatypeTesting/RELU_0": RELUMetatype,
            "ModelForMetatypeTesting/MaxPool2d[max_pool2d]/max_pool2d_0": MaxPool2dMetatype,
            "ModelForMetatypeTesting/NNCFConvTranspose2d[conv_transpose]/conv_transpose2d_0": ConvTranspose2dMetatype,
            "ModelForMetatypeTesting/NNCFConv2d[conv_depthwise]/conv2d_0": DepthwiseConv2dSubtype,
            "ModelForMetatypeTesting/__iadd___0": AddMetatype,
            "ModelForMetatypeTesting/AdaptiveAvgPool2d[adaptive_avg_pool]/adaptive_avg_pool2d_0": AvgPool2dMetatype,
            "ModelForMetatypeTesting/NNCFLinear[linear]/linear_0": LinearMetatype
        }
        class ModelForMetatypeTesting(torch.nn.Module):
            def __init__(self):
                super().__init__()
                self.conv_regular = torch.nn.Conv2d(in_channels=3,
                                                    out_channels=16,
                                                    kernel_size=3)
                self.bn = torch.nn.BatchNorm2d(num_features=16)
                self.max_pool2d = torch.nn.MaxPool2d(kernel_size=2)
                self.conv_transpose = torch.nn.ConvTranspose2d(in_channels=16,
                                                               out_channels=8,
                                                               kernel_size=3)
                self.conv_depthwise = torch.nn.Conv2d(in_channels=8, out_channels=8,
                                                      kernel_size=5, groups=8)
                self.adaptive_avg_pool = torch.nn.AdaptiveAvgPool2d(output_size=1)
                self.linear = torch.nn.Linear(in_features=8, out_features=1)

            def forward(self, input_):
                x = self.conv_regular(input_)
                x = self.bn(x)
                x = torch.nn.functional.relu(x)
                x.transpose_(2, 3)
                x = self.max_pool2d(x)
                x = self.conv_transpose(x)
                x = self.conv_depthwise(x)
                x += torch.ones_like(x)
                x = self.adaptive_avg_pool(x)
                x = self.linear(x.flatten())
                return x

        model = ModelForMetatypeTesting()
        nncf_network = NNCFNetwork(model, [ModelInputInfo([1, 3, 300, 300])])
        ip_graph = nncf_network.get_insertion_point_graph()

        for node in ip_graph.nodes().values():
            if node[InsertionPointGraph.NODE_TYPE_NODE_ATTR] == InsertionPointGraphNodeType.OPERATOR:
                nncf_node_ref = node[InsertionPointGraph.REGULAR_NODE_REF_NODE_ATTR]
                scope_str = str(nncf_node_ref[NNCFGraph.OP_EXEC_CONTEXT_NODE_ATTR].input_agnostic)
                assert scope_str in ref_scope_vs_metatype_dict
                ref_metatype = ref_scope_vs_metatype_dict[scope_str]
                assert node[InsertionPointGraph.OPERATOR_METATYPE_NODE_ATTR] == ref_metatype
예제 #6
0
def get_all_node_names(model, input_sample_size, builder=None):
    if not builder:
        builder = GraphBuilder(
            create_dummy_forward_fn([
                ModelInputInfo(input_sample_size),
            ]))
    graph = builder.build_graph(model)
    return [
        node_name.split(' ', 1)[1] for node_name in graph.get_all_node_keys()
    ]
예제 #7
0
def test_output_quantization(_quantize_config):
    net = test_models.UNet()
    ctx = reset_context('orig')
    ctx = reset_context('quantized_graphs')
    input_shape = (1, 3, 360, 480)
    qnet = QuantizedNetwork(net, _quantize_config.quantizer, [ModelInputInfo(input_shape), ],
                            quantize_outputs=True)
    _ = qnet(torch.zeros(*input_shape))
    _ = qnet(torch.zeros(*input_shape))

    check_graph(ctx.graph, 'unet_qoutput.dot', _quantize_config.graph_dir)
예제 #8
0
def test_resnet18__with_ignore(_quantize_config):
    net = test_models.ResNet18()
    ctx = reset_context('orig')
    ctx = reset_context('quantized_graphs')
    input_shape = (1, 3, 32, 32)
    qnet = QuantizedNetwork(net, _quantize_config.quantizer, [ModelInputInfo(input_shape), ],
                            ignored_scopes=['ResNet/Sequential[layer3]'])
    _ = qnet(torch.zeros(*input_shape))
    _ = qnet(torch.zeros(*input_shape))

    check_graph(ctx.graph, 'resnet18_ignore.dot', _quantize_config.graph_dir)
예제 #9
0
def test_resnet18__with_not_qinput(_quantize_config):
    net = test_models.ResNet18()
    ctx = reset_context('orig')
    ctx = reset_context('quantized_graphs')
    input_shape = (1, 3, 32, 32)
    qnet = QuantizedNetwork(net, _quantize_config.quantizer, [ModelInputInfo(input_shape), ],
                            quantize_inputs=False)
    _ = qnet(torch.zeros(*input_shape))
    _ = qnet(torch.zeros(*input_shape))

    check_graph(ctx.graph, 'resnet18_no_qinput.dot', _quantize_config.graph_dir)
예제 #10
0
 def test_quantize_network(self, model_name, model_builder, forward_fn_, _quantize_config):
     net = model_builder()
     ctx = reset_context('orig')
     ctx = reset_context('quantized_graphs')
     qnet = QuantizedNetwork(net, _quantize_config.quantizer,
                             input_infos=[ModelInputInfo(forward_fn_.keywords["input_size_"]), ],
                             dummy_forward_fn=forward_fn_)
     qnet.to(self.device)
     forward_fn_(qnet)
     forward_fn_(qnet)
     check_graph(ctx.graph, model_name, _quantize_config.graph_dir)
예제 #11
0
def test_disable_shape_matching():
    class MatMulModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.dummy_param = torch.nn.Parameter(torch.ones([1]))

        def forward(self, inputs):
            half1, half2 = torch.chunk(inputs, 2, dim=2)
            return torch.bmm(half1, half2.transpose(1, 2))

    model = MatMulModel()

    input_shape_1 = (3, 32, 32)
    input_shape_2 = (4, 64, 64)

    qnet_no_shape = NNCFNetwork(
        deepcopy(model),
        input_infos=[
            ModelInputInfo(input_shape_1),
        ],
        scopes_without_shape_matching=['MatMulModel'])  # type: NNCFNetwork
    _ = qnet_no_shape(torch.zeros(*input_shape_1))
    graph_1 = deepcopy(qnet_no_shape.get_graph())

    _ = qnet_no_shape(torch.zeros(*input_shape_2))
    graph_2 = deepcopy(qnet_no_shape.get_graph())

    keys_1 = list(graph_1.get_all_node_keys())
    keys_2 = list(graph_2.get_all_node_keys())
    assert len(keys_1) == 2  # 1 input node + 1 operation node
    assert keys_1 == keys_2

    qnet = NNCFNetwork(model, input_infos=[
        ModelInputInfo(input_shape_1),
    ])  # type: NNCFNetwork
    _ = qnet(torch.zeros(*input_shape_1))
    _ = qnet(torch.zeros(*input_shape_2))
    # The second forward run should have led to an increase in registered node counts
    # since disable_shape_matching was False and the network was run with a different
    # shape of input tensor
    assert qnet.get_graph().get_nodes_count() > graph_1.get_nodes_count()
예제 #12
0
def test_custom_quantizable_subgraph_patterns(_quantize_config):
    net = test_models.SENet18()
    ctx = reset_context('orig')
    ctx = reset_context('quantized_graphs')
    input_shape = (1, 3, 32, 32)
    qnet = QuantizedNetwork(net, _quantize_config.quantizer, [ModelInputInfo(input_shape), ],
                            quantize_outputs=False,
                            quantizable_subgraph_patterns=(("sigmoid", "__mul__"),
                                                           ("__iadd__", "batch_norm")))
    _ = qnet(torch.zeros(*input_shape))
    _ = qnet(torch.zeros(*input_shape))

    check_graph(ctx.graph, 'senet_custom_patterns.dot', _quantize_config.graph_dir)
예제 #13
0
    def get_model_and_ctrl_with_applied_hw_config_quantization(model: torch.nn.Module, hw_config_dict: dict,
                                                               should_be_quantize_inputs: bool = True):
        nncf_config = get_quantization_config_without_range_init(model_size=1)
        nncf_config["compression"].update({"quantize_inputs": should_be_quantize_inputs})
        nncf_config["hw_config_type"] = "mock"

        net = NNCFNetwork(model, input_infos=[ModelInputInfo([1, 2, 1, 1])])
        hw_config = HWConfig.from_dict(hw_config_dict)
        qbuilder = QuantizationBuilder(nncf_config["compression"], should_init=False)
        qbuilder.quantizer_setup_type = QuantizerSetupType.PROPAGATION_BASED
        qbuilder.hw_config = hw_config
        net = qbuilder.apply_to(net)
        ctrl = net.commit_compression_changes()
        return net, ctrl
예제 #14
0
def test_custom_module_registering():
    model = TwoConvTestModelWithUserModule()
    nncf_model = NNCFNetwork(model, input_infos=[ModelInputInfo([1, 1, 4, 4])
                                                 ])  # type: NNCFNetwork

    from nncf.layers import UNWRAPPED_USER_MODULES
    assert ModuleOfUser in UNWRAPPED_USER_MODULES.registry_dict.values()

    # pylint: disable=protected-access
    assert isinstance(nncf_model.user_module, ModuleOfUser)
    assert isinstance(nncf_model.user_module, _NNCFModuleMixin)
    assert type(nncf_model.user_module).__name__ == "NNCFUserModuleOfUser"

    user_module_attrs = dir(nncf_model.user_module)
    for attr in dir(_NNCFModuleMixin):
        assert attr in user_module_attrs
def get_all_node_names(model,
                       input_sample_size,
                       graph_scope=None,
                       builder=None):
    if graph_scope is None:
        graph_scope = 'utils'
    reset_context(graph_scope)
    if not builder:
        builder = GraphBuilder(
            create_dummy_forward_fn([
                ModelInputInfo(input_sample_size),
            ]))
    graph = builder.build_graph(model, graph_scope)
    return [
        node_name.split(' ', 1)[1] for node_name in graph.get_all_node_keys()
    ]
def test_ambiguous_function():
    class Model(nn.Module):
        def __init__(self):
            super().__init__()
            self.layers = nn.ModuleList([
                nn.Conv2d(1, 1, 1),
                nn.Conv2d(1, 1, 1)
            ])

        def forward(self, x):
            for layer in self.layers:
                x = F.relu(layer(x))

    reset_context('orig')
    reset_context('quantized_graphs')
    mod = Model()
    input_info = ModelInputInfo((1, 1, 1, 1))
    QuantizedNetwork(mod, create_quantize_module,
                     input_infos=[input_info, ])
예제 #17
0
def create_test_quantization_env() -> QuantizationEnv:
    model = BasicConvTestModel()
    nncf_network = NNCFNetwork(model,
                               input_infos=[ModelInputInfo([1, 1, 4, 4])])
    hw_config_type = HWConfigType.VPU
    hw_config_path = HWConfig.get_path_to_hw_config(hw_config_type)
    hw_config = HWConfig.from_json(hw_config_path)
    setup = PropagationBasedQuantizerSetupGenerator(
        NNCFConfig(), nncf_network, hw_config=hw_config).generate_setup()
    experimental_builder = ExperimentalQuantizationBuilder(setup, {})
    experimental_builder.apply_to(nncf_network)
    # pylint:disable=line-too-long
    experimental_ctrl = nncf_network.commit_compression_changes(
    )  # type: ExperimentalQuantizationController
    data_loader = create_mock_dataloader({
        "sample_size": [1, 1, 4, 4],
    })
    constraints = HardwareQuantizationConstraints()
    for qid in experimental_ctrl.all_quantizations:
        qconf_constraint_list = []
        qconf = experimental_ctrl.all_quantizations[qid].get_current_config()
        bit_set = [8, 4, 2] if 'conv' in str(qid) else [8, 4]
        for bits in bit_set:
            adj_qconf = deepcopy(qconf)
            adj_qconf.bits = bits
            qconf_constraint_list.append(adj_qconf)
        constraints.add(qid, qconf_constraint_list)

    return QuantizationEnv(nncf_network,
                           experimental_ctrl,
                           constraints,
                           data_loader,
                           lambda *x: 0,
                           hw_config_type=HWConfigType.VPU,
                           params=QuantizationEnvParams(
                               compression_ratio=0.15,
                               eval_subset_ratio=1.0,
                               skip_constraint=False,
                               finetune=False,
                               bits=[2, 4, 8],
                               dump_init_precision_data=False))
def test_quantize_has_proper_is_weights_flag():
    class Model(nn.Module):
        def __init__(self, size=1):
            super().__init__()
            self.size = size
            self.conv = nn.Conv2d(size, size, size)

        def forward(self, x):
            return self.conv(x)

    model = Model()
    reset_context('orig')
    reset_context('quantized_graphs')

    input_info = ModelInputInfo((1, 1, 2, 2))
    quant_model = QuantizedNetwork(model, create_quantize_module, input_infos=[input_info, ],
                                   dummy_forward_fn=create_dummy_forward_fn([input_info, ]))
    for module in quant_model.modules():
        if isinstance(module, NNCFConv2d):
            for op in module.pre_ops.values():
                assert isinstance(op, (UpdateWeight, UpdateInputs))
                assert op.operand.is_weights is isinstance(op, UpdateWeight)
    for _, aq in quant_model.activation_quantizers.items():
        assert aq.is_weights is False
예제 #19
0
def test_ambiguous_function():
    class Model(nn.Module):
        def __init__(self):
            super().__init__()
            self.layers = nn.ModuleList(
                [nn.Conv2d(1, 1, 1), nn.Conv2d(1, 1, 1)])

        def forward(self, x):
            for layer in self.layers:
                x = F.relu(layer(x))

    mod = Model()
    input_info = ModelInputInfo([1, 1, 1, 1])

    graph_builder = GraphBuilder(custom_forward_fn=create_dummy_forward_fn([
        input_info,
    ]))
    graph = graph_builder.build_graph(mod)

    unique_op_exec_contexts = set()
    # pylint:disable=protected-access
    for _, node in graph._nx_graph.nodes.items():
        node_op_exec_context = node[NNCFGraph.OP_EXEC_CONTEXT_NODE_ATTR]
        assert node_op_exec_context not in unique_op_exec_contexts
def test_can_quantize_free_operators(mocker):
    class Model(nn.Module):
        def __init__(self):
            super().__init__()
            self.weight = nn.Parameter(torch.ones([1]))
            self.bias = nn.Parameter(torch.ones([1]))

        def forward(self, x):
            return F.linear(x, self.weight, self.bias)

    reset_context('orig')
    reset_context('quantized_graphs')
    mod = Model()
    input_shape = (1, 1, 1, 1)
    input_info = ModelInputInfo(input_shape)
    nncf_module = QuantizedNetwork(mod, create_quantize_module,
                                   input_infos=[input_info, ])
    quantizer_list = nncf_module.function_quantizers.values()
    assert len(quantizer_list) == 2
    for quantizer in quantizer_list:
        mocker.spy(quantizer, 'quantize')
    _ = nncf_module(torch.ones(input_shape))
    for quantizer in quantizer_list:
        assert quantizer.quantize.call_count == 1
예제 #21
0
def forward(arg1=None, arg2=None, arg3=None, arg4=None, arg5=TENSOR_DEFAULT):
    pass


class InputWrappingTestStruct:
    def __init__(self, input_infos, model_args, model_kwargs,
                 ref_wrapping_sequence):
        self.input_infos = input_infos
        self.model_args = model_args
        self.model_kwargs = model_kwargs
        self.ref_wrapping_sequence = ref_wrapping_sequence


INPUT_WRAPPING_TEST_CASES = [
    InputWrappingTestStruct(
        input_infos=[ModelInputInfo([1])],
        model_args=(TENSOR_1, ),
        model_kwargs={},
        ref_wrapping_sequence=[TENSOR_1],
    ),
    InputWrappingTestStruct(
        input_infos=[ModelInputInfo([1], keyword="arg2")],
        model_args=(),
        model_kwargs={"arg2": TENSOR_2},
        ref_wrapping_sequence=[TENSOR_2],
    ),
    InputWrappingTestStruct(
        input_infos=[
            ModelInputInfo([1]),
            ModelInputInfo([1]),
            ModelInputInfo([1], keyword="arg3"),
 def test_build_graph(self, model_name, model_builder, input_size):
     net = model_builder()
     graph_builder = GraphBuilder(create_dummy_forward_fn([ModelInputInfo(input_size), ]))
     graph = graph_builder.build_graph(net)
     check_graph(graph, model_name, 'original')
예제 #23
0
 def setup(self):
     self.compressed_model = NNCFNetwork(
         InsertionPointTestModel(),
         [ModelInputInfo([1, 1, 10, 10])])  # type: NNCFNetwork
예제 #24
0
        ]).output_edges
        output_shapes = [x.tensor_shape for x in output_edges]
        assert output_shapes == ref_output_shapes, "Failed for {}".format(
            node_id)


TEST_KEYWORD_1 = "keyword1"
TEST_KEYWORD_2 = "keyword2"
INPUT_INFO_CONFIG_VS_FORWARD_ARGS = [
    ({
        "sample_size": [2, 3, 300, 300],
        "type": "float",
        "filler": "zeros"
    }, [
        ModelInputInfo([2, 3, 300, 300],
                       type_str="float",
                       filler=ModelInputInfo.FILLER_TYPE_ZEROS)
    ]),
    ([{
        "sample_size": [1, 128],
        "type": "long",
        "filler": "ones"
    }, {
        "sample_size": [1, 128],
        "type": "long",
        "filler": "ones"
    }, {
        "sample_size": [1, 128],
        "type": "long",
        "filler": "zeros"
    }], [