Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/keras/src/layers/convolutional/conv2d_transpose.py: 23%
91 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Keras 2D transposed convolution layer (sometimes called deconvolution)."""
18import tensorflow.compat.v2 as tf
20from keras.src import activations
21from keras.src import backend
22from keras.src import constraints
23from keras.src import initializers
24from keras.src import regularizers
25from keras.src.dtensor import utils
26from keras.src.engine.input_spec import InputSpec
27from keras.src.layers.convolutional.conv2d import Conv2D
28from keras.src.utils import conv_utils
30# isort: off
31from tensorflow.python.util.tf_export import keras_export
34@keras_export(
35 "keras.layers.Conv2DTranspose", "keras.layers.Convolution2DTranspose"
36)
37class Conv2DTranspose(Conv2D):
38 """Transposed convolution layer (sometimes called Deconvolution).
40 The need for transposed convolutions generally arises
41 from the desire to use a transformation going in the opposite direction
42 of a normal convolution, i.e., from something that has the shape of the
43 output of some convolution to something that has the shape of its input
44 while maintaining a connectivity pattern that is compatible with
45 said convolution.
47 When using this layer as the first layer in a model,
48 provide the keyword argument `input_shape`
49 (tuple of integers or `None`, does not include the sample axis),
50 e.g. `input_shape=(128, 128, 3)` for 128x128 RGB pictures
51 in `data_format="channels_last"`.
53 Args:
54 filters: Integer, the dimensionality of the output space
55 (i.e. the number of output filters in the convolution).
56 kernel_size: An integer or tuple/list of 2 integers, specifying the
57 height and width of the 2D convolution window.
58 Can be a single integer to specify the same value for
59 all spatial dimensions.
60 strides: An integer or tuple/list of 2 integers,
61 specifying the strides of the convolution along the height and width.
62 Can be a single integer to specify the same value for
63 all spatial dimensions.
64 Specifying any stride value != 1 is incompatible with specifying
65 any `dilation_rate` value != 1.
66 padding: one of `"valid"` or `"same"` (case-insensitive).
67 `"valid"` means no padding. `"same"` results in padding with zeros
68 evenly to the left/right or up/down of the input such that output has
69 the same height/width dimension as the input.
70 output_padding: An integer or tuple/list of 2 integers,
71 specifying the amount of padding along the height and width
72 of the output tensor.
73 Can be a single integer to specify the same value for all
74 spatial dimensions.
75 The amount of output padding along a given dimension must be
76 lower than the stride along that same dimension.
77 If set to `None` (default), the output shape is inferred.
78 data_format: A string,
79 one of `channels_last` (default) or `channels_first`.
80 The ordering of the dimensions in the inputs.
81 `channels_last` corresponds to inputs with shape
82 `(batch_size, height, width, channels)` while `channels_first`
83 corresponds to inputs with shape
84 `(batch_size, channels, height, width)`.
85 When unspecified, uses `image_data_format` value found in your Keras
86 config file at `~/.keras/keras.json` (if exists) else 'channels_last'.
87 Defaults to "channels_last".
88 dilation_rate: an integer, specifying the dilation rate for all spatial
89 dimensions for dilated convolution. Specifying different dilation rates
90 for different dimensions is not supported.
91 Currently, specifying any `dilation_rate` value != 1 is
92 incompatible with specifying any stride value != 1.
93 activation: Activation function to use.
94 If you don't specify anything, no activation is applied
95 (see `keras.activations`).
96 use_bias: Boolean, whether the layer uses a bias vector.
97 kernel_initializer: Initializer for the `kernel` weights matrix
98 (see `keras.initializers`). Defaults to 'glorot_uniform'.
99 bias_initializer: Initializer for the bias vector
100 (see `keras.initializers`). Defaults to 'zeros'.
101 kernel_regularizer: Regularizer function applied to
102 the `kernel` weights matrix (see `keras.regularizers`).
103 bias_regularizer: Regularizer function applied to the bias vector
104 (see `keras.regularizers`).
105 activity_regularizer: Regularizer function applied to
106 the output of the layer (its "activation") (see `keras.regularizers`).
107 kernel_constraint: Constraint function applied to the kernel matrix
108 (see `keras.constraints`).
109 bias_constraint: Constraint function applied to the bias vector
110 (see `keras.constraints`).
112 Input shape:
113 4D tensor with shape:
114 `(batch_size, channels, rows, cols)` if data_format='channels_first'
115 or 4D tensor with shape:
116 `(batch_size, rows, cols, channels)` if data_format='channels_last'.
118 Output shape:
119 4D tensor with shape:
120 `(batch_size, filters, new_rows, new_cols)` if
121 data_format='channels_first'
122 or 4D tensor with shape:
123 `(batch_size, new_rows, new_cols, filters)` if
124 data_format='channels_last'. `rows` and `cols` values might have changed
125 due to padding.
126 If `output_padding` is specified:
127 ```
128 new_rows = ((rows - 1) * strides[0] + kernel_size[0] - 2 * padding[0] +
129 output_padding[0])
130 new_cols = ((cols - 1) * strides[1] + kernel_size[1] - 2 * padding[1] +
131 output_padding[1])
132 ```
134 Returns:
135 A tensor of rank 4 representing
136 `activation(conv2dtranspose(inputs, kernel) + bias)`.
138 Raises:
139 ValueError: if `padding` is "causal".
140 ValueError: when both `strides` > 1 and `dilation_rate` > 1.
142 References:
143 - [A guide to convolution arithmetic for deep
144 learning](https://arxiv.org/abs/1603.07285v1)
145 - [Deconvolutional
146 Networks](https://www.matthewzeiler.com/mattzeiler/deconvolutionalnetworks.pdf)
147 """
149 @utils.allow_initializer_layout
150 def __init__(
151 self,
152 filters,
153 kernel_size,
154 strides=(1, 1),
155 padding="valid",
156 output_padding=None,
157 data_format=None,
158 dilation_rate=(1, 1),
159 activation=None,
160 use_bias=True,
161 kernel_initializer="glorot_uniform",
162 bias_initializer="zeros",
163 kernel_regularizer=None,
164 bias_regularizer=None,
165 activity_regularizer=None,
166 kernel_constraint=None,
167 bias_constraint=None,
168 **kwargs,
169 ):
170 super().__init__(
171 filters=filters,
172 kernel_size=kernel_size,
173 strides=strides,
174 padding=padding,
175 data_format=data_format,
176 dilation_rate=dilation_rate,
177 activation=activations.get(activation),
178 use_bias=use_bias,
179 kernel_initializer=initializers.get(kernel_initializer),
180 bias_initializer=initializers.get(bias_initializer),
181 kernel_regularizer=regularizers.get(kernel_regularizer),
182 bias_regularizer=regularizers.get(bias_regularizer),
183 activity_regularizer=regularizers.get(activity_regularizer),
184 kernel_constraint=constraints.get(kernel_constraint),
185 bias_constraint=constraints.get(bias_constraint),
186 **kwargs,
187 )
189 self.output_padding = output_padding
190 if self.output_padding is not None:
191 self.output_padding = conv_utils.normalize_tuple(
192 self.output_padding, 2, "output_padding", allow_zero=True
193 )
194 for stride, out_pad in zip(self.strides, self.output_padding):
195 if out_pad >= stride:
196 raise ValueError(
197 "Strides must be greater than output padding. "
198 f"Received strides={self.strides}, "
199 f"output_padding={self.output_padding}."
200 )
202 def build(self, input_shape):
203 input_shape = tf.TensorShape(input_shape)
204 if len(input_shape) != 4:
205 raise ValueError(
206 "Inputs should have rank 4. "
207 f"Received input_shape={input_shape}."
208 )
209 channel_axis = self._get_channel_axis()
210 if input_shape.dims[channel_axis].value is None:
211 raise ValueError(
212 "The channel dimension of the inputs "
213 "to `Conv2DTranspose` should be defined. "
214 f"The input_shape received is {input_shape}, "
215 f"where axis {channel_axis} (0-based) "
216 "is the channel dimension, which found to be `None`."
217 )
218 input_dim = int(input_shape[channel_axis])
219 self.input_spec = InputSpec(ndim=4, axes={channel_axis: input_dim})
220 kernel_shape = self.kernel_size + (self.filters, input_dim)
222 self.kernel = self.add_weight(
223 name="kernel",
224 shape=kernel_shape,
225 initializer=self.kernel_initializer,
226 regularizer=self.kernel_regularizer,
227 constraint=self.kernel_constraint,
228 trainable=True,
229 dtype=self.dtype,
230 )
231 if self.use_bias:
232 self.bias = self.add_weight(
233 name="bias",
234 shape=(self.filters,),
235 initializer=self.bias_initializer,
236 regularizer=self.bias_regularizer,
237 constraint=self.bias_constraint,
238 trainable=True,
239 dtype=self.dtype,
240 )
241 else:
242 self.bias = None
243 self.built = True
245 def call(self, inputs):
246 inputs_shape = tf.shape(inputs)
247 batch_size = inputs_shape[0]
248 if self.data_format == "channels_first":
249 h_axis, w_axis = 2, 3
250 else:
251 h_axis, w_axis = 1, 2
253 # Use the constant height and weight when possible.
254 # TODO(scottzhu): Extract this into a utility function that can be
255 # applied to all convolutional layers, which currently lost the static
256 # shape information due to tf.shape().
257 height, width = None, None
258 if inputs.shape.rank is not None:
259 dims = inputs.shape.as_list()
260 height = dims[h_axis]
261 width = dims[w_axis]
262 height = height if height is not None else inputs_shape[h_axis]
263 width = width if width is not None else inputs_shape[w_axis]
265 kernel_h, kernel_w = self.kernel_size
266 stride_h, stride_w = self.strides
268 if self.output_padding is None:
269 out_pad_h = out_pad_w = None
270 else:
271 out_pad_h, out_pad_w = self.output_padding
273 # Infer the dynamic output shape:
274 out_height = conv_utils.deconv_output_length(
275 height,
276 kernel_h,
277 padding=self.padding,
278 output_padding=out_pad_h,
279 stride=stride_h,
280 dilation=self.dilation_rate[0],
281 )
282 out_width = conv_utils.deconv_output_length(
283 width,
284 kernel_w,
285 padding=self.padding,
286 output_padding=out_pad_w,
287 stride=stride_w,
288 dilation=self.dilation_rate[1],
289 )
290 if self.data_format == "channels_first":
291 output_shape = (batch_size, self.filters, out_height, out_width)
292 else:
293 output_shape = (batch_size, out_height, out_width, self.filters)
295 output_shape_tensor = tf.stack(output_shape)
296 outputs = backend.conv2d_transpose(
297 inputs,
298 self.kernel,
299 output_shape_tensor,
300 strides=self.strides,
301 padding=self.padding,
302 data_format=self.data_format,
303 dilation_rate=self.dilation_rate,
304 )
306 if not tf.executing_eagerly() and inputs.shape.rank:
307 # Infer the static output shape:
308 out_shape = self.compute_output_shape(inputs.shape)
309 outputs.set_shape(out_shape)
311 if self.use_bias:
312 outputs = tf.nn.bias_add(
313 outputs,
314 self.bias,
315 data_format=conv_utils.convert_data_format(
316 self.data_format, ndim=4
317 ),
318 )
320 if self.activation is not None:
321 return self.activation(outputs)
322 return outputs
324 def compute_output_shape(self, input_shape):
325 input_shape = tf.TensorShape(input_shape).as_list()
326 output_shape = list(input_shape)
327 if self.data_format == "channels_first":
328 c_axis, h_axis, w_axis = 1, 2, 3
329 else:
330 c_axis, h_axis, w_axis = 3, 1, 2
332 kernel_h, kernel_w = self.kernel_size
333 stride_h, stride_w = self.strides
335 if self.output_padding is None:
336 out_pad_h = out_pad_w = None
337 else:
338 out_pad_h, out_pad_w = self.output_padding
340 output_shape[c_axis] = self.filters
341 output_shape[h_axis] = conv_utils.deconv_output_length(
342 output_shape[h_axis],
343 kernel_h,
344 padding=self.padding,
345 output_padding=out_pad_h,
346 stride=stride_h,
347 dilation=self.dilation_rate[0],
348 )
349 output_shape[w_axis] = conv_utils.deconv_output_length(
350 output_shape[w_axis],
351 kernel_w,
352 padding=self.padding,
353 output_padding=out_pad_w,
354 stride=stride_w,
355 dilation=self.dilation_rate[1],
356 )
357 return tf.TensorShape(output_shape)
359 def get_config(self):
360 config = super().get_config()
361 config["output_padding"] = self.output_padding
362 return config
365# Alias
367Convolution2DTranspose = Conv2DTranspose