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

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).""" 

16 

17 

18import tensorflow.compat.v2 as tf 

19 

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 

28 

29# isort: off 

30from tensorflow.python.util.tf_export import keras_export 

31 

32 

33@keras_export( 

34 "keras.layers.Conv3DTranspose", "keras.layers.Convolution3DTranspose" 

35) 

36class Conv3DTranspose(Conv3D): 

37 """Transposed convolution layer (sometimes called Deconvolution). 

38 

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. 

45 

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"`. 

51 

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`). 

114 

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'. 

122 

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 ``` 

140 

141 Returns: 

142 A tensor of rank 5 representing 

143 `activation(conv3dtranspose(inputs, kernel) + bias)`. 

144 

145 Raises: 

146 ValueError: if `padding` is "causal". 

147 ValueError: when both `strides` > 1 and `dilation_rate` > 1. 

148 

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 """ 

155 

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 ) 

195 

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 ) 

208 

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}) 

228 

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 

251 

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 

259 

260 depth = inputs_shape[d_axis] 

261 height = inputs_shape[h_axis] 

262 width = inputs_shape[w_axis] 

263 

264 kernel_d, kernel_h, kernel_w = self.kernel_size 

265 stride_d, stride_h, stride_w = self.strides 

266 

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 

271 

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) 

312 

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 ) 

324 

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) 

329 

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 ) 

338 

339 if self.activation is not None: 

340 return self.activation(outputs) 

341 return outputs 

342 

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 

350 

351 kernel_d, kernel_h, kernel_w = self.kernel_size 

352 stride_d, stride_h, stride_w = self.strides 

353 

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 

358 

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) 

382 

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 

388 

389 

390# Alias 

391 

392Convolution3DTranspose = Conv3DTranspose 

393