Skip to content
Snippets Groups Projects
Commit a4644e7a authored by lukas leufen's avatar lukas leufen
Browse files

docs for paddings, updated docs requirements

parent 1bf8d5d6
Branches
Tags
3 merge requests!125Release v0.10.0,!124Update Master to new version v0.10.0,!91WIP: Resolve "create sphinx docu"
Pipeline #35385 passed
sphinx==3.0.1
sphinx==3.0.3
sphinx-autoapi==1.3.0
sphinx-rtd-theme==0.4.3
recommonmark==0.6.0
sphinx-autodoc-typehints==1.10.3
\ No newline at end of file
"""Collection of customised padding layers."""
__author__ = 'Felix Kleinert'
__date__ = '2020-03-02'
import tensorflow as tf
import numpy as np
import keras.backend as K
from keras.layers.convolutional import _ZeroPadding
from typing import Union, Tuple
import numpy as np
import tensorflow as tf
from keras.backend.common import normalize_data_format
from keras.layers import ZeroPadding2D
from keras.layers.convolutional import _ZeroPadding
from keras.legacy import interfaces
from keras.utils import conv_utils
from keras.utils.generic_utils import transpose_shape
from keras.backend.common import normalize_data_format
class PadUtils:
"""
Helper class for advanced paddings
"""
"""Helper class for advanced padding."""
@staticmethod
def get_padding_for_same(kernel_size, strides=1):
def get_padding_for_same(kernel_size: Tuple[int], strides: int = 1) -> Tuple[int]:
"""
This methods calculates the padding size to keep input and output dimensions equal for a given kernel size
(STRIDES HAVE TO BE EQUAL TO ONE!)
:param kernel_size:
:return:
Calculate padding size to keep input and output dimensions equal for a given kernel size.
.. hint:: custom paddings are currently only implemented for strides = 1
:param kernel_size: size of padding kernel size
:param strides: number of strides (default 1, currently only strides=1 supported)
:return: padding size
"""
if strides != 1:
raise NotImplementedError("Strides other than 1 not implemented!")
......@@ -40,15 +45,15 @@ class PadUtils:
if all(k % 2 == 1 for k in ks): # (d & 0x1 for d in ks):
pad = ((ks - 1) / 2).astype(np.int64)
# convert numpy int to base int
pad = [np.asscalar(v) for v in pad]
pad = [int(v.item()) for v in pad]
return tuple(pad)
# return tuple(PadUtils.check_padding_format(pad))
else:
raise NotImplementedError(f"even kernel size not implemented. Got {kernel_size}")
@staticmethod
def spatial_2d_padding(padding=((1, 1), (1, 1)), data_format=None):
"""Pads the 2nd and 3rd dimensions of a 4D tensor.
"""
Pad the 2nd and 3rd dimensions of a 4D tensor.
# Arguments
x: Tensor or variable.
......@@ -75,6 +80,7 @@ class PadUtils:
@staticmethod
def check_padding_format(padding):
"""Check padding format (int, 1D or 2D, >0)."""
if isinstance(padding, int):
normalized_padding = ((padding, padding), (padding, padding))
elif hasattr(padding, '__len__'):
......@@ -94,11 +100,13 @@ class PadUtils:
height_padding = conv_utils.normalize_tuple(padding[0], 2,
'1st entry of padding')
if not all(k >= 0 for k in height_padding):
raise ValueError(f"The `1st entry of padding` argument must be >= 0. Received: {padding[0]} of type {type(padding[0])}")
raise ValueError(
f"The `1st entry of padding` argument must be >= 0. Received: {padding[0]} of type {type(padding[0])}")
width_padding = conv_utils.normalize_tuple(padding[1], 2,
'2nd entry of padding')
if not all(k >= 0 for k in width_padding):
raise ValueError(f"The `2nd entry of padding` argument must be >= 0. Received: {padding[1]} of type {type(padding[1])}")
raise ValueError(
f"The `2nd entry of padding` argument must be >= 0. Received: {padding[1]} of type {type(padding[1])}")
normalized_padding = (height_padding, width_padding)
else:
raise ValueError('`padding` should be either an int, '
......@@ -112,9 +120,10 @@ class PadUtils:
class ReflectionPadding2D(_ZeroPadding):
"""
Reflection padding layer for 2D input. This custum padding layer is built on keras' zero padding layers. Doc is copy
pasted from the original functions/methods:
Reflection padding layer for 2D input.
This custom padding layer is built on keras' zero padding layers. Doc is copy and pasted from the original
functions/methods:
This layer can add rows and columns of reflected values
at the top, bottom, left and right side of an image like tensor.
......@@ -129,7 +138,7 @@ class ReflectionPadding2D(_ZeroPadding):
'# Arguments
# Arguments
padding: int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints.
- If int: the same symmetric padding
is applied to height and width.
......@@ -172,21 +181,24 @@ class ReflectionPadding2D(_ZeroPadding):
padding=(1, 1),
data_format=None,
**kwargs):
"""Initialise ReflectionPadding2D."""
normalized_padding = PadUtils.check_padding_format(padding=padding)
super(ReflectionPadding2D, self).__init__(normalized_padding,
data_format,
**kwargs)
def call(self, inputs, mask=None):
"""Call ReflectionPadding2D."""
pattern = PadUtils.spatial_2d_padding(padding=self.padding, data_format=self.data_format)
return tf.pad(inputs, pattern, 'REFLECT')
class SymmetricPadding2D(_ZeroPadding):
"""
Symmetric padding layer for 2D input. This custom padding layer is built on keras' zero padding layers. Doc is copy
pasted from the original functions/methods:
Symmetric padding layer for 2D input.
This custom padding layer is built on keras' zero padding layers. Doc is copy pasted from the original
functions/methods:
This layer can add rows and columns of symmetric values
at the top, bottom, left and right side of an image like tensor.
......@@ -243,39 +255,57 @@ class SymmetricPadding2D(_ZeroPadding):
padding=(1, 1),
data_format=None,
**kwargs):
"""Initialise SymmetricPadding2D."""
normalized_padding = PadUtils.check_padding_format(padding=padding)
super(SymmetricPadding2D, self).__init__(normalized_padding,
data_format,
**kwargs)
def call(self, inputs, mask=None):
"""Call SymmetricPadding2D."""
pattern = PadUtils.spatial_2d_padding(padding=self.padding, data_format=self.data_format)
return tf.pad(inputs, pattern, 'SYMMETRIC')
class Padding2D:
'''
This class combines the implemented padding methods. You can call this method by defining a specific padding type.
The __call__ method will return the corresponding Padding layer.
'''
"""
Combine all implemented padding methods.
You can call this method by defining a specific padding type. The __call__ method will return the corresponding
Padding layer.
.. code-block:: python
input_x = ... # your input data
kernel_size = (5, 1)
padding_size = PadUtils.get_padding_for_same(kernel_size)
tower = layers.Conv2D(...)(input_x)
tower = layers.Activation(...)(tower)
tower = Padding2D('ZeroPad2D')(padding=padding_size, name=f'Custom_Pad')(tower)
Padding type can either be set by a string or directly by using an instance of a valid padding class.
"""
allowed_paddings = {
**dict.fromkeys(("RefPad2D", "ReflectionPadding2D"), ReflectionPadding2D),
**dict.fromkeys(("SymPad2D", "SymmetricPadding2D"), SymmetricPadding2D),
**dict.fromkeys(("ZeroPad2D", "ZeroPadding2D"), ZeroPadding2D)
}
padding_type = Union[ReflectionPadding2D, SymmetricPadding2D, ZeroPadding2D]
def __init__(self, padding_type):
def __init__(self, padding_type: Union[str, padding_type]):
"""Set padding type."""
self.padding_type = padding_type
def _check_and_get_padding(self):
if isinstance(self.padding_type, str):
try:
pad2d = self.allowed_paddings[self.padding_type]
except KeyError as einfo:
except KeyError as e:
raise NotImplementedError(
f"`{einfo}' is not implemented as padding. "
"Use one of those: i) `RefPad2D', ii) `SymPad2D', iii) `ZeroPad2D'")
f"`{e}' is not implemented as padding. Use one of those: i) `RefPad2D', ii) `SymPad2D', "
f"iii) `ZeroPad2D'")
else:
if self.padding_type in self.allowed_paddings.values():
pad2d = self.padding_type
......@@ -286,6 +316,7 @@ class Padding2D:
return pad2d
def __call__(self, *args, **kwargs):
"""Call padding."""
return self._check_and_get_padding()(*args, **kwargs)
......@@ -318,5 +349,3 @@ if __name__ == '__main__':
model.compile('adam', loss='mse')
model.summary()
model.fit(x, y, epochs=10)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment