Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/ops/image_grad.py: 22%

90 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"""Contains Gradient functions for image ops.""" 

16 

17from tensorflow.python.framework import dtypes 

18from tensorflow.python.framework import ops 

19from tensorflow.python.ops import array_ops 

20from tensorflow.python.ops import array_ops_stack 

21from tensorflow.python.ops import gen_image_ops 

22from tensorflow.python.ops import math_ops 

23 

24 

25@ops.RegisterGradient("ResizeNearestNeighbor") 

26def _ResizeNearestNeighborGrad(op, grad): 

27 """The derivatives for nearest neighbor resizing. 

28 

29 Args: 

30 op: The ResizeNearestNeighbor op. 

31 grad: The tensor representing the gradient w.r.t. the output. 

32 

33 Returns: 

34 The gradients w.r.t. the input and the output. 

35 """ 

36 image = op.inputs[0] 

37 if image.get_shape()[1:3].is_fully_defined(): 

38 image_shape = image.get_shape()[1:3] 

39 else: 

40 image_shape = array_ops.shape(image)[1:3] 

41 

42 grads = gen_image_ops.resize_nearest_neighbor_grad( 

43 grad, 

44 image_shape, 

45 align_corners=op.get_attr("align_corners"), 

46 half_pixel_centers=op.get_attr("half_pixel_centers")) 

47 return [grads, None] 

48 

49 

50@ops.RegisterGradient("ResizeBilinear") 

51def _ResizeBilinearGrad(op, grad): 

52 """The derivatives for bilinear resizing. 

53 

54 Args: 

55 op: The ResizeBilinear op. 

56 grad: The tensor representing the gradient w.r.t. the output. 

57 

58 Returns: 

59 The gradients w.r.t. the input. 

60 """ 

61 grad0 = gen_image_ops.resize_bilinear_grad( 

62 grad, 

63 op.inputs[0], 

64 align_corners=op.get_attr("align_corners"), 

65 half_pixel_centers=op.get_attr("half_pixel_centers")) 

66 return [grad0, None] 

67 

68 

69@ops.RegisterGradient("ScaleAndTranslate") 

70def _ScaleAndTranslateGrad(op, grad): 

71 """The derivatives for ScaleAndTranslate transformation op. 

72 

73 Args: 

74 op: The ScaleAndTranslate op. 

75 grad: The tensor representing the gradient w.r.t. the output. 

76 

77 Returns: 

78 The gradients w.r.t. the input. 

79 """ 

80 

81 grad0 = gen_image_ops.scale_and_translate_grad( 

82 grad, 

83 op.inputs[0], 

84 op.inputs[2], 

85 op.inputs[3], 

86 kernel_type=op.get_attr("kernel_type"), 

87 antialias=op.get_attr("antialias")) 

88 return [grad0, None, None, None] 

89 

90 

91@ops.RegisterGradient("ResizeBicubic") 

92def _ResizeBicubicGrad(op, grad): 

93 """The derivatives for bicubic resizing. 

94 

95 Args: 

96 op: The ResizeBicubic op. 

97 grad: The tensor representing the gradient w.r.t. the output. 

98 

99 Returns: 

100 The gradients w.r.t. the input. 

101 """ 

102 allowed_types = [dtypes.float32, dtypes.float64] 

103 grad0 = None 

104 if op.inputs[0].dtype in allowed_types: 

105 grad0 = gen_image_ops.resize_bicubic_grad( 

106 grad, 

107 op.inputs[0], 

108 align_corners=op.get_attr("align_corners"), 

109 half_pixel_centers=op.get_attr("half_pixel_centers")) 

110 return [grad0, None] 

111 

112 

113@ops.RegisterGradient("CropAndResize") 

114def _CropAndResizeGrad(op, grad): 

