Exemple #1
0
    def rand_crop(img: tf_compat.Tensor):
        with tf_compat.name_scope(name):
            orig_shape = tf_compat.shape(img)
            scale = tf_compat.random_uniform(shape=[1],
                                             minval=scale_range[0],
                                             maxval=scale_range[1])[0]
            ratio = tf_compat.random_uniform(shape=[1],
                                             minval=ratio_range[0],
                                             maxval=ratio_range[1])[0]
            height = tf_compat.minimum(
                tf_compat.cast(
                    tf_compat.round(
                        tf_compat.cast(orig_shape[0], dtype=tf_compat.float32)
                        * scale / ratio),
                    tf_compat.int32,
                ),
                orig_shape[0],
            )
            width = tf_compat.minimum(
                tf_compat.cast(
                    tf_compat.round(
                        tf_compat.cast(orig_shape[1], dtype=tf_compat.float32)
                        * scale),
                    tf_compat.int32,
                ),
                orig_shape[1],
            )
            img = tf_compat.random_crop(img, [height, width, orig_shape[2]])

            return img
Exemple #2
0
        def _calc_lr():
            less = tf_compat.cast(
                tf_compat.greater_equal(global_step, milestone_steps),
                tf_compat.int64)
            updates = tf_compat.reduce_sum(less)
            mult_g = tf_compat.pow(gamma,
                                   tf_compat.cast(updates, tf_compat.float32))

            return tf_compat.multiply(init_lr, mult_g)
Exemple #3
0
            def zero_fraction(inp: tf_compat.Tensor):
                nonzero = tf_compat.cast(
                    tf_compat.reduce_sum(
                        tf_compat.cast(tf_compat.not_equal(inp, 0),
                                       tf_compat.int64)),
                    tf_compat.float32,
                )
                size = tf_compat.size(inp, out_type=tf_compat.float32)

                return 1 - tf_compat_div(nonzero, size)
Exemple #4
0
        def _calc_lr():
            steps = tf_compat.subtract(global_step, start_step)
            updates = tf_compat.cond(
                after,
                lambda: max_updates,
                lambda: tf_compat.cast(
                    tf_compat.floor(tf_compat.divide(steps, step_size)),
                    tf_compat.int64,
                ),
            )
            mult_g = tf_compat.pow(gamma,
                                   tf_compat.cast(updates, tf_compat.float32))

            return tf_compat.multiply(init_lr, mult_g)
Exemple #5
0
 def _set_constant_mask():
     # Assign mask tensor to be 1 for all nonzero values of op_var_tens otherwise 0
     # On end step, revert mask to be all 1s
     with tf_compat.name_scope(
             PruningScope.model(
                 op,
                 ks_group,
                 additional=PruningScope.OPS_UPDATE,
                 trailing_slash=True,
             )):
         new_mask = tf_compat.cond(
             is_start_step,
             lambda: tf_compat.cast(tf_compat.not_equal(op_var_tens, 0.0),
                                    dtype=op_var_tens.dtype),
             lambda: tf_compat.ones(op_var_tens.shape,
                                    dtype=op_var_tens.dtype),
         )
         weight_var = get_tensor_var(op_var_tens)
         return tf_compat.group(
             tf_compat.assign(mask,
                              new_mask,
                              name=PruningScope.OP_MASK_ASSIGN),
             tf_compat.assign(weight_var,
                              masked,
                              name=PruningScope.OP_WEIGHT_UPDATE),
         )
