示例#1
0
    def test_with_slim_bn_op(self):
        """
        Test with Tf Slim BN op
        :return:
        """
        tf.compat.v1.reset_default_graph()
        sess = tf.compat.v1.Session(graph=tf.compat.v1.get_default_graph())
        inp = tf.compat.v1.placeholder(tf.float32, [1, 32, 32, 3])
        net = slim.conv2d(inp, 32, [3, 3])
        _ = slim.batch_norm(net, decay=.7, epsilon=.65, is_training=True)

        init = tf.compat.v1.global_variables_initializer()
        sess.run(init)
        with sess.graph.as_default():
            bn_op = sess.graph.get_operation_by_name('BatchNorm/FusedBatchNormV3')
            moving_mean = BNUtils.get_moving_mean_as_numpy_data(sess, bn_op)
            moving_var = BNUtils.get_moving_variance_as_numpy_data(sess, bn_op)
            beta = BNUtils.get_beta_as_numpy_data(sess, bn_op)
            gamma = BNUtils.get_gamma_as_numpy_data(sess, bn_op)

        # check the values read are equal to init values
        expected_beta = np.zeros_like(beta)
        expected_gamma = np.ones_like(gamma)
        expected_mean = np.zeros_like(moving_mean)
        expected_variance = np.ones_like(moving_var)

        self.assertTrue(np.allclose(expected_beta, beta))
        self.assertTrue(np.allclose(expected_gamma, gamma))
        self.assertTrue(np.allclose(expected_mean, moving_mean))
        self.assertTrue(np.allclose(expected_variance, moving_var))
示例#2
0
    def _create_new_op(
            self, op_tensor_tuple: Tuple[Op,
                                         List[tf.Tensor]]) -> List[tf.Tensor]:
        """
        Given a tuple of an operation to mirror and the parent tensor, create the new op.  Return a list of output
        tensors from the new op.
        :param op_tensor_tuple: Tuple containing (op to winnow, list of input tensors to the op)
        :return: List of output tensors of the winnowed op
        """

        switcher = {
            "Conv2D": module_reducers.reduce_conv2d,
            "DepthwiseConv2dNative": module_reducers.reduce_conv2d,
            "MaxPool": module_reducers.reduce_maxpool,
            "BatchNorm": module_reducers.reduce_batchnorm,
            "FusedBatchNormV3": module_reducers.reduce_batchnorm,
            "Relu": module_reducers.reduce_relu,
            "Relu6": module_reducers.reduce_relu,
            "AvgPool": module_reducers.reduce_avgpool,
            "Tanh": module_reducers.reduce_tanh,
            "Add": module_reducers.reduce_add,
            "AddN": module_reducers.reduce_add,
            "AddV2": module_reducers.reduce_add,
            "Identity": module_reducers.reduce_identity,
            "Dropout": module_reducers.reduce_dropout,
            "Pad": module_reducers.reduce_pad,
            "PadV2": module_reducers.reduce_pad,
            "MirrorPad": module_reducers.reduce_pad,
            "Minimum": module_reducers.reduce_min_max,
            "Maximum": module_reducers.reduce_min_max,
            "Downsample": module_reducers.reduce_downsample,
            "Upsample2D": module_reducers.reduce_upsample2d,
            "LeakyRelu": module_reducers.reduce_leaky_relu
        }

        reducer = switcher.get(op_tensor_tuple[0].type,
                               module_reducers.reduce_default)
        op_mask = self._op_to_mask_dict[op_tensor_tuple[0]]
        name, output_op_node, module = reducer(self._sess, op_tensor_tuple,
                                               op_mask)
        self._reduced_op_info[op_tensor_tuple[0]] = ReducedInfo(
            name, output_op_node, module)
        self._reduced_modules[op_tensor_tuple[0].get_module().name] = (module,
                                                                       op_mask)

        output_tensors = output_op_node.outputs
        if op_tensor_tuple[0].type in ['FusedBatchNormV3', 'Dropout']:
            output_tensors = output_tensors[:
                                            1]  # only get first output tensor, but in list form

        # Remove winnowed bn ops from UPDATE_OPS if present
        if op_tensor_tuple[0].type == 'FusedBatchNormV3':
            BNUtils.remove_bn_op_from_update_ops(
                self._sess, op_tensor_tuple[0].get_module())
        return output_tensors