115 """The derivatives for crop_and_resize. 

116 

117 We back-propagate to the image only when the input image tensor has floating 

118 point dtype but we always back-propagate to the input boxes tensor. 

119 

120 Args: 

121 op: The CropAndResize op. 

122 grad: The tensor representing the gradient w.r.t. the output. 

123 

124 Returns: 

125 The gradients w.r.t. the input image, boxes, as well as the always-None 

126 gradients w.r.t. box_ind and crop_size. 

127 """ 

128 image = op.inputs[0] 

129 if image.get_shape().is_fully_defined(): 

130 image_shape = image.get_shape().as_list() 

131 else: 

132 image_shape = array_ops.shape(image) 

133 

134 allowed_types = [dtypes.float16, dtypes.float32, dtypes.float64] 

135 if op.inputs[0].dtype in allowed_types: 

136 # pylint: disable=protected-access 

137 grad0 = gen_image_ops.crop_and_resize_grad_image( 

138 grad, op.inputs[1], op.inputs[2], image_shape, T=op.get_attr("T"), 

139 method=op.get_attr("method")) 

140 # pylint: enable=protected-access 

141 else: 

142 grad0 = None 

143 

144 # `grad0` is the gradient to the input image pixels and it 

145 # has been implemented for nearest neighbor and bilinear sampling 

146 # respectively. `grad1` is the gradient to the input crop boxes' coordinates. 

147 # When using nearest neighbor sampling, the gradient to crop boxes' 

148 # coordinates are not well defined. In practice, we still approximate 

149 # grad1 using the gradient derived from bilinear sampling. 

150 grad1 = gen_image_ops.crop_and_resize_grad_boxes( 

151 grad, op.inputs[0], op.inputs[1], op.inputs[2]) 

152 

153 return [grad0, grad1, None, None] 

154 

155 

156def _CustomReciprocal(x): 

157 """Wrapper function around `math_ops.div_no_nan()` to perform a "safe" reciprocal incase the input is zero. Avoids divide by zero and NaNs. 

158 

159 Input: 

160 x -> input tensor to be reciprocat-ed. 

161 Returns: 

162 x_reciprocal -> reciprocal of x without NaNs. 

163 """ 

164 return math_ops.div_no_nan(math_ops.cast(1.0, x.dtype), x) 

165 

166 

167@ops.RegisterGradient("RGBToHSV") 

168def _RGBToHSVGrad(op, grad): 

169 """The gradients for `rgb_to_hsv` operation. 

170 

171 This function is a piecewise continuous function as defined here: 

172 https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB 

173 We perform the multivariate derivative and compute all partial derivatives 

174 separately before adding them in the end. Formulas are given before each 

175 partial derivative calculation. 

176 

177 Args: 

178 op: The `rgb_to_hsv` `Operation` that we are differentiating. 

179 grad: Gradient with respect to the output of the `rgb_to_hsv` op. 

180 

181 Returns: 

182 Gradients with respect to the input of `rgb_to_hsv`. 

183 """ 

184 # Input Channels 

185 reds = op.inputs[0][..., 0] 

186 greens = op.inputs[0][..., 1] 

187 blues = op.inputs[0][..., 2] 

188 # Output Channels 

189 saturation = op.outputs[0][..., 1] 

190 value = op.outputs[0][..., 2] 

191 

192 dtype = op.inputs[0].dtype 

193 

194 # Mask/Indicator for max and min values of each pixel. 

195 # Arbitrary assignment in case of tie breakers with R>G>B. 

196 # Max values 

197 red_biggest = math_ops.cast((reds >= blues) & \ 

198 (reds >= greens), dtype) 

199 green_biggest = math_ops.cast((greens > reds) & \ 

200 (greens >= blues), dtype) 

201 blue_biggest = math_ops.cast((blues > reds) & \ 

202 (blues > greens), dtype) 

203 # Min values 

204 red_smallest = math_ops.cast((reds < blues) & \ 

205 (reds < greens), dtype) 

