Skip to content

Introduce Symmetric/Reflection padding

Introduce two more padding variants which might fit better to time series forecasts than "same" (zero) padding. The padding size has to be calculated as a function of the applied kernel size. Currently, I use n_{\text{pad}} = \frac{k - 1}{2} which does not take strides other than one into account. Padding layers have to be passed as custom_objects dictionary (custom_objects = {'SymmetricPadding2D': SymmetricPadding2D}) when reloading the model from disk (model = load_model(experiment_name+'my_model.h5', custom_objects=custom_objects)).

  • Add padding base class
  • Add ReflectionPadding2D
  • Add SymmetricPadding2D
  • Add Sym/Ref padding to custom_objects => shifted to #62 (closed)

Code for paddings could look like this:


from keras.layers import ZeroPadding2D
import tensorflow as tf

class Paddings(ZeroPadding2D):
    """
     Summary of padding methods based on tf.pad
     Methods avaiable:
     - ReflectionPadding2D
     - SymmetricPadding2D
    """

    @staticmethod
    def get_padding_for_same(kernel_size):
        """
        This methods calculates the padding size to keep input and output dimensions equal for a given kernel size
        :param kernel_size:
        :return:
        """

        ks = np.array(kernel_size, dtype=np.int64)
        if (d & 0x1 for d in ks):
            pad = ((ks - 1) / 2).astype(np.int64)
            pad = ((pad[0], pad[0]), (pad[1], pad[1]))
            return pad
        else:
            raise NotImplementedError("even kernel size not implemented")

    @staticmethod
    def _set_paddings(padding):
        if isinstance(padding, tuple):
            pad1, pad2 = padding
            if isinstance(pad1, tuple) and isinstance(pad2, tuple):
                top_pad, bottom_pad = pad1
                left_pad, right_pad = pad2
            elif isinstance(pad1, int) and isinstance(pad2, int):
                top_pad, bottom_pad = pad1, pad1
                left_pad, right_pad = pad2, pad2
            else:
                raise NotImplementedError("Tuple, int mixtures not possible")
        pattern = [[0, 0],
                   [top_pad, bottom_pad],
                   [left_pad, right_pad],
                   [0, 0]]
        return pattern


class ReflectionPadding2D(Paddings, ZeroPadding2D):
    """
    Works like ZeroPadding, but uses reflecting values are used instead of zeros
    call: Copy pasted from
    https://github.com/robertomest/neural-style-keras/blob/11fecd8e99228aab4851e4c00e85ed31217406db/layers.py#L11
    """

    def call(self, x, mask=None):
        """
        Call method
        :param x:
        :param mask:
        :return:
        """
        return tf.pad(x, self._set_paddings(padding=self.padding), mode='REFLECT')

class SymmetricPadding2D(Paddings, ZeroPadding2D):
    """
    Works like ZeroPadding, but uses mode tf.pad with "symmetric"
    """

    def call(self, x, mask=None):
        """
        Call method
        :param x:
        :param mask:
        :return:
        """
        print(type(x))
        return tf.pad(x, self._set_paddings(padding=self.padding), mode='SYMMETRIC')
Edited by Ghost User