示例#1
0
 def residual_block_quant(self,
                          quantizable_op_type,
                          skip_pattern=None,
                          for_ci=True):
     main = fluid.Program()
     startup = fluid.Program()
     with fluid.program_guard(main, startup):
         loss = quant_dequant_residual_block(2, skip_pattern)
         opt = fluid.optimizer.Adam(learning_rate=0.001)
         opt.minimize(loss)
     place = fluid.CPUPlace()
     graph = IrGraph(core.Graph(main.desc), for_test=False)
     add_quant_dequant_pass = AddQuantDequantPass(
         scope=fluid.global_scope(),
         place=place,
         skip_pattern=skip_pattern,
         quantizable_op_type=quantizable_op_type)
     add_quant_dequant_pass.apply(graph)
     if not for_ci:
         marked_nodes = set()
         for op in graph.all_op_nodes():
             if op.name().find('quant') > -1:
                 marked_nodes.add(op)
         graph.draw('.', 'add_quant_dequant_graph', marked_nodes)
     self.check_graph(graph, skip_pattern)
     program = graph.to_program()
     val_graph = IrGraph(core.Graph(program.desc), for_test=False)
     if not for_ci:
         val_marked_nodes = set()
         for op in val_graph.all_op_nodes():
             if op.name().find('quant') > -1:
                 val_marked_nodes.add(op)
         val_graph.draw('.', 'val_add_quant_dequant_graph', val_marked_nodes)
示例#2
0
 def linear_fc_quant(self,
                     activation_quant_type,
                     weight_quantize_type,
                     for_ci=True):
     main = fluid.Program()
     startup = fluid.Program()
     with fluid.program_guard(main, startup):
         loss = linear_fc(3)
         opt = fluid.optimizer.Adam(learning_rate=0.001)
         opt.minimize(loss)
     place = fluid.CPUPlace()
     graph = IrGraph(core.Graph(main.desc), for_test=False)
     transform_pass = QuantizationTransformPass(
         scope=fluid.global_scope(),
         place=place,
         activation_quantize_type=activation_quant_type,
         weight_quantize_type=weight_quantize_type)
     transform_pass.apply(graph)
     if not for_ci:
         marked_nodes = set()
         for op in graph.all_op_nodes():
             if op.name().find('quantize') > -1:
                 marked_nodes.add(op)
         graph.draw('.', 'quantize_fc_' + activation_quant_type,
                    marked_nodes)
     program = graph.to_program()
     self.check_program(program)
     val_graph = IrGraph(core.Graph(program.desc), for_test=False)
     if not for_ci:
         val_marked_nodes = set()
         for op in val_graph.all_op_nodes():
             if op.name().find('quantize') > -1:
                 val_marked_nodes.add(op)
         val_graph.draw('.', 'val_fc_' + activation_quant_type,
                        val_marked_nodes)
 def residual_block_quant(self, quant_type):
     main = fluid.Program()
     startup = fluid.Program()
     with fluid.program_guard(main, startup):
         loss = residual_block(2)
         opt = fluid.optimizer.Adam(learning_rate=0.001)
         opt.minimize(loss)
     place = fluid.CPUPlace()
     exe = fluid.Executor(place)
     graph = IrGraph(core.Graph(main.desc), for_test=False)
     transform_pass = QuantizationTransformPass(
         scope=fluid.global_scope(),
         place=place,
         activation_quantize_type=quant_type)
     transform_pass.apply(graph)
     marked_nodes = set()
     for op in graph.all_op_nodes():
         if op.name().find('quantize') > -1:
             marked_nodes.add(op)
     graph.draw('.', 'quantize_residual_' + quant_type, marked_nodes)
     program = graph.to_program()
     self.check_program(transform_pass, program)
     val_graph = IrGraph(core.Graph(program.desc), for_test=False)
     val_marked_nodes = set()
     for op in val_graph.all_op_nodes():
         if op.name().find('quantize') > -1:
             val_marked_nodes.add(op)
     val_graph.draw('.', 'val_residual_' + quant_type, val_marked_nodes)
示例#4
0
def quant_embedding(program, place, config, scope=None):
    """quantize lookup_table op parameters

    Args:
        program(fluid.Program): infer program
        scope(fluid.Scope): Scope records the mapping between variable names and variables, similar to brackets in programming languages. Usually users can use `fluid.global_scope() <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_ . When ``None`` will use `fluid.global_scope() <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_. Default : ``None``.
        place(fluid.CPUPlace or fluid.CUDAPlace): This parameter represents the executor run on which device.
        config(dict): config to quantize. The keys are 'params_name', 'quantize_type', \
                'quantize_bits', 'dtype', 'threshold'. \
                ``params_name`` is parameter name to quantize, must be set.
                ``quantize_type`` is  quantize type, supported types are ['abs_max'], default is "abs_max".
                ``quantize_bits`` supported bits are [8] and default is 8.
                ``dtype`` is quantize dtype, supported dtype are ['int8'], default is 'int8'.
                ``threshold`` is threshold to clip tensor before quant. When threshold is not set, \
                        tensor will not be clipped.

    Returns:
        None
    """
    assert isinstance(config, dict), "config must be dict"
    config = _merge_config(copy.deepcopy(default_config), config)
    scope = fluid.global_scope() if scope is None else scope

    graph = IrGraph(core.Graph(program.desc), for_test=True)
    if config['quantize_type'] == 'abs_max':
        _quant_embedding_abs_max(graph, scope, place, config)

    return graph.to_program()
示例#5
0
 def test_fuse_resenet_unit(self):
     place = paddle.CUDAPlace(0)
     program = paddle.static.Program()
     startup_program = paddle.static.Program()
     with paddle.static.amp.fp16_guard():
         with paddle.static.program_guard(program, startup_program):
             x = paddle.static.data("x", [1, 64, 64, 8])
             conv2d = paddle.nn.Conv2D(
                 8, 32, 1, bias_attr=False, data_format='NHWC')
             batch_norm = paddle.nn.BatchNorm(
                 32, act='relu', data_layout='NHWC')
             out = batch_norm(conv2d(x))
     graph = core.Graph(program.desc)
     core.get_pass("fuse_resnet_unit").apply(graph)
     after_program = paddle.fluid.framework.IrGraph(graph).to_program()
     params = paddle.static.amp.cast_model_to_fp16(program)
     after_params = paddle.static.amp.cast_model_to_fp16(after_program)
     exe = paddle.static.Executor(place)
     exe.run(startup_program)
     paddle.static.amp.cast_parameters_to_fp16(
         place, program, to_fp16_var_names=params)
     paddle.static.amp.cast_parameters_to_fp16(
         place, after_program, to_fp16_var_names=after_params)
     feed = {"x": np.random.randn(1, 64, 64, 8).astype("float16")}
     before_out = exe.run(program, feed=feed, fetch_list=[out.name])
     after_out = exe.run(after_program, feed=feed, fetch_list=[out.name])
     self.assertTrue(np.allclose(before_out[0], after_out[0], atol=5e-3))