206 green_smallest = math_ops.cast((greens <= reds) & \ 

207 (greens < blues), dtype) 

208 blue_smallest = math_ops.cast((blues <= reds) & \ 

209 (blues <= greens), dtype) 

210 

211 # Derivatives of R, G, B wrt Value slice 

212 dv_dr = red_biggest 

213 dv_dg = green_biggest 

214 dv_db = blue_biggest 

215 

216 # Derivatives of R, G, B wrt Saturation slice 

217 

218 # The first term in the addition is the case when the corresponding color 

219 # from (r,g,b) was "MAX" 

220 # -> derivative = MIN/square(MAX), MIN could be one of the other two colors 

221 # The second term is the case when the corresponding color from 

222 # (r,g,b) was "MIN" 

223 # -> derivative = -1/MAX, MAX could be one of the other two colours. 

224 ds_dr = math_ops.cast(reds > 0, dtype) * math_ops.add( 

225 red_biggest * math_ops.add(green_smallest * greens, blue_smallest * blues) 

226 * _CustomReciprocal(math_ops.square(reds)), red_smallest * -1 * 

227 _CustomReciprocal((green_biggest * greens) + (blue_biggest * blues))) 

228 ds_dg = math_ops.cast(greens > 0, dtype) * math_ops.add( 

229 green_biggest * math_ops.add(red_smallest * reds, blue_smallest * blues) * 

230 _CustomReciprocal(math_ops.square(greens)), green_smallest * -1 * 

231 _CustomReciprocal((red_biggest * reds) + (blue_biggest * blues))) 

232 ds_db = math_ops.cast(blues > 0, dtype) * math_ops.add( 

233 blue_biggest * math_ops.add(green_smallest * greens, red_smallest * reds) 

234 * _CustomReciprocal(math_ops.square(blues)), blue_smallest * -1 * 

235 _CustomReciprocal((green_biggest * greens) + (red_biggest * reds))) 

236 

237 # Derivatives of R, G, B wrt Hue slice 

238 

239 # Need to go case by case for each color. 

240 # for red, dh_dr -> dh_dr_1 + dh_dr_2 + dh_dr_3 + dh_dr_4 + dh_dr_5 

241 # dh_dr_1 -> 

242 # if red was MAX, then derivative = 60 * -1 * (G-B)/square(MAX-MIN) == 60 *\ 

243 # -1 * (greens-blues) * reciprocal(square(saturation)) * \ 

244 # reciprocal(square(value)) 

245 # elif green was MAX, there are two subcases 

246 # ie when red was MIN and when red was NOT MIN 

247 # dh_dr_2 -> 

248 # if red was MIN (use UV rule) -> 60 * ((1 * -1/(MAX-MIN)) +\ 

249 # (B-R)*(-1/square(MAX-MIN) * -1)) == 60 * (blues - greens) *\ 

250 # reciprocal(square(reds - greens)) 

251 # dh_dr_3 -> 

252 # if red was NOT MIN -> 60 * -1/MAX-MIN == -60 * reciprocal(greens-blues) 

253 # elif blue was MAX, there are two subcases 

254 # dh_dr_4 -> 

255 # if red was MIN (similarly use the UV rule) -> 60 * (blues - greens) *\ 

256 # reciprocal(square(blues - reds)) 

257 # dh_dr_5 -> 

258 # if red was NOT MIN -> 60 * 1/MAX-MIN == 60 * reciprocal(blues-greens) 

259 dh_dr_1 = 60 * ( 

260 math_ops.cast(reds > 0, dtype) * red_biggest * -1 * 

261 (greens - blues) * _CustomReciprocal(math_ops.square(saturation)) * 

262 _CustomReciprocal(math_ops.square(value))) 

263 dh_dr_2 = 60 * ( 

264 math_ops.cast(greens > 0, dtype) * green_biggest * red_smallest * 

265 (blues - greens) * _CustomReciprocal(math_ops.square(reds - greens))) 

