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
No related branches found
No related tags found
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