示例#6
0
def transform_and_save_model(original_path, save_path, save_type):
    place = fluid.CPUPlace()
    exe = fluid.Executor(place)
    inference_scope = fluid.executor.global_scope()
    with fluid.scope_guard(inference_scope):
        if os.path.exists(os.path.join(original_path, '__model__')):
            [inference_program, feed_target_names, fetch_targets
             ] = fluid.io.load_inference_model(original_path, exe)
        else:
            [inference_program, feed_target_names, fetch_targets
             ] = fluid.io.load_inference_model(original_path, exe, 'model',
                                               'params')

        quantized_ops = set(test_args.quantized_ops.split(','))
        transform_to_mkldnn_int8_pass = Qat2Int8MkldnnPass(
            quantized_ops, _scope=inference_scope, _place=place, _core=core)

        graph = IrGraph(core.Graph(inference_program.desc), for_test=True)
        if save_type == 'FP32':
            graph = transform_to_mkldnn_int8_pass.apply_fp32(graph)
        elif save_type == 'INT8':
            graph = transform_to_mkldnn_int8_pass.apply(graph)
        inference_program = graph.to_program()
        with fluid.scope_guard(inference_scope):
            fluid.io.save_inference_model(save_path, feed_target_names,
                                          fetch_targets, exe,
                                          inference_program)
        print(
            "Success! Transformed QAT_{0} model can be found at {1}\n".format(
                save_type, save_path))
def quant_embedding(program, place, config, scope=None):
    """
    quant lookup_table op parameters
    Args:
        program(fluid.Program): infer program
        scope(fluid.Scope): the scope to store var, when is None will use fluid.global_scope()
        place(fluid.CPUPlace or fluid.CUDAPlace): place
        config(dict): config to quant. The keys are 'params_name', 'quantize_type', \
                'quantize_bits', 'dtype', 'threshold'. \
                'params_name': parameter name to quant, must be set.
                'quantize_type': quantize type, supported types are ['abs_max']. default is "abs_max".
                'quantize_bits': quantize bits, supported bits are [8].  default is 8.
                'dtype': quantize dtype, supported dtype are ['int8']. default is 'int8'.
                'threshold': threshold to clip tensor before quant. When threshold is not set, \
                        tensor will not be clipped.
    """
    assert isinstance(config, dict), "config must be dict"
    config = _merge_config(copy.deepcopy(default_config), config)
    scope = fluid.global_scope() if scope is None else scope

    graph = IrGraph(core.Graph(program.desc), for_test=True)
    if config['quantize_type'] == 'abs_max':
        _quant_embedding_abs_max(graph, scope, place, config)

    return graph.to_program()
    def test_dequantize_op_weights(self):
        program = fluid.Program()
        with fluid.program_guard(program):
            self.prepare_program_mul(program)
            graph = IrGraph(core.Graph(program.desc), for_test=True)

            for op in graph.all_op_nodes():
                if op.op().type() == "mul":
                    op_node = op
                    break

            qpass = Quant2Int8MkldnnPass(self.quantized_ops,
                                         _scope=self.scope,
                                         _place=self.place,
                                         _core=core,
                                         _debug=False)
            qpass._weight_scales["mul_output"] = self.mul_output_scale
            param = self.scope.var("mul_weights").get_tensor()
            param.set(self.variables_mul["mul_weights"], self.place)
            qpass._dequantize_op_weights(graph, op_node, "Y", "Out")

            assert np.allclose(
                self.scope.find_var("mul_weights").get_tensor(),
                [[127, 63.5, 42.3333, 31.75, 25.4],
                 [127, 63.5, 42.3333, 31.75, 25.4],
                 [127, 63.5, 42.3333, 31.75, 25.4]])

            param = self.scope.var("mul_weights").get_tensor()
            param.set(self.variables_mul["mul_weights_bad"], self.place)
            with self.assertRaises(ValueError):
                qpass._dequantize_op_weights(graph, op_node, "Y", "Out")
    def test_generate_layer_norm_fuse_pass(self):
        paddle.enable_static()
        program = paddle.static.Program()
        startup_program = paddle.static.Program()
        with paddle.static.program_guard(program, startup_program):
            x = paddle.static.data("x", [3, 64, 120], "float32")
            gamma = paddle.static.create_parameter(shape=[120],
                                                   dtype="float32",
                                                   is_bias=True)
            beta = paddle.static.create_parameter(shape=[120],
                                                  dtype="float32",
                                                  is_bias=True)

            x_sub_mean = x - paddle.mean(x, axis=-1, keepdim=True)
            std_dev = paddle.mean(x_sub_mean.pow(2), axis=-1, keepdim=True)
            lnorm = x_sub_mean - (std_dev + 1e-5).sqrt()
            out = lnorm * gamma + beta
        graph = core.Graph(program.desc)
        before_node_nums = len(graph.nodes())
        core.get_pass("generate_layer_norm_fuse_pass").apply(graph)
        after_node_nums = len(graph.nodes())
        self.assertEqual(after_node_nums, before_node_nums - 14)
        after_program = paddle.fluid.framework.IrGraph(graph).to_program()
        executor = paddle.static.Executor(paddle.CPUPlace())
        executor.run(startup_program)
        feed = {"x": np.random.random([3, 64, 120]).astype("float32")}
        before_out = executor.run(program, feed=feed, fetch_list=[out.name])
        after_out = executor.run(after_program,
                                 feed=feed,
                                 fetch_list=[out.name])
        self.assertTrue(np.allclose(before_out, after_out))