示例#3
0
def get_bn_params_aimet_api(sess, bn_op):
    """
    Helper to get param values from BN layer using AIMET api(s)
    :param bn_op: BN layer
    :return: beta, gamma, mean and vairance values extracted from BN layer
    """
    beta = BNUtils.get_beta_as_numpy_data(sess, bn_op)
    gamma = BNUtils.get_gamma_as_numpy_data(sess, bn_op)
    moving_mean = BNUtils.get_moving_mean_as_numpy_data(sess, bn_op)
    moving_var = BNUtils.get_moving_variance_as_numpy_data(sess, bn_op)

    return [beta, gamma, moving_mean, moving_var]
示例#4
0
    def _get_bn_params(model, bn_layer) -> libpymo.BnParamsBiasCorr():
        """
        get bn params for bn based bias correction
        :param model: tf.compat.v1.Session type
        :param bn_layer: tf.Operation type
        :return: bn params as libpymo.BnParamsBiasCorr() type
        """

        bn_params = libpymo.BnParamsBiasCorr()
        bn_params.beta = BNUtils.get_beta_as_numpy_data(model,
                                                        bn_layer).reshape(-1)
        bn_params.gamma = BNUtils.get_gamma_as_numpy_data(model,
                                                          bn_layer).reshape(-1)

        return bn_params
    def get_bn_params_for_bias_fold(sess: tf.compat.v1.Session, bn_op: tf.Operation, scaling_parameter: np.ndarray):
        """

        :param sess: active tf.compat.v1.Session
        :param bn_op: tf Operation type fused batchnorm op.
        :param scaling_parameter: scaling param as np.ndarray
        :return: bn_params as BNParamsHighBiasFold type.
        """

        bn_params = libpymo.BNParamsHighBiasFold()
        # Scaling gamma and beta parameter of batch norm layer
        gamma = BNUtils.get_gamma_as_numpy_data(sess, bn_op).reshape(-1)
        bn_params.gamma = np.divide(gamma, scaling_parameter)
        beta = BNUtils.get_beta_as_numpy_data(sess, bn_op).reshape(-1)
        bn_params.beta = np.divide(beta, scaling_parameter)

        return bn_params
示例#6
0
        def create_batchnorm_params(my_op: Op):
            """ Create products for fusedbatchnorm """
            tf_op = my_op.get_module()

            beta_tensor = BNUtils.get_beta_read_var_op_tensor(tf_op)
            create_and_connect_product('beta', beta_tensor.shape, my_op, beta_tensor)

            gamma_tensor = BNUtils.get_gamma_read_var_op_tensor(tf_op)
            create_and_connect_product('gamma', gamma_tensor.shape, my_op, gamma_tensor)

            moving_mean_tensor = BNUtils.get_moving_mean_read_var_op_tensor(tf_op)
            create_and_connect_product('moving_mean', moving_mean_tensor.shape, my_op,
                                       moving_mean_tensor)

            moving_variance_tensor = BNUtils.get_moving_variance_read_var_op_tensor(tf_op)
            create_and_connect_product('moving_variance', moving_variance_tensor.shape, my_op,
                                       moving_variance_tensor)
示例#7
0
def _get_bn_params(sess: tf.compat.v1.Session,
                   bn: tf.Operation) -> libpymo.BNParams():
    """
    helper to populate BN params from given BN op, required for fold
    :param sess: tf.compat.v1.Session type
    :param bn: BatchNorm or a FusedBatch Norm op
    :return: bn_params
    """
    # make sure you define the session and graph scope before loading vars from graph.
    with sess.graph.as_default():
        # create BNParams type and populate
        bn_params = libpymo.BNParams()
        bn_params.beta = BNUtils.get_beta_as_numpy_data(sess, bn).reshape(-1)
        bn_params.gamma = BNUtils.get_gamma_as_numpy_data(sess, bn).reshape(-1)
        bn_params.runningMean = BNUtils.get_moving_mean_as_numpy_data(
            sess, bn).reshape(-1)
        bn_params.runningVar = BNUtils.get_moving_variance_as_numpy_data(
            sess, bn).reshape(-1)
        epsilon = BNUtils.get_epsilon(bn)
        var = BNUtils.get_moving_variance_as_numpy_data(sess, bn).reshape(-1)
        var_with_epsilon = var + epsilon
        sigma = np.sqrt(var_with_epsilon)
        # sigma = tf.sqrt(BNUtils.get_moving_variance_as_numpy_data(sess, bn).reshape(-1) + epsilon)
        bn_params.runningVar = sigma  # sess.run(sigma).reshape(-1)

    return bn_params