Exemple #6
0
    def cent_crop(img: tf_compat.Tensor):
        with tf_compat.name_scope(name):
            orig_shape = tf_compat.shape(img)
            min_size = tf_compat.cond(
                tf_compat.greater_equal(orig_shape[0], orig_shape[1]),
                lambda: orig_shape[1],
                lambda: orig_shape[0],
            )

            if padding > 0:
                orig_shape_list = img.get_shape().as_list()
                resize((orig_shape_list[0] + 2 * padding,
                        orig_shape_list[1] + 2 * padding))

            padding_height = tf_compat.add(
                tf_compat.cast(
                    tf_compat.round(
                        tf_compat.div(
                            tf_compat.cast(
                                tf_compat.subtract(orig_shape[0], min_size),
                                tf_compat.float32,
                            ),
                            2.0,
                        )),
                    tf_compat.int32,
                ),
                padding,
            )
            padding_width = tf_compat.add(
                tf_compat.cast(
                    tf_compat.round(
                        tf_compat.div(
                            tf_compat.cast(
                                tf_compat.subtract(orig_shape[1], min_size),
                                tf_compat.float32,
                            ),
                            2.0,
                        )),
                    tf_compat.int32,
                ),
                padding,
            )
            img = tf_compat.image.crop_to_bounding_box(img, padding_height,
                                                       padding_width, min_size,
                                                       min_size)

            return img
    def create_sparsity_mask(
        self,
        tensor: tf_compat.Tensor,
        sparsity: tf_compat.Tensor,
    ) -> tf_compat.Tensor:
        """
        :param tensor: A tensor of a model layer's weights
        :param sparsity: the target sparsity to use for assigning the masks
        :return: A sparsity mask close to the set sparsity based on the values of
            the input tensor
        """
        abs_var = tf_compat.abs(tensor)  # Magnitudes of weights
        sparse_threshold_index = tf_compat.cast(
            tf_compat.round(
                tf_compat.cast(tf_compat.size(abs_var), tf_compat.float32) *
                sparsity),
            tf_compat.int32,
        )
        sparse_threshold_index = tf_compat.minimum(
            tf_compat.maximum(sparse_threshold_index, 0),
            tf_compat.size(tensor) - 1,
        )

        try:
            argsort = tf_compat.argsort
        except Exception:
            try:
                argsort = tf_compat.contrib.framework.argsort
            except Exception:
                raise RuntimeError(
                    "cannot find argsort function in tensorflow_v1, "
                    "currently unsupported")

        # produce tensor where each element is the index in sorted order of abs_var
        abs_var_flat = tf_compat.reshape(abs_var, [-1])
        element_ranks_flat = tf_compat.scatter_nd(
            tf_compat.expand_dims(argsort(abs_var_flat), 1),
            tf_compat.range(abs_var_flat.get_shape()[0].value),
            abs_var_flat.get_shape(),
        )
        element_ranks = tf_compat.reshape(element_ranks_flat,
                                          abs_var.get_shape())
        return tf_compat.cast(
            tf_compat.greater(element_ranks, sparse_threshold_index),
            tf_compat.float32,
        )
Exemple #8
0
def multi_step_lr_schedule(
    global_step: tf_compat.Tensor,
    start_step: int,
    milestone_steps: List[int],
    init_lr: float,
    gamma: float,
    name: str = "multi_step_lr_schedule",
):
    """
    Create a multi step learning rate schedule in the current graph.
    Multiplies init_lr by gamma after each milestone has passed.
    Ex: lr = init_lr * (gamma ** NUM_UPDATES)

    :param global_step: the global step used for training
    :param start_step: the step to start the exponential schedule on
    :param milestone_steps: a list of steps to decrease the learning rate at,
        these are the number of steps that must pass after start_step to decrease lr
    :param init_lr: the learning rate to start the schedule with
    :param gamma: the decay weight to decrease init_lr by after every step_size interval
    :param name: the name scope to create the graph under
    :return: the calculated learning rate tensor
    """
    with tf_compat.name_scope(name):
        global_step = tf_compat.cast(global_step, tf_compat.int64)
        milestone_steps = tf_compat.constant(
            [mile + start_step for mile in milestone_steps],
            dtype=tf_compat.int64,
            name="milestone_steps",
        )
        start_step = tf_compat.constant(start_step,
                                        dtype=tf_compat.int64,
                                        name="start_step")
        init_lr = tf_compat.constant(init_lr,
                                     dtype=tf_compat.float32,
                                     name="init_lr")
        gamma = tf_compat.constant(gamma,
                                   dtype=tf_compat.float32,
                                   name="gamma")
        before = tf_compat.less(global_step, start_step, name="before")

        def _calc_lr():
            less = tf_compat.cast(
                tf_compat.greater_equal(global_step, milestone_steps),
                tf_compat.int64)
            updates = tf_compat.reduce_sum(less)
            mult_g = tf_compat.pow(gamma,
                                   tf_compat.cast(updates, tf_compat.float32))

            return tf_compat.multiply(init_lr, mult_g)

        learning_rate = tf_compat.cond(before,
                                       lambda: init_lr,
                                       _calc_lr,
                                       name="learning_rate")

    return learning_rate
        def non_zero_mask_initializer(
                shape: tf_compat.TensorShape,
                dtype: tf_compat.DType = tf_compat.float32,
                partition_info: Any = None,  # unsued variable for compatability
        ) -> tf_compat.Tensor:
            dtype = tf_compat.as_dtype(dtype)
            if not dtype.is_numpy_compatible or dtype == tf_compat.string:
                raise ValueError("Expected numeric or boolean dtype, got %s." %
                                 dtype)

            return tf_compat.cast(tf_compat.not_equal(tensor, 0.0),
                                  dtype=dtype)