示例#10
0
def transform_and_save_int8_model(original_path,
                                  save_path,
                                  ops_to_quantize='',
                                  op_ids_to_skip='',
                                  debug=False,
                                  quant_model_filename='',
                                  quant_params_filename='',
                                  save_model_filename="__model__",
                                  save_params_filename=None):
    place = fluid.CPUPlace()
    exe = fluid.Executor(place)
    inference_scope = fluid.executor.global_scope()
    with fluid.scope_guard(inference_scope):
        if not quant_model_filename:
            if os.path.exists(os.path.join(original_path, '__model__')):
                [inference_program, feed_target_names, fetch_targets
                 ] = fluid.io.load_inference_model(original_path, exe)
            else:
                [inference_program, feed_target_names, fetch_targets
                 ] = fluid.io.load_inference_model(original_path, exe, 'model',
                                                   'params')
        else:
            [inference_program, feed_target_names, fetch_targets
             ] = fluid.io.load_inference_model(original_path, exe,
                                               quant_model_filename,
                                               quant_params_filename)

        ops_to_quantize_set = set()
        print(ops_to_quantize)
        if len(ops_to_quantize) > 0:
            ops_to_quantize_set = set(ops_to_quantize.split(','))

        op_ids_to_skip_set = set([-1])
        print(op_ids_to_skip)
        if len(op_ids_to_skip) > 0:
            op_ids_to_skip_set = set(map(int, op_ids_to_skip.split(',')))

        graph = IrGraph(core.Graph(inference_program.desc), for_test=True)
        if (debug):
            graph.draw('.', 'quant_orig', graph.all_op_nodes())
        transform_to_mkldnn_int8_pass = Quant2Int8MkldnnPass(
            ops_to_quantize_set,
            _op_ids_to_skip=op_ids_to_skip_set,
            _scope=inference_scope,
            _place=place,
            _core=core,
            _debug=debug)
        graph = transform_to_mkldnn_int8_pass.apply(graph)
        inference_program = graph.to_program()
        with fluid.scope_guard(inference_scope):
            fluid.io.save_inference_model(save_path,
                                          feed_target_names,
                                          fetch_targets,
                                          exe,
                                          inference_program,
                                          model_filename=save_model_filename,
                                          params_filename=save_params_filename)
        print(
            "Success! INT8 model obtained from the Quant model can be found at {}\n"
            .format(save_path))
示例#11
0
    def _apply_ir_passes(self):
        graph = core.Graph(self.main_program.desc)
        graph.set_not_owned("__param_scope__", fluid.global_scope())

        if not isinstance(self.pass_names, list):
            self.pass_names = [self.pass_names]

        pass_builder = core.PassBuilder()
        for name in self.pass_names:
            ir_pass = pass_builder.append_pass(name)
            # Set attr for pass
            if self.pass_attrs.get(name, None) is not None:
                attrs = self.pass_attrs[name]
                for key in attrs:
                    ir_pass.set(key, attrs[key])

        trans_pass = pass_builder.append_pass("graph_to_program_pass")
        opt_program = fluid.Program()
        trans_pass.set_not_owned("program", opt_program.desc)
        for p in pass_builder.all_passes():
            p.apply(graph)
        opt_program.blocks = [
            Block(opt_program, i)
            for i in six.moves.range(opt_program.desc.num_blocks())
        ]
        opt_program._sync_with_cpp()
        return opt_program
    def test_dequantize_op_weights(self):
        program = fluid.Program()
        with fluid.program_guard(program):
            self.prepare_program_mul(program)
            graph = IrGraph(core.Graph(program.desc), for_test=True)

            op_node = ""
            for op in graph.all_op_nodes():
                if op.op().type() == self.op_name():
                    op_node = op
                    break
            assert op_node != "", "op of type %s not found" % self.op_name()

            qpass = Quant2Int8MkldnnPass(self.quantized_ops,
                                         _scope=self.scope,
                                         _place=self.place,
                                         _core=core,
                                         _debug=False)
            qpass._weight_thresholds["mul_output"] = self.mul_output_scale
            param = self.scope.var("mul_weights").get_tensor()
            param.set(self.variables_mul["mul_weights"], self.place)
            qpass._dequantize_op_weights(graph, op_node, "Y", "Out")

            assert np.allclose(
                self.scope.find_var("mul_weights").get_tensor(),
                [[1. / 127., 2. / 127., 3. / 127., 4. / 127., 5. / 127.],
                 [1. / 127., 2. / 127., 3. / 127., 4. / 127., 5. / 127.],
                 [1. / 127., 2. / 127., 3. / 127., 4. / 127., 5. / 127.]])

            param = self.scope.var("mul_weights").get_tensor()
            param.set(self.variables_mul["mul_weights_bad"], self.place)
            with self.assertRaises(ValueError):
                qpass._dequantize_op_weights(graph, op_node, "Y", "Out")
        def test_quant_update_activation(self):
            program = fluid.Program()
            with fluid.program_guard(program):
                self.prepare_program(program)
                graph = IrGraph(core.Graph(program.desc), for_test=True)
                quant2_int8_mkldnn_pass = Quant2Int8MkldnnPass(
                    self.quantized_ops,
                    _scope=self.scope,
                    _place=self.place,
                    _core=core,
                    _debug=False)

                input_scale_tensor = quant2_int8_mkldnn_pass._convert_scale2tensor(
                    np.array(self.scale).astype(np.float64))
                output_scale_tensor = quant2_int8_mkldnn_pass._convert_scale2tensor(
                    np.array(1. / self.scale * self.scale).astype(np.float64))
                var_scale = {
                    "input": (False, input_scale_tensor),
                    "filter": (False, input_scale_tensor),
                    "conv_output": (False, output_scale_tensor),
                }
                if core.avx_supported():
                    quant2_int8_mkldnn_pass._var_quant_scales = var_scale
                    graph = quant2_int8_mkldnn_pass._propagate_scales(graph)
                    graph = quant2_int8_mkldnn_pass._quantize_fp32_graph(graph)
                    self.check_graph_after_pass(graph)
 def check_multi_add_to_sum(self, pass_type):
     program = paddle.static.Program()
     startup_program = paddle.static.Program()
     with paddle.static.program_guard(program, startup_program):
         x = paddle.static.data("x", [10, 10, 10], "float32")
         y = paddle.static.data("y", [10, 10, 10], "float32")
         z = paddle.static.data("z", [10, 10, 10], "float32")
         add_1 = paddle.add(paddle.add(x, y), z)
         matmul_1 = paddle.matmul(add_1, z)
         add_tmp = paddle.add(x, y)
         add_2 = paddle.add(add_tmp, z)
         matmul_2 = paddle.matmul(add_2, add_tmp)
         out = paddle.add(matmul_1, matmul_2)
     graph = core.Graph(program.desc)
     before_node_nums = len(graph.nodes())
     core.get_pass(pass_type).apply(graph)
     after_node_nums = len(graph.nodes())
     self.assertEqual(after_node_nums, before_node_nums - 2)
     after_program = paddle.fluid.framework.IrGraph(graph).to_program()
     executor = paddle.static.Executor(paddle.CPUPlace())
     executor.run(startup_program)
     feed = {
         "x": np.random.random([10, 10, 10]).astype("float32"),
         "y": np.random.random([10, 10, 10]).astype("float32"),
         "z": np.random.random([10, 10, 10]).astype("float32")
     }
     before_out = executor.run(program, feed=feed, fetch_list=[out.name])
     after_out = executor.run(after_program,
                              feed=feed,
                              fetch_list=[out.name])
     self.assertTrue(np.allclose(before_out, after_out))
 def test_generate_combine_mul_v1(self):
     paddle.enable_static()
     program = paddle.static.Program()
     startup_program = paddle.static.Program()
     with paddle.static.program_guard(program, startup_program):
         x = paddle.static.data("x", [16, 32])
         y = paddle.static.data("y", [32, 12])
         z = paddle.static.data("z", [32, 48])
         out1 = paddle.matmul(x, y)
         out2 = paddle.matmul(x, z)
     graph = core.Graph(program.desc)
     before_node_nums = len(graph.nodes())
     core.get_pass("generate_combine_mul_v1").apply(graph)
     after_node_nums = len(graph.nodes())
     self.assertEqual(after_node_nums, before_node_nums + 4)
     after_program = paddle.fluid.framework.IrGraph(graph).to_program()
     executor = paddle.static.Executor(paddle.CPUPlace())
     executor.run(startup_program)
     feed = {
         "x": np.random.random([16, 32]).astype("float32"),
         "y": np.random.random([32, 12]).astype("float32"),
         "z": np.random.random([32, 48]).astype("float32")
     }
     before_out1, before_out2 = executor.run(
         program, feed=feed, fetch_list=[out1.name, out2.name])
     after_out1, after_out2 = executor.run(
         after_program, feed=feed, fetch_list=[out1.name, out2.name])
     self.assertTrue(np.allclose(before_out1, after_out1))
     self.assertTrue(np.allclose(before_out2, after_out2))
