Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/keras/src/layers/convolutional/conv3d_transpose.py: 22%
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 3D transposed convolution layer (sometimes called deconvolution)."""
18import tensorflow.compat.v2 as tf
20from keras.src import activations
21from keras.src import constraints
22from keras.src import initializers
23from keras.src import regularizers
24from keras.src.dtensor import utils
25from keras.src.engine.input_spec import InputSpec
26from keras.src.layers.convolutional.conv3d import Conv3D
27from keras.src.utils import conv_utils
29# isort: off
30from tensorflow.python.util.tf_export import keras_export
33@keras_export(
34 "keras.layers.Conv3DTranspose", "keras.layers.Convolution3DTranspose"
35)
36class Conv3DTranspose(Conv3D):
37 """Transposed convolution layer (sometimes called Deconvolution).
39 The need for transposed convolutions generally arises
40 from the desire to use a transformation going in the opposite direction
41 of a normal convolution, i.e., from something that has the shape of the
42 output of some convolution to something that has the shape of its input
43 while maintaining a connectivity pattern that is compatible with
44 said convolution.
46 When using this layer as the first layer in a model,
47 provide the keyword argument `input_shape`
48 (tuple of integers or `None`, does not include the sample axis),
49 e.g. `input_shape=(128, 128, 128, 3)` for a 128x128x128 volume with 3
50 channels if `data_format="channels_last"`.
52 Args:
53 filters: Integer, the dimensionality of the output space
54 (i.e. the number of output filters in the convolution).
55 kernel_size: An integer or tuple/list of 3 integers, specifying the
56 depth, height and width of the 3D convolution window.
57 Can be a single integer to specify the same value for
58 all spatial dimensions.
59 strides: An integer or tuple/list of 3 integers,
60 specifying the strides of the convolution along the depth, height
61 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 3 integers,
71 specifying the amount of padding along the depth, height, and
72 width.
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, depth, height, width, channels)` while `channels_first`
83 corresponds to inputs with shape
84 `(batch_size, channels, depth, 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 or tuple/list of 3 integers, specifying
89 the dilation rate to use for dilated convolution.
90 Can be a single integer to specify the same value for
91 all spatial dimensions.
92 Currently, specifying any `dilation_rate` value != 1 is
93 incompatible with specifying any stride value != 1.
94 activation: Activation function to use.
95 If you don't specify anything, no activation is applied
96 (see `keras.activations`).
97 use_bias: Boolean, whether the layer uses a bias vector.
98 kernel_initializer: Initializer for the `kernel` weights matrix
99 (see `keras.initializers`). Defaults to 'glorot_uniform'.
100 bias_initializer: Initializer for the bias vector
101 (see `keras.initializers`). Defaults to 'zeros'.
102 kernel_regularizer: Regularizer function applied to
103 the `kernel` weights matrix
104 (see `keras.regularizers`).
105 bias_regularizer: Regularizer function applied to the bias vector
106 (see `keras.regularizers`).
107 activity_regularizer: Regularizer function applied to
108 the output of the layer (its "activation")
109 (see `keras.regularizers`).
110 kernel_constraint: Constraint function applied to the kernel matrix
111 (see `keras.constraints`).
112 bias_constraint: Constraint function applied to the bias vector
113 (see `keras.constraints`).
115 Input shape:
116 5D tensor with shape:
117 `(batch_size, channels, depth, rows, cols)` if
118 data_format='channels_first'
119 or 5D tensor with shape:
120 `(batch_size, depth, rows, cols, channels)` if
121 data_format='channels_last'.
123 Output shape:
124 5D tensor with shape:
125 `(batch_size, filters, new_depth, new_rows, new_cols)` if
126 data_format='channels_first'
127 or 5D tensor with shape:
128 `(batch_size, new_depth, new_rows, new_cols, filters)` if
129 data_format='channels_last'.
130 `depth` and `rows` and `cols` values might have changed due to padding.
131 If `output_padding` is specified::
132 ```
133 new_depth = ((depth - 1) * strides[0] + kernel_size[0] - 2 * padding[0] +
134 output_padding[0])
135 new_rows = ((rows - 1) * strides[1] + kernel_size[1] - 2 * padding[1] +
136 output_padding[1])
137 new_cols = ((cols - 1) * strides[2] + kernel_size[2] - 2 * padding[2] +
138 output_padding[2])
139 ```
141 Returns:
142 A tensor of rank 5 representing
143 `activation(conv3dtranspose(inputs, kernel) + bias)`.
145 Raises:
146 ValueError: if `padding` is "causal".
147 ValueError: when both `strides` > 1 and `dilation_rate` > 1.
149 References:
150 - [A guide to convolution arithmetic for deep
151 learning](https://arxiv.org/abs/1603.07285v1)
152 - [Deconvolutional
153 Networks](https://www.matthewzeiler.com/mattzeiler/deconvolutionalnetworks.pdf)
154 """
156 @utils.allow_initializer_layout
157 def __init__(
158 self,
159 filters,
160 kernel_size,
161 strides=(1, 1, 1),
162 padding="valid",
163 output_padding=None,
164 data_format=None,
165 dilation_rate=(1, 1, 1),
166 activation=None,
167 use_bias=True,
168 kernel_initializer="glorot_uniform",
169 bias_initializer="zeros",
170 kernel_regularizer=None,
171 bias_regularizer=None,
172 activity_regularizer=None,
173 kernel_constraint=None,
174 bias_constraint=None,
175 **kwargs,
176 ):
177 super().__init__(
178 filters=filters,
179 kernel_size=kernel_size,
180 strides=strides,
181 padding=padding,
182 data_format=data_format,
183 dilation_rate=dilation_rate,
184 activation=activations.get(activation),
185 use_bias=use_bias,
186 kernel_initializer=initializers.get(kernel_initializer),
187 bias_initializer=initializers.get(bias_initializer),
188 kernel_regularizer=regularizers.get(kernel_regularizer),
189 bias_regularizer=regularizers.get(bias_regularizer),
190 activity_regularizer=regularizers.get(activity_regularizer),
191 kernel_constraint=constraints.get(kernel_constraint),
192 bias_constraint=constraints.get(bias_constraint),
193 **kwargs,
194 )
196 self.output_padding = output_padding
197 if self.output_padding is not None:
198 self.output_padding = conv_utils.normalize_tuple(
199 self.output_padding, 3, "output_padding", allow_zero=True
200 )
201 for stride, out_pad in zip(self.strides, self.output_padding):
202 if out_pad >= stride:
203 raise ValueError(
204 "Strides must be greater than output padding. "
205 f"Received strides={self.strides}, "
206 f"output_padding={self.output_padding}."
207 )
209 def build(self, input_shape):
210 input_shape = tf.TensorShape(input_shape)
211 if len(input_shape) != 5:
212 raise ValueError(
213 "Inputs should have rank 5. "
214 f"Received input_shape={input_shape}."
215 )
216 channel_axis = self._get_channel_axis()
217 if input_shape.dims[channel_axis].value is None:
218 raise ValueError(
219 "The channel dimension of the inputs "
220 "to `Conv3DTranspose` should be defined. "
221 f"The input_shape received is {input_shape}, "
222 f"where axis {channel_axis} (0-based) "
223 "is the channel dimension, which found to be `None`."
224 )
225 input_dim = int(input_shape[channel_axis])
226 kernel_shape = self.kernel_size + (self.filters, input_dim)
227 self.input_spec = InputSpec(ndim=5, axes={channel_axis: input_dim})
229 self.kernel = self.add_weight(
230 "kernel",
231 shape=kernel_shape,
232 initializer=self.kernel_initializer,
233 regularizer=self.kernel_regularizer,
234 constraint=self.kernel_constraint,
235 trainable=True,
236 dtype=self.dtype,
237 )
238 if self.use_bias:
239 self.bias = self.add_weight(
240 "bias",
241 shape=(self.filters,),
242 initializer=self.bias_initializer,
243 regularizer=self.bias_regularizer,
244 constraint=self.bias_constraint,
245 trainable=True,
246 dtype=self.dtype,
247 )
248 else:
249 self.bias = None
250 self.built = True
252 def call(self, inputs):
253 inputs_shape = tf.shape(inputs)
254 batch_size = inputs_shape[0]
255 if self.data_format == "channels_first":
256 d_axis, h_axis, w_axis = 2, 3, 4
257 else:
258 d_axis, h_axis, w_axis = 1, 2, 3
260 depth = inputs_shape[d_axis]
261 height = inputs_shape[h_axis]
262 width = inputs_shape[w_axis]
264 kernel_d, kernel_h, kernel_w = self.kernel_size
265 stride_d, stride_h, stride_w = self.strides
267 if self.output_padding is None:
268 out_pad_d = out_pad_h = out_pad_w = None
269 else:
270 out_pad_d, out_pad_h, out_pad_w = self.output_padding
272 # Infer the dynamic output shape:
273 out_depth = conv_utils.deconv_output_length(
274 depth,
275 kernel_d,
276 padding=self.padding,
277 output_padding=out_pad_d,
278 stride=stride_d,
279 )
280 out_height = conv_utils.deconv_output_length(
281 height,
282 kernel_h,
283 padding=self.padding,
284 output_padding=out_pad_h,
285 stride=stride_h,
286 )
287 out_width = conv_utils.deconv_output_length(
288 width,
289 kernel_w,
290 padding=self.padding,
291 output_padding=out_pad_w,
292 stride=stride_w,
293 )
294 if self.data_format == "channels_first":
295 output_shape = (
296 batch_size,
297 self.filters,
298 out_depth,
299 out_height,
300 out_width,
301 )
302 strides = (1, 1, stride_d, stride_h, stride_w)
303 else:
304 output_shape = (
305 batch_size,
306 out_depth,
307 out_height,
308 out_width,
309 self.filters,
310 )
311 strides = (1, stride_d, stride_h, stride_w, 1)
313 output_shape_tensor = tf.stack(output_shape)
314 outputs = tf.nn.conv3d_transpose(
315 inputs,
316 self.kernel,
317 output_shape_tensor,
318 strides,
319 data_format=conv_utils.convert_data_format(
320 self.data_format, ndim=5
321 ),
322 padding=self.padding.upper(),
323 )
325 if not tf.executing_eagerly() and inputs.shape.rank:
326 # Infer the static output shape:
327 out_shape = self.compute_output_shape(inputs.shape)
328 outputs.set_shape(out_shape)
330 if self.use_bias:
331 outputs = tf.nn.bias_add(
332 outputs,
333 self.bias,
334 data_format=conv_utils.convert_data_format(
335 self.data_format, ndim=4
336 ),
337 )
339 if self.activation is not None:
340 return self.activation(outputs)
341 return outputs
343 def compute_output_shape(self, input_shape):
344 input_shape = tf.TensorShape(input_shape).as_list()
345 output_shape = list(input_shape)
346 if self.data_format == "channels_first":
347 c_axis, d_axis, h_axis, w_axis = 1, 2, 3, 4
348 else:
349 c_axis, d_axis, h_axis, w_axis = 4, 1, 2, 3
351 kernel_d, kernel_h, kernel_w = self.kernel_size
352 stride_d, stride_h, stride_w = self.strides
354 if self.output_padding is None:
355 out_pad_d = out_pad_h = out_pad_w = None
356 else:
357 out_pad_d, out_pad_h, out_pad_w = self.output_padding
359 output_shape[c_axis] = self.filters
360 output_shape[d_axis] = conv_utils.deconv_output_length(
361 output_shape[d_axis],
362 kernel_d,
363 padding=self.padding,
364 output_padding=out_pad_d,
365 stride=stride_d,
366 )
367 output_shape[h_axis] = conv_utils.deconv_output_length(
368 output_shape[h_axis],
369 kernel_h,
370 padding=self.padding,
371 output_padding=out_pad_h,
372 stride=stride_h,
373 )
374 output_shape[w_axis] = conv_utils.deconv_output_length(
375 output_shape[w_axis],
376 kernel_w,
377 padding=self.padding,
378 output_padding=out_pad_w,
379 stride=stride_w,
380 )
381 return tf.TensorShape(output_shape)
383 def get_config(self):
384 config = super().get_config()
385 config.pop("dilation_rate")
386 config["output_padding"] = self.output_padding
387 return config
390# Alias
392Convolution3DTranspose = Conv3DTranspose