Exemple #10
0
def preprocess_for_eval(image: tf_compat.Tensor):
    """
    The default preprocessing function for test set as defined in Resnet paper
    for Cifar datasets

    :param image: the image tensor

    :return: the preprocessed image
    """
    with tf_compat.name_scope("test_preprocess"):
        image = tf_compat.cast(image, dtype=tf_compat.float32)
        image = tf_compat_div(image, 255.0)
        image = tf_compat.image.random_crop(image, [32, 32, 3])
        return image
Exemple #11
0
    def create_ops(
        self,
        steps_per_epoch: int,
        global_step: tf_compat.Variable,
        graph: tf_compat.Graph,
    ) -> Tuple[List[Union[tf_compat.Tensor, tf_compat.Operation]], Dict[str, Any]]:
        """
        Create switch case computing the learning rate at a given global step and
        extras created by individual LR modifiers

        :param steps_per_epoch: the number of steps per training epoch
        :param global_step: the global step used while training
        :param graph: the graph to be modified
        :return: a tuple (list of empty ops, dict of named ops/tensors for learning
            rate and summaries as extras)
        """
        mod_ops, mod_extras = super().create_ops(graph, steps_per_epoch, global_step)
        name_scope = "{}/{}".format(NM_RECAL, self.__class__.__name__)

        with graph.as_default():
            with tf_compat.name_scope(name_scope):
                pred_fn_pairs = []
                global_step = tf_compat.cast(global_step, tf_compat.int64)

                for index, child in enumerate(self._lr_modifiers):
                    with tf_compat.name_scope(str(index)):
                        _, child_extras = child.create_ops(
                            steps_per_epoch, global_step, graph
                        )
                        child_lr = child_extras[EXTRAS_KEY_LEARNING_RATE]
                        child_start_step, _ = child.start_end_steps(
                            steps_per_epoch, after_optim=False
                        )
                        child_select = tf_compat.greater_equal(
                            global_step,
                            tf_compat.constant(child_start_step, tf_compat.int64),
                            name="active",
                        )
                        pred_fn_pairs.append((child_select, lambda lr=child_lr: lr))

                learning_rate = tf_compat.case(pred_fn_pairs)
                _add_lr_extras(mod_extras, learning_rate, self.log_types)

        return mod_ops, mod_extras
Exemple #12
0
    def processor(self, file_path: tf_compat.Tensor, label: tf_compat.Tensor):
        """
        :param file_path: the path to the file to load an image from
        :param label: the label for the given image
        :return: a tuple containing the processed image and label
        """
        with tf_compat.name_scope("img_to_tensor"):
            img = tf_compat.read_file(file_path)

            # Decode and reshape the image to 3 dimensional tensor
            # Note: "expand_animations" not available for TF 1.13 and prior,
            # hence the reshape trick below
            img = tf_compat.image.decode_image(img)
            img_shape = tf_compat.shape(img)
            img = tf_compat.reshape(img,
                                    [img_shape[0], img_shape[1], img_shape[2]])
            img = tf_compat.cast(img, dtype=tf_compat.float32)

        if self.pre_resize_transforms:
            transforms = (self.pre_resize_transforms.train
                          if self.train else self.pre_resize_transforms.val)
            if transforms:
                with tf_compat.name_scope("pre_resize_transforms"):
                    for trans in transforms:
                        img = trans(img)

        if self._image_size:
            res_callable = resize((self.image_size, self.image_size))
            img = res_callable(img)

        if self.post_resize_transforms:
            transforms = (self.post_resize_transforms.train
                          if self.train else self.post_resize_transforms.val)
            if transforms:
                with tf_compat.name_scope("post_resize_transforms"):
                    for trans in transforms:
                        img = trans(img)

        return img, label