示例#16
0
def convert(program, place, config=None, scope=None, save_int8=False):
    """
    convert quantized and well-trained ``program`` to final  quantized ``program`` that can be used to  save ``inference model``.
    
    Args:
        program(fluid.Program): quantized and well-trained ``test program``.
        place(fluid.CPUPlace or fluid.CUDAPlace): This parameter represents the executor run on which device.
        config(dict, optional): configs for convert. if set None, will use default config. 
            It must be same with config that used in 'quant_aware'. Default: None.
        scope(fluid.Scope, optional):  Scope records the mapping between variable names and variables, 
            similar to brackets in programming languages. Usually users can use 
            `fluid.global_scope <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_.              When ``None`` will use `fluid.global_scope() <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_ . Default: ``None``.
        save_int8: Whether to return ``program`` which model parameters' dtype is ``int8``. 
            This parameter can only be used to get model size. Default: ``False``.

    Returns:
        Tuple : freezed program which can be used for inference.
        when ``save_int8`` is False, return ``freezed_program(fluid.Program)``.
        when ``save_int8`` is True, return ``freezed_program(fluid.Program)`` and ``freezed_program_int8(fluid.Program)``
    """
    scope = fluid.global_scope() if not scope else scope

    if config is None:
        config = _quant_config_default
    else:
        assert isinstance(config, dict), "config must be dict"
        config = _parse_configs(config)
    _logger.info("convert config {}".format(config))

    test_graph = IrGraph(core.Graph(program.desc), for_test=True)
    support_op_types = []
    for op in config['quantize_op_types']:
        if op in QuantizationFreezePass._supported_quantizable_op_type:
            support_op_types.append(op)

    # Freeze the graph after training by adjusting the quantize
    # operators' order for the inference.
    freeze_pass = QuantizationFreezePass(
        scope=scope,
        place=place,
        weight_bits=config['weight_bits'],
        activation_bits=config['activation_bits'],
        weight_quantize_type=config['weight_quantize_type'],
        quantizable_op_type=support_op_types)
    freeze_pass.apply(test_graph)
    freezed_program = test_graph.to_program()

    if save_int8:
        convert_int8_pass = ConvertToInt8Pass(
            scope=fluid.global_scope(),
            place=place,
            quantizable_op_type=support_op_types)
        convert_int8_pass.apply(test_graph)
        freezed_program_int8 = test_graph.to_program()
        return freezed_program, freezed_program_int8
    else:
        return freezed_program
示例#17
0
    def test_get_valid_program_error(self):
        # case 1: CompiledProgram no program
        graph = core.Graph(core.ProgramDesc())
        compiled_program = fluid.CompiledProgram(graph)
        with self.assertRaises(TypeError):
            fluid.io._get_valid_program(compiled_program)

        # case 2: main_program type error
        with self.assertRaises(TypeError):
            fluid.io._get_valid_program("program")
示例#18
0
    def get_op_number(self, prog):

        graph = IrGraph(core.Graph(prog.desc), for_test=False)
        quant_op_nums = 0
        op_nums = 0
        for op in graph.all_op_nodes():
            if op.name() in ['conv2d', 'depthwise_conv2d', 'mul']:
                op_nums += 1
            elif 'fake_' in op.name():
                quant_op_nums += 1
        return op_nums, quant_op_nums
 def test_exception(self):
     paddle.enable_static()
     program = paddle.static.Program()
     startup_program = paddle.static.Program()
     with paddle.static.program_guard(program, startup_program):
         x = paddle.static.data("x", [10, 10], "float32")
         y = paddle.static.data("y", [10, 10], "float32")
         paddle.add(x, y)
     graph = core.Graph(program.desc)
     with self.assertRaises(NotImplementedError):
         core.get_pass("unimplemented_operand_exception").apply(graph)
     with self.assertRaises(NotImplementedError):
         core.get_pass("unimplemented_operation_exception").apply(graph)
 def test_quant_update_activation(self):
     program = fluid.Program()
     with fluid.program_guard(program):
         self.prepare_program(program)
         graph = IrGraph(core.Graph(program.desc), for_test=True)
         graph = self.remove_fuse_activation_attribute(graph)
         self.check_graph_before_pass(graph)
         quant2_int8_mkldnn_pass = Quant2Int8MkldnnPass(self.quantized_ops,
                                                        _scope=self.scope,
                                                        _place=self.place,
                                                        _core=core,
                                                        _debug=False)
         graph = quant2_int8_mkldnn_pass._update_activations(graph)
         self.check_graph_after_pass(graph)
