import tensorflow as tf


                    X = self._do_separable_conv(X, w, h, ch, filter_size=filter_size, stride=stack_stride,
                                                W_d=W_d, W_p=W_p, no_batch_norm=True)
                    X = self._add_batch_norm(X, ch, offset=batch_norm_offset, scale=batch_norm_scale,
                                            no_moving_average=is_dynamic, is_train=is_train)

        X = tf.reshape(X, (-1, w // stride, h // stride, ch)) # Sanity shape check
        return X

    ####################################
    # Utils
    ####################################

    def _do_cutout(self, image, im_width, im_height, cutout_size):
        mask = tf.ones([cutout_size, cutout_size], dtype=tf.int32)
        start_x = tf.random.uniform(shape=(1,), minval=0, maxval=im_width, dtype=tf.int32)
        start_y = tf.random.uniform(shape=(1,), minval=0, maxval=im_height, dtype=tf.int32)
        mask = tf.pad(mask, [[cutout_size + start_y[0], im_height - start_y[0]],
                            [cutout_size + start_x[0], im_width - start_x[0]]])
        mask = mask[cutout_size: cutout_size + im_height,
                    cutout_size: cutout_size + im_width]
        mask = tf.tile(tf.reshape(mask, (im_height, im_width, 1)), (1, 1, 3))
        image = tf.where(tf.equal(mask, 0), x=image, y=tf.zeros_like(image))
        return image

    def _add_drop_path(self, X, keep_prob):
        with tf.variable_scope('drop_path'):
            batch_size = tf.shape(X)[0]