Exemple #13
0
def preprocess_for_train(image: tf_compat.Tensor):
    """
    The default preprocessing function for train set as defined in Resnet paper
    for Cifar datasets

    :param image: the image tensor

    :return: the preprocessed image
    """
    with tf_compat.name_scope("train_preprocess"):
        image = tf_compat.cast(image, dtype=tf_compat.float32)
        rand_choice = tf_compat.random_uniform(shape=[],
                                               minval=0,
                                               maxval=2,
                                               dtype=tf_compat.int32)
        padding = _PADDING
        image = tf_compat.cond(
            tf_compat.equal(rand_choice, 0),
            lambda: tf_compat.pad(image, [[padding, padding],
                                          [padding, padding], [0, 0]]),
            lambda: tf_compat.image.random_flip_left_right(image),
        )
        distorted_image = tf_compat.image.random_crop(image, [32, 32, 3])
        return distorted_image
Exemple #14
0
def create_ks_schedule_ops(
    global_step: tf_compat.Variable,
    begin_step: int,
    end_step: int,
    update_step_freq: int,
    init_sparsity: float,
    final_sparsity: float,
    exponent: float,
    ks_group: str,
) -> Tuple[tf_compat.Tensor, tf_compat.Tensor]:
    """
    Create a gradual schedule for model pruning (kernel sparsity).
    Creates a sparsity tensor that goes from init_sparsity til final_sparsity
    starting at begin_step and ending at end_step.
    Uses the global_step to map those.
    Additionally creates an update_ready tensor that is True if an update
    to the sparsity tensor should be run, False otherwise.

    :param global_step: the global optimizer step for the training graph
    :param begin_step: the global step to begin pruning at
    :param end_step: the global step to end pruning at
    :param update_step_freq: the number of global steps between each weight update
    :param init_sparsity: the starting value for sparsity of a
        weight tensor to be enforce
    :param final_sparsity: the end value for sparsity for a weight tensor to be enforce
    :param exponent: the exponent to use for interpolating between
        init_sparsity and final_sparsity higher values will lead to larger sparsity
        steps at the beginning vs the end ie: linear (1) vs cubic (3)
    :param ks_group: the group identifier the scope should be created under
    :return: a tuple containing the signal for update_ready and the target sparsity
    """

    # create the scheduling ops first and the sparsity ops
    with tf_compat.name_scope(
            PruningScope.general(ks_group,
                                 additional=PruningScope.OPS_SCHEDULE,
                                 trailing_slash=True)):
        sched_before = tf_compat.less(global_step, begin_step)
        sched_start = tf_compat.equal(global_step, begin_step)
        sched_end = tf_compat.equal(global_step, end_step)
        sched_active = tf_compat.logical_and(
            tf_compat.greater(global_step, begin_step),
            tf_compat.less(global_step, end_step),
        )
        sched_active_inclusive = tf_compat.logical_or(
            sched_active, tf_compat.logical_or(sched_start, sched_end))
        sched_update = tf_compat.cond(
            tf_compat.less_equal(update_step_freq, 0),
            lambda: tf_compat.constant(True),
            lambda: tf_compat.equal(
                tf_compat.mod(
                    (global_step - begin_step), update_step_freq), 0),
        )
        sched_update_ready = tf_compat.logical_or(
            tf_compat.logical_or(sched_start, sched_end), sched_update)

        percentage = tf_compat.minimum(
            1.0,
            tf_compat.maximum(
                0.0,
                tf_compat_div(
                    tf_compat.cast(global_step - begin_step,
                                   tf_compat.float32),
                    end_step - begin_step,
                ),
            ),
        )
        exp_percentage = 1 - tf_compat.pow(1 - percentage, exponent)
        calc_sparsity = (tf_compat.multiply(final_sparsity - init_sparsity,
                                            exp_percentage) + init_sparsity)

        # create the update ready tensor and sparsity tensor
    with tf_compat.name_scope(
            PruningScope.general(ks_group, trailing_slash=True)):
        update_ready = tf_compat.logical_and(
            sched_active_inclusive,
            sched_update_ready,
            name=PruningScope.OP_UPDATE_READY,
        )
        sparsity = tf_compat.case(
            [
                (sched_before, lambda: tf_compat.constant(0.0)),
                (sched_start, lambda: tf_compat.constant(init_sparsity)),
                (sched_active, lambda: calc_sparsity),
            ],
            default=lambda: tf_compat.constant(final_sparsity),
            name=PruningScope.OP_SPARSITY,
        )

        # add return state to collections
    tf_compat.add_to_collection(
        PruningScope.collection_name(ks_group, PruningScope.OP_UPDATE_READY),
        update_ready,
    )
    tf_compat.add_to_collection(
        PruningScope.collection_name(ks_group, PruningScope.OP_SPARSITY),
        sparsity)

    return update_ready, sparsity