266 dh_dr_3 = 60 * ( 

267 math_ops.cast(greens > 0, dtype) * green_biggest * blue_smallest * -1 * 

268 _CustomReciprocal(greens - blues)) 

269 dh_dr_4 = 60 * ( 

270 math_ops.cast(blues > 0, dtype) * blue_biggest * red_smallest * 

271 (blues - greens) * _CustomReciprocal(math_ops.square(blues - reds))) 

272 dh_dr_5 = 60 * ( 

273 math_ops.cast(blues > 0, dtype) * blue_biggest * green_smallest * 

274 _CustomReciprocal(blues - greens)) 

275 

276 dh_dr = dh_dr_1 + dh_dr_2 + dh_dr_3 + dh_dr_4 + dh_dr_5 

277 # Converting from degrees to [0,1] scale as specified in 

278 # https://www.tensorflow.org/api_docs/python/tf/image/rgb_to_hsv 

279 dh_dr = dh_dr / 360 

280 

281 # for green, dh_dg -> dh_dg_1 + dh_dg_2 + dh_dg_3 + dh_dg_4 + dh_dg_5 

282 # dh_dg_1 -> 

283 # if green was MAX, then derivative = 60 * -1 * (B-R)/square(MAX-MIN) == 60 *\ 

284 # -1 * (blues - reds) * reciprocal(square(saturation)) * \ 

285 # reciprocal(square(value)) 

286 # elif red was MAX, there are two subcases ie 

287 # when green was MIN and when green was NOT MIN 

288 # dh_dg_2 -> 

289 # if green was MIN (use UV rule) -> 60 * ((1 * 1/(MAX-MIN)) + \ 

290 # (greens-blues) * (-1/square(MAX-MIN) * -1)) == 60 * \ 

291 # ((reciprocal(reds-greens) + (greens-blues) * \ 

292 # reciprocal(square(reds-greens)))) 

293 # dh_dg_3 -> 

294 # if green was NOT MIN -> 60 * 1/MAX-MIN == 60 * reciprocal(reds - blues) 

295 # elif blue was MAX, there are two subcases 

296 # dh_dg_4 -> 

297 # if green was MIN (similarly use the UV rule) -> 60 * -1 * \ 

298 # (reciprocal(blues - greens) + (reds-greens)* -1 * \ 

299 # reciprocal(square(blues-greens))) 

300 # dh_dr_5 -> 

301 # if green was NOT MIN -> 60 * -1/MAX-MIN == -60 * reciprocal(blues - reds) 

302 dh_dg_1 = 60 * ( 

303 math_ops.cast(greens > 0, dtype) * green_biggest * -1 * 

304 (blues - reds) * _CustomReciprocal(math_ops.square(saturation)) * 

305 _CustomReciprocal(math_ops.square(value))) 

306 dh_dg_2 = 60 * ( 

307 math_ops.cast(reds > 0, dtype) * red_biggest * green_smallest * 

308 (reds - blues) * _CustomReciprocal(math_ops.square(reds - greens))) 

309 dh_dg_3 = 60 * ( 

310 math_ops.cast(reds > 0, dtype) * red_biggest * blue_smallest * 

311 _CustomReciprocal(reds - blues)) 

312 dh_dg_4 = 60 * ( 

313 math_ops.cast(blues > 0, dtype) * blue_biggest * green_smallest * 

314 (reds - blues) * _CustomReciprocal(math_ops.square(blues - greens))) 

315 dh_dg_5 = 60 * ( 

316 math_ops.cast(blues > 0, dtype) * blue_biggest * red_smallest * -1 * 

317 _CustomReciprocal(blues - reds)) 

318 

319 dh_dg = dh_dg_1 + dh_dg_2 + dh_dg_3 + dh_dg_4 + dh_dg_5 

320 # Converting from degrees to [0,1] scale as specified in 