示例#8
0
    def test_training_batchnorm(self):
        """ Test BNUtils get_training() with both fused and non fused batchnorms, with all three training modes """

        tf.compat.v1.reset_default_graph()

        # Model with fused batchnorms
        _ = keras_model_functional()
        fused_bn_training_true_op = tf.compat.v1.get_default_graph().get_operation_by_name('batch_normalization/FusedBatchNormV3')
        self.assertTrue(BNUtils.get_training(fused_bn_training_true_op))
        self.assertTrue(isinstance(BNUtils.get_training(fused_bn_training_true_op), bool))

        fused_bn_training_tensor_op = tf.compat.v1.get_default_graph().get_operation_by_name('scope_1/batch_normalization_1/cond/'
                                                                                   'FusedBatchNormV3_1')
        training_tensor = tf.compat.v1.get_default_graph().get_tensor_by_name('is_training:0')
        self.assertEqual(BNUtils.get_training(fused_bn_training_tensor_op), training_tensor)

        fused_bn_training_false_op = tf.compat.v1.get_default_graph().get_operation_by_name('scope_1/batch_normalization_2/'
                                                                                  'FusedBatchNormV3')
        self.assertFalse(BNUtils.get_training(fused_bn_training_false_op))

        tf.compat.v1.reset_default_graph()

        # Model with non fused batchnorms
        _ = keras_model_functional_with_non_fused_batchnorms()
        bn_training_true_op = tf.compat.v1.get_default_graph().get_operation_by_name('batch_normalization/batchnorm/mul_1')
        self.assertTrue(BNUtils.get_training(bn_training_true_op))
        self.assertTrue(isinstance(BNUtils.get_training(bn_training_true_op), bool))

        bn_training_tensor_op = tf.compat.v1.get_default_graph().get_operation_by_name('scope_1/batch_normalization_1/batchnorm/'
                                                                             'mul_1')
        training_tensor = tf.compat.v1.get_default_graph().get_tensor_by_name('is_training:0')
        self.assertEqual(BNUtils.get_training(bn_training_tensor_op), training_tensor)

        bn_training_false_op = tf.compat.v1.get_default_graph().get_operation_by_name('scope_1/batch_normalization_2/batchnorm/'
                                                                            'mul_1')
        self.assertFalse(BNUtils.get_training(bn_training_false_op))

        tf.compat.v1.reset_default_graph()
示例#9
0
def _fold_given_auto_selected_batch_norms(
        sess: tf.compat.v1.Session,
        layer_pairs: List[PairType]) -> tf.compat.v1.Session:
    """
    Fold a given set of batch_norm layers into conv layers

    :param sess: tf.compat.v1.Session
    :param layer_pairs: pair of conv and bn layers
    :return: new session with updated graph
    """

    with sess.graph.as_default():

        for pair in layer_pairs:

            conv_linear, batchnorm, is_batch_norm_second = pair

            assert conv_linear.type in [
                'Conv2D', 'DepthwiseConv2dNative', 'MatMul'
            ]

            #  check flag
            is_bias_valid = False

            if not BiasUtils.is_bias_none(conv_linear):
                is_bias_valid = True

            bn_params = _get_bn_params(sess, batchnorm.op)
            weight_tensor = _get_weight_tensor_transpose_reshape(
                sess, conv_linear)
            bias_tensor = _get_bias_tensor(sess, conv_linear)

            bias = libpymo.fold(bn_params, weight_tensor, bias_tensor,
                                is_bias_valid, is_batch_norm_second)

            # converting back to TF format [kh, kw, Nic, Noc] before updating weight tensor value
            if conv_linear.type == 'DepthwiseConv2dNative':
                # Depthwise conv layers in TF have outputs(Noc) set to 1.
                # we send in format [Nic, Noc, kh, kw]
                numpy_weight_reshaped = np.reshape(
                    weight_tensor.data, weight_tensor.shape).transpose(
                        (2, 3, 0, 1))
            elif conv_linear.type == 'MatMul':
                # o, i - convert to i , o
                numpy_weight_reshaped = np.reshape(
                    weight_tensor.data,
                    [weight_tensor.shape[0], weight_tensor.shape[1]
                     ]).transpose(1, 0)
            else:
                # conv2D case
                # we sent in format [Noc, Nic, kh, kw]
                numpy_weight_reshaped = np.reshape(
                    weight_tensor.data, weight_tensor.shape).transpose(
                        (2, 3, 1, 0))

            WeightTensorUtils.update_tensor_for_op(sess, conv_linear,
                                                   numpy_weight_reshaped)

            # remove bn op
            BNUtils.skip_bn_op(sess, batchnorm.op, batchnorm.in_tensor,
                               batchnorm.out_tensor)

            # update bias tensor, even in case there was no existing bias add op in given conv2D op.
            bias_tensor_shape = [weight_tensor.shape[0]]
            numpy_bias_reshaped = np.reshape(bias, bias_tensor_shape)
            BiasUtils.update_bias_for_op(sess, conv_linear,
                                         numpy_bias_reshaped)

        # we edited the graph, so we should load and save for the metagraph associated with the session to be updated
        after_bn_fold_sess = save_and_load_graph('./temp_bn_fold', sess)

    return after_bn_fold_sess