Exemple #15
0
def step_lr_schedule(
    global_step: tf_compat.Tensor,
    start_step: int,
    end_step: int,
    step_size: int,
    init_lr: float,
    gamma: float,
    name: str = "exponential_lr_schedule",
) -> tf_compat.Tensor:
    """
    Create an exponential learning rate schedule in the current graph.
    Multiplies init_lr by gamma after each step_size interval has passed.
    Ex: lr = init_lr * (gamma ** NUM_UPDATES)

    :param global_step: the global step used for training
    :param start_step: the step to start the exponential schedule on
    :param end_step: the step to end the exponential schedule on,
        can be set to -1 and in that event will continually update the LR
    :param step_size: the number of steps between each gamma update to the init_lr
    :param init_lr: the learning rate to start the schedule with
    :param gamma: the decay weight to decrease init_lr by after every step_size interval
    :param name: the name scope to create the graph under
    :return: the calculated learning rate tensor
    """
    with tf_compat.name_scope(name):
        global_step = tf_compat.cast(global_step, tf_compat.int64)
        max_updates = tf_compat.constant(
            (end_step - start_step) // step_size if end_step > 0 else -1,
            dtype=tf_compat.int64,
            name="max_updates",
        )
        start_step = tf_compat.constant(start_step,
                                        dtype=tf_compat.int64,
                                        name="start_step")
        end_step = tf_compat.constant(end_step,
                                      dtype=tf_compat.int64,
                                      name="end_step")
        init_lr = tf_compat.constant(init_lr,
                                     dtype=tf_compat.float32,
                                     name="init_lr")
        step_size = tf_compat.constant(step_size,
                                       dtype=tf_compat.int64,
                                       name="step_size")
        gamma = tf_compat.constant(gamma,
                                   dtype=tf_compat.float32,
                                   name="gamma")
        before = tf_compat.less(global_step, start_step, name="before")
        after = tf_compat.logical_and(
            tf_compat.greater_equal(global_step, end_step, name="after"),
            tf_compat.not_equal(end_step,
                                tf_compat.constant(-1, tf_compat.int64)),
        )

        def _calc_lr():
            steps = tf_compat.subtract(global_step, start_step)
            updates = tf_compat.cond(
                after,
                lambda: max_updates,
                lambda: tf_compat.cast(
                    tf_compat.floor(tf_compat.divide(steps, step_size)),
                    tf_compat.int64,
                ),
            )
            mult_g = tf_compat.pow(gamma,
                                   tf_compat.cast(updates, tf_compat.float32))

            return tf_compat.multiply(init_lr, mult_g)

        learning_rate = tf_compat.cond(before,
                                       lambda: init_lr,
                                       _calc_lr,
                                       name="learning_rate")

    return learning_rate