示例#21
0
def quant_embedding(program, place, config=None, scope=None):
    """quantize lookup_table op parameters

    Args:
        program(paddle.static.Program): infer program
        scope(paddle.static.Scope, optional): Scope records the mapping between variable names and variables, similar to brackets in programming languages. Usually users can use `paddle.static.global_scope() <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_ . When ``None`` will use `paddle.static.global_scope() <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_. Default : ``None``.
        place(paddle.CPUPlace or paddle.CUDAPlace): This parameter represents the executor run on which device.
        config(dict, optional): config to quantize. The keys are 'quantize_op_types'. For op in quantize_op_types, you can define 'quantize_type', \
                'quantize_bits', 'dtype', 'threshold'. \
                ``quantize_type`` is  quantize type, supported types are ['abs_max'], default is "abs_max".
                ``quantize_bits`` supported bits are [8] and default is 8.
                ``dtype`` is quantize dtype, supported dtype are ['int8'], default is 'int8'.
                ``threshold`` is threshold to clip tensor before quant. When threshold is not set, \
                        tensor will not be clipped.

    Returns:
        None
    """
    config = config or {}
    config = _merge_config(copy.deepcopy(_default_config), config)
    scope = paddle.static.global_scope() if scope is None else scope

    graph = IrGraph(core.Graph(program.desc), for_test=True)
    quantize_params_map = {}
    all_op = graph.all_op_nodes()
    for op in all_op:
        if op.inputs == [] and op.outputs == []:
            continue
        op_type = op.name()
        if op_type in config['quantize_op_types']:
            weight_name = op.input('W')[0]
            if weight_name in quantize_params_map.values():
                continue
            embedding_node = graph._find_node_by_name(op.inputs,
                                                      op.input('W')[0])
            for op_node in embedding_node.outputs:
                if op_node.name() == 'fused_embedding_seq_pool':
                    _split_embedding_seq_pool(graph, op_node)
            if config[op_type]['quantize_type'] == 'abs_max':
                _quant_embedding_abs_max(graph, scope, place, config[op_type],
                                         weight_name, embedding_node)
            elif config[op_type]['quantize_type'] == 'log':
                _quant_embedding_log(graph, scope, place, config[op_type],
                                     weight_name, embedding_node)
            quantize_params_map[weight_name] = _get_quant_var_name(weight_name)
    for op in all_op:
        if op.name() == 'fused_embedding_seq_pool':
            graph.safe_remove_nodes(op)

    return graph.to_program()
示例#22
0
    def _predict(self, test_reader=None, model_path=None):
        place = fluid.CPUPlace()
        exe = fluid.Executor(place)
        inference_scope = fluid.executor.global_scope()
        with fluid.scope_guard(inference_scope):
            if os.path.exists(os.path.join(model_path, '__model__')):
                [inference_program, feed_target_names, fetch_targets
                 ] = fluid.io.load_inference_model(model_path, exe)
            else:
                [inference_program, feed_target_names, fetch_targets
                 ] = fluid.io.load_inference_model(model_path, exe, 'model',
                                                   'params')

            use_mkldnn = fluid.core.globals()["FLAGS_use_mkldnn"]
            if (use_mkldnn):
                graph = IrGraph(core.Graph(inference_program.desc),
                                for_test=True)
                graph = self._transform_depthwise_conv(graph)
                inference_program = graph.to_program()

            dshape = [3, 224, 224]
            top1 = 0.0
            top5 = 0.0
            total_samples = 0
            for batch_id, data in enumerate(test_reader()):
                if six.PY2:
                    images = map(lambda x: x[0].reshape(dshape), data)
                if six.PY3:
                    images = list(map(lambda x: x[0].reshape(dshape), data))
                images = np.array(images).astype('float32')
                labels = np.array([x[1] for x in data]).astype("int64")
                labels = labels.reshape([-1, 1])
                fluid.core.set_num_threads(int(os.environ['CPU_NUM_THREADS']))
                out = exe.run(inference_program,
                              feed={
                                  feed_target_names[0]: images,
                                  feed_target_names[1]: labels
                              },
                              fetch_list=fetch_targets)
                fluid.core.set_num_threads(1)
                top1 += np.sum(out[1]) * len(data)
                top5 += np.sum(out[2]) * len(data)
                total_samples += len(data)
                if (batch_id + 1) % 100 == 0:
                    _logger.info(
                        '{} images have been predicted'.format(total_samples))
            return top1 / total_samples, top5 / total_samples
示例#23
0
 def init_dist_attr_for_graph(self):
     assert self._is_initialized_for_program, \
         "The program must be initialized before initializing the distributed attributes for its graph."
     if self._is_initialized_for_graph:
         return
     # Convert program to graph
     self._serial_graph = framework.IrGraph(
         core.Graph(self._serial_program.desc))
     all_nodes = self._serial_graph.all_nodes()
     self.order_nodes_by_program_order()
     for node in self.serial_ordered_nodes:
         if node.is_var() and node.var() is not None:
             dist_tensor = None
             tensor_id = node.node.original_desc_id()
             for cur_tensor_id, cur_dist_tensor in self._dist_tensors_for_program.items(
             ):
                 if tensor_id == cur_tensor_id \
                     or tensor_id == cur_dist_tensor.serial_tensor.desc.original_id():
                     dist_tensor = cur_dist_tensor
                     self._node_id_to_tensor_id[node.id()] = cur_tensor_id
             assert dist_tensor is not None, \
                 "Tensor must have a distributed tensor after the initialization for program."
             serial_tensor_node_id = node.id()
             new_dist_tensor = DistributedTensor(dist_tensor.serial_tensor,
                                                 dist_tensor.dist_attr)
             self._dist_tensors_for_graph[
                 serial_tensor_node_id] = new_dist_tensor
         if node.is_op() and node.op() is not None:
             dist_op = None
             op_id = node.node.original_desc_id()
             for cur_op_id, cur_dist_op in self._dist_ops_for_program.items(
             ):
                 if op_id == cur_op_id \
                     or op_id == cur_dist_op.serial_op.desc.original_id():
                     dist_op = cur_dist_op
                     self._node_id_to_op_id[node.id()] = cur_op_id
             assert dist_op is not None, \
                 "Operator must have a distributed operator after the initialization for program."
             serial_op_node_id = node.id()
             new_dist_op = DistributedOperator(dist_op.serial_op,
                                               dist_op.dist_attr)
             self._dist_ops_for_graph[serial_op_node_id] = new_dist_op
     self._is_initialized_for_graph = True
