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

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

16 

17 

18import tensorflow.compat.v2 as tf 

19 

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 

29 

30# isort: off 

31from tensorflow.python.util.tf_export import keras_export 

32 

33 

34@keras_export( 

35 "keras.layers.Conv2DTranspose", "keras.layers.Convolution2DTranspose" 

36) 

37class Conv2DTranspose(Conv2D): 

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

39 

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. 

46 

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

52 

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

111 

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

117 

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

133 

134 Returns: 

135 A tensor of rank 4 representing 

136 `activation(conv2dtranspose(inputs, kernel) + bias)`. 

137 

138 Raises: 

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

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

141 

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

148 

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 ) 

188 

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 ) 

201 

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) 

221 

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 

244 

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 

252 

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] 

264 

265 kernel_h, kernel_w = self.kernel_size 

266 stride_h, stride_w = self.strides 

267 

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 

272 

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) 

294 

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 ) 

305 

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) 

310 

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 ) 

319 

320 if self.activation is not None: 

321 return self.activation(outputs) 

322 return outputs 

323 

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 

331 

332 kernel_h, kernel_w = self.kernel_size 

333 stride_h, stride_w = self.strides 

334 

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 

339 

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) 

358 

359 def get_config(self): 

360 config = super().get_config() 

361 config["output_padding"] = self.output_padding 

362 return config 

363 

364 

365# Alias 

366 

367Convolution2DTranspose = Conv2DTranspose 

368