321 # https://www.tensorflow.org/api_docs/python/tf/image/rgb_to_hsv 

322 dh_dg = dh_dg / 360 

323 

324 # for blue, dh_db -> dh_db_1 + dh_db_2 + dh_db_3 + dh_db_4 + dh_db_5 

325 # dh_db_1 -> 

326 # if blue was MAX, then derivative = 60 * -1 * (R-G)/square(MAX-MIN) == 60 *\ 

327 # -1 * reciprocal(square(saturation)) * reciprocal(square(value)) 

328 # elif red was MAX, there are two subcases 

329 # ie when blue was MIN and when blue was NOT MIN 

330 # dh_dg_2 -> 

331 # if blue was MIN (use UV rule) -> 60 * ((1 * -1/(MAX-MIN)) + \ 

332 # (greens-blues) * (-1/square(MAX-MIN) * -1)) == 60 * (greens - reds) *\ 

333 # reciprocal(square(reds - blues)) 

334 # dh_dg_3 -> 

335 # if blue was NOT MIN -> 60 * -1/MAX-MIN == 60 * -1 * \ 

336 # reciprocal(reds - greens) 

337 # elif green was MAX, there are two subcases 

338 # dh_dg_4 -> 

339 # if blue was MIN (similarly use the UV rule) -> 60 * -1 * \ 

340 # (reciprocal(greens - blues) + (blues - reds) * -1 * \ 

341 # reciprocal(square(greens - blues))) 

342 # dh_dr_5 -> 

343 # if blue was NOT MIN -> 60 * 1/MAX-MIN == 60 * reciprocal(greens - reds) 

344 dh_db_1 = 60 * ( 

345 math_ops.cast(blues > 0, dtype) * blue_biggest * -1 * 

346 (reds - greens) * _CustomReciprocal(math_ops.square(saturation)) * 

347 _CustomReciprocal(math_ops.square(value))) 

348 dh_db_2 = 60 * ( 

349 math_ops.cast(reds > 0, dtype) * red_biggest * blue_smallest * 

350 (greens - reds) * _CustomReciprocal(math_ops.square(reds - blues))) 

351 dh_db_3 = 60 * ( 

352 math_ops.cast(reds > 0, dtype) * red_biggest * green_smallest * -1 * 

353 _CustomReciprocal(reds - greens)) 

354 dh_db_4 = 60 * ( 

355 math_ops.cast(greens > 0, dtype) * green_biggest * blue_smallest * 

356 (greens - reds) * _CustomReciprocal(math_ops.square(greens - blues))) 

357 dh_db_5 = 60 * ( 

358 math_ops.cast(greens > 0, dtype) * green_biggest * red_smallest * 

359 _CustomReciprocal(greens - reds)) 

360 

361 dh_db = dh_db_1 + dh_db_2 + dh_db_3 + dh_db_4 + dh_db_5 

362 # Converting from degrees to [0,1] scale as specified in 

363 # https://www.tensorflow.org/api_docs/python/tf/image/rgb_to_hsv 

364 dh_db = dh_db / 360 

365 

366 # Gradients wrt to inputs 

367 dv_drgb = array_ops_stack.stack( 

368 [grad[..., 2] * dv_dr, grad[..., 2] * dv_dg, grad[..., 2] * dv_db], 

369 axis=-1) 

370 ds_drgb = array_ops_stack.stack( 

371 [grad[..., 1] * ds_dr, grad[..., 1] * ds_dg, grad[..., 1] * ds_db], 

372 axis=-1) 

373 dh_drgb = array_ops_stack.stack( 

374 [grad[..., 0] * dh_dr, grad[..., 0] * dh_dg, grad[..., 0] * dh_db], 

375 axis=-1) 

376 

377 gradient_input = math_ops.add(math_ops.add(dv_drgb, ds_drgb), dh_drgb) 

378 return gradient_input