示例#24
0
 def test_graph_functions(self):
     main = fluid.Program()
     startup = fluid.Program()
     with fluid.program_guard(main, startup):
         loss = residual_block(2)
         opt = fluid.optimizer.Adam(learning_rate=0.001)
         opt.minimize(loss)
     graph = IrGraph(core.Graph(main.desc), for_test=False)
     marked_nodes = set()
     for op in graph.all_op_nodes():
         if op.name().find('conv2d') > -1:
             marked_nodes.add(op)
     graph.draw('.', 'residual', marked_nodes)
     self.assertFalse(graph.has_circle())
     self.assertEqual(graph.graph_num(), 1)
     nodes = graph.topology_sort()
     self.assertEqual(len(nodes), len(graph.all_op_nodes()))
     nodes_map = graph.build_adjacency_list()
     self.assertEqual(len(nodes_map), len(graph.all_op_nodes()))
     nodes_num = len(graph.all_nodes())
     graph.safe_remove_nodes(marked_nodes)
     self.assertEqual(len(graph.all_nodes()), nodes_num - len(marked_nodes))
示例#25
0
def generate_dot_for_model(model_path, save_graph_dir, save_graph_name):
    place = fluid.CPUPlace()
    exe = fluid.Executor(place)
    inference_scope = fluid.executor.global_scope()
    with fluid.scope_guard(inference_scope):
        if os.path.exists(os.path.join(model_path, '__model__')):
            [inference_program, feed_target_names,
             fetch_targets] = fluid.io.load_inference_model(model_path, exe)
        else:
            [inference_program, feed_target_names,
             fetch_targets] = fluid.io.load_inference_model(model_path, exe,
                                                            'model', 'params')
        graph = IrGraph(core.Graph(inference_program.desc), for_test=True)
        if not os.path.exists(save_graph_dir):
            os.makedirs(save_graph_dir)
        model_name = os.path.basename(os.path.normpath(save_graph_dir))
        if save_graph_name is '':
            save_graph_name = model_name
        graph.draw(save_graph_dir, save_graph_name, graph.all_op_nodes())
        print(
            "Success! Generated dot and pdf files for {0} model, that can be found at {1} named {2}.\n".
            format(model_name, save_graph_dir, save_graph_name))
示例#26
0
    def build_graph_with_sub_graph(self):
        def linear_fc(num):
            data = fluid.layers.data(name='image',
                                     shape=[1, 32, 32],
                                     dtype='float32')
            label = fluid.layers.data(name='label', shape=[1], dtype='int64')
            hidden = data
            for _ in six.moves.xrange(num):
                hidden = fluid.layers.fc(hidden, size=128, act='relu')
            loss = fluid.layers.cross_entropy(input=hidden, label=label)
            loss = fluid.layers.mean(loss)
            return loss

        main_program = Program()
        startup_program = Program()

        def true_func():
            return linear_fc(3)

        def false_func():
            return linear_fc(5)

        with program_guard(main_program, startup_program):
            x = layers.fill_constant(shape=[1], dtype='float32', value=0.1)
            y = layers.fill_constant(shape=[1], dtype='float32', value=0.23)
            pred = layers.less_than(y, x)
            out = layers.cond(pred, true_func, false_func)

        core_graph = core.Graph(main_program.desc)
        # We should create graph for test, otherwise it will throw a
        # error that it cannot find the node of "STEP_COUNTER"
        graph = IrGraph(core_graph, for_test=True)
        sub_graph = graph.get_sub_graph(0)
        all_sub_graphs = graph.all_sub_graphs(
            for_test=True)  # same reason for subgraph
        # Should return graph and sub_graphs at the same time. If only return sub_graph, the graph will
        # be destructed and the sub_graphs will be empty.
        return graph, all_sub_graphs
 def check_generate_simplify_inference(self, pass_type):
     paddle.enable_static()
     program = paddle.static.Program()
     startup_program = paddle.static.Program()
     with paddle.static.program_guard(program, startup_program):
         x = paddle.static.data("x", [10, 16, 16], "float32")
         x1 = paddle.transpose(paddle.transpose(x, [0, 2, 1]), [0, 2, 1])
         tmp = paddle.transpose(x, [0, 2, 1])
         x2 = paddle.transpose(tmp, [0, 2, 1])
         out = paddle.add(x1, paddle.matmul(x2, tmp))
     graph = core.Graph(program.desc)
     before_node_nums = len(graph.nodes())
     core.get_pass(pass_type).apply(graph)
     after_node_nums = len(graph.nodes())
     self.assertEqual(after_node_nums, before_node_nums - 6)
     after_program = paddle.fluid.framework.IrGraph(graph).to_program()
     executor = paddle.static.Executor(paddle.CPUPlace())
     executor.run(startup_program)
     feed = {"x": np.random.random([10, 16, 16]).astype("float32")}
     before_out = executor.run(program, feed=feed, fetch_list=[out.name])
     after_out = executor.run(after_program,
                              feed=feed,
                              fetch_list=[out.name])
     self.assertTrue(np.allclose(before_out, after_out))
示例#28
0
    def _predict(self,
                 test_reader=None,
                 model_path=None,
                 batch_size=1,
                 batch_num=1,
                 skip_batch_num=0,
                 transform_to_int8=False):
        place = fluid.CPUPlace()
        exe = fluid.Executor(place)
        inference_scope = fluid.executor.global_scope()
        with fluid.scope_guard(inference_scope):
            if os.path.exists(os.path.join(model_path, '__model__')):
                [inference_program, feed_target_names, fetch_targets
                 ] = fluid.io.load_inference_model(model_path, exe)
            else:
                [inference_program, feed_target_names, fetch_targets
                 ] = fluid.io.load_inference_model(model_path, exe, 'model',
                                                   'params')

            graph = IrGraph(core.Graph(inference_program.desc), for_test=True)
            if (self._debug):
                graph.draw('.', 'qat_orig', graph.all_op_nodes())
            if (transform_to_int8):
                transform_to_mkldnn_int8_pass = Qat2Int8MkldnnPass(
                    self._quantized_ops,
                    _scope=inference_scope,
                    _place=place,
                    _core=core,
                    _debug=self._debug)
                graph = transform_to_mkldnn_int8_pass.apply(graph)

            inference_program = graph.to_program()

            total_correct = 0
            total_samples = 0
            batch_times = []
            ppses = []  # predictions per second
            iters = 0
            infer_start_time = time.time()
            for data in test_reader():
                if batch_num > 0 and iters >= batch_num:
                    break
                if iters == skip_batch_num:
                    total_samples = 0
                    infer_start_time = time.time()
                input0 = np.array([x[0] for x in data]).astype('int64')
                input1 = np.array([x[1] for x in data]).astype('int64')
                labels = np.array([x[2] for x in data]).astype('int64')

                start = time.time()
                out = exe.run(inference_program,
                              feed={
                                  feed_target_names[0]: input0,
                                  feed_target_names[1]: input1
                              },
                              fetch_list=fetch_targets)
                batch_time = (time.time() - start) * 1000  # in miliseconds
                batch_times.append(batch_time)
                batch_correct = self._get_batch_correct(out, labels)
                batch_len = len(data)
                total_samples += batch_len
                total_correct += batch_correct
                batch_acc = float(batch_correct) / float(batch_len)
                pps = batch_len / batch_time * 1000
                ppses.append(pps)
                latency = batch_time / batch_len
                iters += 1
                appx = ' (warm-up)' if iters <= skip_batch_num else ''
                _logger.info(
                    'batch {0}{4}, acc: {1:.4f}, latency: {2:.4f} ms, predictions per sec: {3:.2f}'
                    .format(iters, batch_acc, latency, pps, appx))

            # Postprocess benchmark data
            infer_total_time = time.time() - infer_start_time
            batch_latencies = batch_times[skip_batch_num:]
            batch_latency_avg = np.average(batch_latencies)
            latency_avg = batch_latency_avg / batch_size
            ppses = ppses[skip_batch_num:]
            pps_avg = np.average(ppses)
            acc_avg = float(np.sum(total_correct)) / float(total_samples)
            _logger.info(
                'Total inference run time: {:.2f} s'.format(infer_total_time))

            return acc_avg, pps_avg, latency_avg