示例#10
0
def reduce_batchnorm(sess: tf.compat.v1.Session,
                     op_tensor_tuple: Tuple[Op, List[tf.Tensor]], op_mask) -> (str, tf.Operation, tf.Operation):
    """
    Fused and non fused batchnorm module reducer
    :param sess: current tf.compat.v1.Session
    :param op_tensor_tuple: tuple containing the op to reduce, and a list of input tensors to the op
    :param op_mask: Mask containing information on input and output channels to winnow
    """

    beta_product = op_tensor_tuple[0].get_param_product('beta')
    if beta_product:
        use_beta = True
        reduced_beta_init = tf.constant_initializer(_get_reduced_params(sess=sess,
                                                                        product=beta_product,
                                                                        mask=op_mask,
                                                                        input_dim=0,
                                                                        output_dim=None),
                                                    verify_shape=True)
    else:
        use_beta = False
        reduced_beta_init = 'zeros'

    gamma_product = op_tensor_tuple[0].get_param_product('gamma')
    if gamma_product:
        use_gamma = True
        reduced_gamma_init = tf.constant_initializer(_get_reduced_params(sess=sess,
                                                                         product=gamma_product,
                                                                         mask=op_mask,
                                                                         input_dim=0,
                                                                         output_dim=None),
                                                     verify_shape=True)
    else:
        use_gamma = False
        reduced_gamma_init = 'ones'

    moving_mean_product = op_tensor_tuple[0].get_param_product('moving_mean')
    reduced_mov_mean_init = tf.constant_initializer(_get_reduced_params(sess=sess,
                                                                        product=moving_mean_product,
                                                                        mask=op_mask,
                                                                        input_dim=0,
                                                                        output_dim=None),
                                                    verify_shape=True)
    moving_variance_product = op_tensor_tuple[0].get_param_product('moving_variance')
    reduced_mov_variance_init = tf.constant_initializer(_get_reduced_params(sess=sess,
                                                                            product=moving_variance_product,
                                                                            mask=op_mask,
                                                                            input_dim=0,
                                                                            output_dim=None),
                                                        verify_shape=True)

    name = "reduced_" + op_tensor_tuple[0].dotted_name
    # Get training attribute
    # This will either be True, False, or a string representing a training_placeholder the original BN was using
    training = BNUtils.get_training(op_tensor_tuple[0].get_module())
    assert training is not None
    is_fused = op_tensor_tuple[0].type == 'FusedBatchNormV3'
    epsilon = BNUtils.get_epsilon(op_tensor_tuple[0].get_module())
    momentum = BNUtils.get_momentum(op_tensor_tuple[0].get_module())
    if momentum is not None:
        new_tensor = tf.keras.layers.BatchNormalization(center=use_beta,
                                                        scale=use_gamma,
                                                        epsilon=epsilon,
                                                        momentum=momentum,
                                                        beta_initializer=reduced_beta_init,
                                                        gamma_initializer=reduced_gamma_init,
                                                        moving_mean_initializer=reduced_mov_mean_init,
                                                        moving_variance_initializer=reduced_mov_variance_init,
                                                        fused=is_fused,
                                                        name=name)(op_tensor_tuple[1][0], training=training)
    else:
        new_tensor = tf.keras.layers.BatchNormalization(center=use_beta,
                                                        scale=use_gamma,
                                                        epsilon=epsilon,
                                                        beta_initializer=reduced_beta_init,
                                                        gamma_initializer=reduced_gamma_init,
                                                        moving_mean_initializer=reduced_mov_mean_init,
                                                        moving_variance_initializer=reduced_mov_variance_init,
                                                        fused=is_fused,
                                                        name=name)(op_tensor_tuple[1][0], training=training)
    module = new_tensor.op.inputs[0].op

    return name, new_tensor.op, module