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
« 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."""
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
25@ops.RegisterGradient("ResizeNearestNeighbor")
26def _ResizeNearestNeighborGrad(op, grad):
27 """The derivatives for nearest neighbor resizing.
29 Args:
30 op: The ResizeNearestNeighbor op.
31 grad: The tensor representing the gradient w.r.t. the output.
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]
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]
50@ops.RegisterGradient("ResizeBilinear")
51def _ResizeBilinearGrad(op, grad):
52 """The derivatives for bilinear resizing.
54 Args:
55 op: The ResizeBilinear op.
56 grad: The tensor representing the gradient w.r.t. the output.
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]
69@ops.RegisterGradient("ScaleAndTranslate")
70def _ScaleAndTranslateGrad(op, grad):
71 """The derivatives for ScaleAndTranslate transformation op.
73 Args:
74 op: The ScaleAndTranslate op.
75 grad: The tensor representing the gradient w.r.t. the output.
77 Returns:
78 The gradients w.r.t. the input.
79 """
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]
91@ops.RegisterGradient("ResizeBicubic")
92def _ResizeBicubicGrad(op, grad):
93 """The derivatives for bicubic resizing.
95 Args:
96 op: The ResizeBicubic op.
97 grad: The tensor representing the gradient w.r.t. the output.
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]
113@ops.RegisterGradient("CropAndResize")
114def _CropAndResizeGrad(op, grad):
115 """The derivatives for crop_and_resize.
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.
120 Args:
121 op: The CropAndResize op.
122 grad: The tensor representing the gradient w.r.t. the output.
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)
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
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])
153 return [grad0, grad1, None, None]
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.
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)
167@ops.RegisterGradient("RGBToHSV")
168def _RGBToHSVGrad(op, grad):
169 """The gradients for `rgb_to_hsv` operation.
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.
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.
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]
192 dtype = op.inputs[0].dtype
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)
211 # Derivatives of R, G, B wrt Value slice
212 dv_dr = red_biggest
213 dv_dg = green_biggest
214 dv_db = blue_biggest
216 # Derivatives of R, G, B wrt Saturation slice
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)))
237 # Derivatives of R, G, B wrt Hue slice
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))
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
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))
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
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))
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
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)
377 gradient_input = math_ops.add(math_ops.add(dv_drgb, ds_drgb), dh_drgb)
378 return gradient_input