示例#29
0
    def test_qat_acc(self):
        def _build_static_lenet(main, startup, is_test=False, seed=1000):
            with fluid.unique_name.guard():
                with fluid.program_guard(main, startup):
                    main.random_seed = seed
                    startup.random_seed = seed
                    img = fluid.layers.data(
                        name='image', shape=[1, 28, 28], dtype='float32')
                    label = fluid.layers.data(
                        name='label', shape=[1], dtype='int64')
                    prediction = StaticLenet(img)
                    if not is_test:
                        loss = fluid.layers.cross_entropy(
                            input=prediction, label=label)
                        avg_loss = fluid.layers.mean(loss)
                    else:
                        avg_loss = prediction
            return img, label, avg_loss

        reader = paddle.batch(
            paddle.dataset.mnist.test(), batch_size=32, drop_last=True)
        weight_quantize_type = 'abs_max'
        activation_quant_type = 'moving_average_abs_max'
        param_init_map = {}
        seed = 1000
        lr = 0.001

        # imperative train
        _logger.info(
            "--------------------------dynamic graph qat--------------------------"
        )
        imperative_qat = ImperativeQuantAware(
            weight_quantize_type=weight_quantize_type,
            activation_quantize_type=activation_quant_type,
            quantizable_layer_type=[
                'Conv2D', 'Linear', 'ReLU', 'LeakyReLU', 'ReLU6', 'Tanh',
                'Swish'
            ])

        with fluid.dygraph.guard():
            np.random.seed(seed)
            fluid.default_main_program().random_seed = seed
            fluid.default_startup_program().random_seed = seed
            lenet = ImperativeLenet()
            fixed_state = {}
            for name, param in lenet.named_parameters():
                p_shape = param.numpy().shape
                p_value = param.numpy()
                if name.endswith("bias"):
                    value = np.zeros_like(p_value).astype('float32')
                else:
                    value = np.random.normal(
                        loc=0.0, scale=0.01, size=np.product(p_shape)).reshape(
                            p_shape).astype('float32')
                fixed_state[name] = value
                param_init_map[param.name] = value
            lenet.set_dict(fixed_state)

            imperative_qat.quantize(lenet)
            adam = AdamOptimizer(
                learning_rate=lr, parameter_list=lenet.parameters())
            dynamic_loss_rec = []
            lenet.train()
            for batch_id, data in enumerate(reader()):
                x_data = np.array([x[0].reshape(1, 28, 28)
                                   for x in data]).astype('float32')
                y_data = np.array(
                    [x[1] for x in data]).astype('int64').reshape(-1, 1)

                img = fluid.dygraph.to_variable(x_data)
                label = fluid.dygraph.to_variable(y_data)

                out = lenet(img)
                loss = fluid.layers.cross_entropy(out, label)
                avg_loss = fluid.layers.mean(loss)
                avg_loss.backward()
                adam.minimize(avg_loss)
                lenet.clear_gradients()
                dynamic_loss_rec.append(avg_loss.numpy()[0])
                if batch_id % 100 == 0:
                    _logger.info('{}: {}'.format('loss', avg_loss.numpy()))
                if batch_id > 500:
                    break
            lenet.eval()
        paddle.jit.save(
            layer=lenet,
            path="./dynamic_mnist/model",
            input_spec=[
                paddle.static.InputSpec(
                    shape=[None, 1, 28, 28], dtype='float32')
            ])

        # static graph train
        _logger.info(
            "--------------------------static graph qat--------------------------"
        )
        static_loss_rec = []
        if core.is_compiled_with_cuda():
            place = core.CUDAPlace(0)
        else:
            place = core.CPUPlace()
        exe = fluid.Executor(place)

        main = fluid.Program()
        infer = fluid.Program()
        startup = fluid.Program()
        static_img, static_label, static_loss = _build_static_lenet(
            main, startup, False, seed)
        infer_img, _, infer_pre = _build_static_lenet(infer, startup, True,
                                                      seed)
        with fluid.unique_name.guard():
            with fluid.program_guard(main, startup):
                opt = AdamOptimizer(learning_rate=lr)
                opt.minimize(static_loss)

        scope = core.Scope()
        with fluid.scope_guard(scope):
            exe.run(startup)
        for param in main.all_parameters():
            param_tensor = scope.var(param.name).get_tensor()
            param_tensor.set(param_init_map[param.name], place)

        main_graph = IrGraph(core.Graph(main.desc), for_test=False)
        infer_graph = IrGraph(core.Graph(infer.desc), for_test=True)
        transform_pass = QuantizationTransformPass(
            scope=scope,
            place=place,
            activation_quantize_type=activation_quant_type,
            weight_quantize_type=weight_quantize_type,
            quantizable_op_type=['conv2d', 'depthwise_conv2d', 'mul'])
        add_quant_dequant_pass = AddQuantDequantPass(
            scope=scope,
            place=place,
            quantizable_op_type=[
                'relu', 'leaky_relu', 'relu6', 'tanh', 'swish'
            ])
        transform_pass.apply(main_graph)
        transform_pass.apply(infer_graph)
        add_quant_dequant_pass.apply(main_graph)
        add_quant_dequant_pass.apply(infer_graph)
        build_strategy = fluid.BuildStrategy()
        build_strategy.fuse_all_reduce_ops = False
        binary = fluid.CompiledProgram(main_graph.graph).with_data_parallel(
            loss_name=static_loss.name, build_strategy=build_strategy)

        feeder = fluid.DataFeeder(
            feed_list=[static_img, static_label], place=place)
        with fluid.scope_guard(scope):
            for batch_id, data in enumerate(reader()):
                loss_v, = exe.run(binary,
                                  feed=feeder.feed(data),
                                  fetch_list=[static_loss])
                static_loss_rec.append(loss_v[0])
                if batch_id % 100 == 0:
                    _logger.info('{}: {}'.format('loss', loss_v))

        save_program = infer_graph.to_program()
        with fluid.scope_guard(scope):
            fluid.io.save_inference_model("./static_mnist", [infer_img.name],
                                          [infer_pre], exe, save_program)
        rtol = 1e-08
        atol = 1e-10
        for i, (loss_d,
                loss_s) in enumerate(zip(dynamic_loss_rec, static_loss_rec)):
            diff = np.abs(loss_d - loss_s)
            if diff > (atol + rtol * np.abs(loss_s)):
                _logger.info(
                    "diff({}) at {}, dynamic loss = {}, static loss = {}".
                    format(diff, i, loss_d, loss_s))
                break

        self.assertTrue(
            np.allclose(
                np.array(dynamic_loss_rec),
                np.array(static_loss_rec),
                rtol=rtol,
                atol=atol,
                equal_nan=True),
            msg='Failed to do the imperative qat.')
