Coverage for mlair/keras_legacy/conv_utils.py: 18%
76 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-12-02 15:24 +0000
« prev ^ index » next coverage.py v6.4.2, created at 2022-12-02 15:24 +0000
1"""Utilities used in convolutional layers.
2"""
3from __future__ import absolute_import
4from __future__ import division
5from __future__ import print_function
7import numpy as np
8from tensorflow.keras import backend as K
11def normalize_tuple(value, n, name):
12 """Transforms a single int or iterable of ints into an int tuple.
14 # Arguments
15 value: The value to validate and convert. Could be an int, or any iterable
16 of ints.
17 n: The size of the tuple to be returned.
18 name: The name of the argument being validated, e.g. `strides` or
19 `kernel_size`. This is only used to format error messages.
21 # Returns
22 A tuple of n integers.
24 # Raises
25 ValueError: If something else than an int/long or iterable thereof was
26 passed.
27 """
28 if isinstance(value, int):
29 return (value,) * n
30 else:
31 try:
32 value_tuple = tuple(value)
33 except TypeError:
34 raise ValueError('The `' + name + '` argument must be a tuple of ' +
35 str(n) + ' integers. Received: ' + str(value))
36 if len(value_tuple) != n: 36 ↛ 37line 36 didn't jump to line 37, because the condition on line 36 was never true
37 raise ValueError('The `' + name + '` argument must be a tuple of ' +
38 str(n) + ' integers. Received: ' + str(value))
39 for single_value in value_tuple:
40 try:
41 int(single_value)
42 except ValueError:
43 raise ValueError('The `' + name + '` argument must be a tuple of ' +
44 str(n) + ' integers. Received: ' + str(value) + ' '
45 'including element ' + str(single_value) + ' of '
46 'type ' + str(type(single_value)))
47 return value_tuple
50def normalize_padding(value):
51 padding = value.lower()
52 allowed = {'valid', 'same', 'causal'}
53 if K.backend() == 'theano':
54 allowed.add('full')
55 if padding not in allowed:
56 raise ValueError('The `padding` argument must be one of "valid", "same" '
57 '(or "causal" for Conv1D). Received: ' + str(padding))
58 return padding
61def convert_kernel(kernel):
62 """Converts a Numpy kernel matrix from Theano format to TensorFlow format.
64 Also works reciprocally, since the transformation is its own inverse.
66 # Arguments
67 kernel: Numpy array (3D, 4D or 5D).
69 # Returns
70 The converted kernel.
72 # Raises
73 ValueError: in case of invalid kernel shape or invalid data_format.
74 """
75 kernel = np.asarray(kernel)
76 if not 3 <= kernel.ndim <= 5:
77 raise ValueError('Invalid kernel shape:', kernel.shape)
78 slices = [slice(None, None, -1) for _ in range(kernel.ndim)]
79 no_flip = (slice(None, None), slice(None, None))
80 slices[-2:] = no_flip
81 return np.copy(kernel[slices])
84def conv_output_length(input_length, filter_size,
85 padding, stride, dilation=1):
86 """Determines output length of a convolution given input length.
88 # Arguments
89 input_length: integer.
90 filter_size: integer.
91 padding: one of `"same"`, `"valid"`, `"full"`.
92 stride: integer.
93 dilation: dilation rate, integer.
95 # Returns
96 The output length (integer).
97 """
98 if input_length is None:
99 return None
100 assert padding in {'same', 'valid', 'full', 'causal'}
101 dilated_filter_size = filter_size + (filter_size - 1) * (dilation - 1)
102 if padding == 'same':
103 output_length = input_length
104 elif padding == 'valid':
105 output_length = input_length - dilated_filter_size + 1
106 elif padding == 'causal':
107 output_length = input_length
108 elif padding == 'full':
109 output_length = input_length + dilated_filter_size - 1
110 return (output_length + stride - 1) // stride
113def conv_input_length(output_length, filter_size, padding, stride):
114 """Determines input length of a convolution given output length.
116 # Arguments
117 output_length: integer.
118 filter_size: integer.
119 padding: one of `"same"`, `"valid"`, `"full"`.
120 stride: integer.
122 # Returns
123 The input length (integer).
124 """
125 if output_length is None:
126 return None
127 assert padding in {'same', 'valid', 'full'}
128 if padding == 'same':
129 pad = filter_size // 2
130 elif padding == 'valid':
131 pad = 0
132 elif padding == 'full':
133 pad = filter_size - 1
134 return (output_length - 1) * stride - 2 * pad + filter_size
137def deconv_length(dim_size, stride_size, kernel_size, padding,
138 output_padding, dilation=1):
139 """Determines output length of a transposed convolution given input length.
141 # Arguments
142 dim_size: Integer, the input length.
143 stride_size: Integer, the stride along the dimension of `dim_size`.
144 kernel_size: Integer, the kernel size along the dimension of
145 `dim_size`.
146 padding: One of `"same"`, `"valid"`, `"full"`.
147 output_padding: Integer, amount of padding along the output dimension,
148 Can be set to `None` in which case the output length is inferred.
149 dilation: dilation rate, integer.
151 # Returns
152 The output length (integer).
153 """
154 assert padding in {'same', 'valid', 'full'}
155 if dim_size is None:
156 return None
158 # Get the dilated kernel size
159 kernel_size = kernel_size + (kernel_size - 1) * (dilation - 1)
161 # Infer length if output padding is None, else compute the exact length
162 if output_padding is None:
163 if padding == 'valid':
164 dim_size = dim_size * stride_size + max(kernel_size - stride_size, 0)
165 elif padding == 'full':
166 dim_size = dim_size * stride_size - (stride_size + kernel_size - 2)
167 elif padding == 'same':
168 dim_size = dim_size * stride_size
169 else:
170 if padding == 'same':
171 pad = kernel_size // 2
172 elif padding == 'valid':
173 pad = 0
174 elif padding == 'full':
175 pad = kernel_size - 1
177 dim_size = ((dim_size - 1) * stride_size + kernel_size - 2 * pad +
178 output_padding)
180 return dim_size