示例#30
0
def quant_aware(program,
                place,
                config=None,
                scope=None,
                for_test=False,
                weight_quantize_func=None,
                act_quantize_func=None,
                weight_preprocess_func=None,
                act_preprocess_func=None,
                optimizer_func=None,
                executor=None,
                return_program=False):
    """Add quantization  and dequantization operators to "program" 
    for quantization training or testing.

    Args:
        program(paddle.static.Program): training or testing ``program``.
        place(paddle.CPUPlace or paddle.CUDAPlace): This parameter represents 
            the executor run on which device.
        config(dict, optional): configs for quantization. if None, will use default config. 
            Default: None.
        scope(paddle.static.Scope): Scope records the mapping between variable names and variables, 
            similar to brackets in programming languages. Usually users can use 
            `paddle.static.global_scope <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_.              When ``None`` will use `paddle.static.global_scope() <https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html>`_ . Default: ``None``.
        for_test(bool): If the 'program' parameter is a test program, this parameter should be set to ``True``. 
            Otherwise, set to ``False``.Default: False
       weight_quantize_func(function): Function that defines how to quantize weight. Using this
                can quickly test if user's quantization method works or not. In this function, user should
                both define quantization function and dequantization function, that is, the function's input
                is non-quantized weight and function returns dequantized weight. If None, will use
                quantization op defined by 'weight_quantize_type'.
                Default is None.
        act_quantize_func(function): Function that defines how to quantize activation. Using this
                can quickly test if user's quantization method works or not. In this function, user should
                both define quantization and dequantization process, that is, the function's input
                is non-quantized activation and function returns dequantized activation. If None, will use 
                quantization op defined by 'activation_quantize_type'.
                Default is None.
        weight_preprocess_func(function): Function that defines how to preprocess weight before quantization. Using this
                can quickly test if user's preprocess method works or not. The function's input
                is non-quantized weight and function returns processed weight to be quantized. If None, the weight will
                be quantized directly.
                Default is None.
        act_preprocess_func(function): Function that defines how to preprocess activation before quantization. Using this
                can quickly test if user's preprocess method works or not. The function's input
                is non-quantized activation and function returns processed activation to be quantized. If None, the activation will
                be quantized directly.
                Default is None.
        optimizer_func(function): Fuction return a optimizer. When 'is_test' is False and user want to use self-defined 
            quantization function and preprocess function, this function must be set. Default is None.
        exe(paddle.static.Executor): If user want to use self-defined quantization function and preprocess function, exe must be set for
                initialization. Default is None.
        return_program(bool): If user want return value is a Program rather than Compiled Program, This argument should be set True.
                Default is False.
    Returns:
        paddle.static.CompiledProgram | paddle.static.Program: Program with quantization and dequantization ``operators``
    """

    scope = paddle.static.global_scope() if not scope else scope
    if config is None:
        config = _quant_config_default
    else:
        assert isinstance(config, dict), "config must be dict"
        config = _parse_configs(config)
    _logger.info("quant_aware config {}".format(config))

    main_graph = IrGraph(core.Graph(program.desc), for_test=for_test)

    transform_pass_ops = []
    quant_dequant_ops = []
    for op_type in config['quantize_op_types']:
        if op_type in TRANSFORM_PASS_OP_TYPES:
            transform_pass_ops.append(op_type)
        elif op_type in QUANT_DEQUANT_PASS_OP_TYPES:
            quant_dequant_ops.append(op_type)
    if len(transform_pass_ops) > 0:
        transform_pass = QuantizationTransformPass(
            scope=scope,
            place=place,
            weight_bits=config['weight_bits'],
            activation_bits=config['activation_bits'],
            activation_quantize_type=config['activation_quantize_type'],
            weight_quantize_type=config['weight_quantize_type'],
            window_size=config['window_size'],
            moving_rate=config['moving_rate'],
            quantizable_op_type=transform_pass_ops,
            skip_pattern=config['not_quant_pattern'],
            weight_quantize_func=weight_quantize_func,
            act_quantize_func=act_quantize_func,
            weight_preprocess_func=weight_preprocess_func,
            act_preprocess_func=act_preprocess_func,
            optimizer_func=optimizer_func,
            executor=executor)

        transform_pass.apply(main_graph)

    if len(quant_dequant_ops) > 0:
        quant_dequant_pass = AddQuantDequantPass(
            scope=scope,
            place=place,
            moving_rate=config['moving_rate'],
            quant_bits=config['activation_bits'],
            skip_pattern=config['not_quant_pattern'],
            quantizable_op_type=quant_dequant_ops)
        quant_dequant_pass.apply(main_graph)

    out_scale_training_pass = OutScaleForTrainingPass(
        scope=scope, place=place, moving_rate=config['moving_rate'])
    out_scale_training_pass.apply(main_graph)

    if (weight_preprocess_func is not None
            or act_preprocess_func is not None) and not for_test:
        _logger.info(
            "When a preprocess_func is used in quant_aware, Need to save a mapping table to match variable names in the convert phase."
        )
        _logger.info(
            "The mapping table is saved as '{}'.".format(VARS_MAPPING_TABLE))
        save_dict(main_graph.out_node_mapping_table)

    if for_test or return_program:
        quant_program = main_graph.to_program()
    else:
        quant_program = paddle.static.CompiledProgram(main_graph.graph)
    return quant_program