You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2022/12/02 04:50:16 UTC

[GitHub] [tvm] wrongtest-intellif commented on a diff in pull request #13530: [TOPI] Use integer arithmetic for topi.image.resize

wrongtest-intellif commented on code in PR #13530:
URL: https://github.com/apache/tvm/pull/13530#discussion_r1037783823


##########
python/tvm/topi/image/resize.py:
##########
@@ -136,71 +122,96 @@ def get_3d_pixel(data, layout, image_depth, image_height, image_width, n, c, z,
 
 
 def get_inx(
-    x,
+    target_x,
     image_width,
     target_width,
     coordinate_transformation_mode,
     start_x=0,
     end_x=-1,
-    use_int_div=False,
 ):
     """Infer input x from output x with various coordinate transformation methods"""
-    scale_x = te.div(image_width.astype("float"), target_width.astype("float"))
+
+    non_trivial_target_width = target_width > 1
+
+    def _as_fraction_or_float(expr):
+        try:
+            return Fraction(expr)
+        except ValueError:
+            return expr.astype("float")
+
+    image_width = _as_fraction_or_float(image_width)
+    target_width = _as_fraction_or_float(target_width)
+    target_x = _as_fraction_or_float(target_x)
+
+    scale_x = image_width / target_width
+
     if coordinate_transformation_mode == "half_pixel":
-        in_x = (x + 0.5) * scale_x - 0.5
+        return (target_x + 0.5) * scale_x - 0.5
     elif coordinate_transformation_mode == "align_corners":
-        in_x = (image_width - 1).astype("float") / (target_width - 1) * x
+        return (image_width - 1) / (target_width - 1) * target_x
     elif coordinate_transformation_mode == "asymmetric":
-        if use_int_div:
-            in_x = te.div(x, te.div(target_width, image_width))
-        else:
-            in_x = scale_x * x
+        return scale_x * target_x
     elif coordinate_transformation_mode == "pytorch_half_pixel":
-        in_x = te.if_then_else(target_width > 1, (x + 0.5) * scale_x - 0.5, 0.0)
+        return te.if_then_else(non_trivial_target_width, (target_x + 0.5) * scale_x - 0.5, 0.0)
     elif coordinate_transformation_mode == "tf_half_pixel_for_nn":
-        in_x = (x + 0.5) * scale_x
+        return (target_x + 0.5) * scale_x
     elif coordinate_transformation_mode == "tf_crop_and_resize":
-        in_x = te.if_then_else(
-            target_width > 1,
+        start_x = _as_fraction_or_float(start_x)
+        end_x = _as_fraction_or_float(end_x)
+        return te.if_then_else(
+            non_trivial_target_width,
             start_x * (image_width - 1)
-            + x * (end_x - start_x) * (image_width - 1).astype("float") / (target_width - 1),
+            + target_x * (end_x - start_x) * (image_width - 1) / (target_width - 1),
             0.5 * (start_x + end_x) * (image_width - 1),
         )
     else:
         raise ValueError(
             "Unsupported coordinate_transformation_mode: {}".format(coordinate_transformation_mode)
         )
-    return in_x
 
 
-def get_closest_index(in_x, rounding_method, boxes, use_int_div=False):
+def get_closest_index(in_x, rounding_method, boxes):
     """get the closest index to a value based on a certain rounding method"""
-    if use_int_div:
-        closest_x_index = in_x.astype("int32")
-        return closest_x_index
-
-    if rounding_method == "round" or boxes is not None:
-        closest_x_index = te.round(in_x).astype("int32")
-    elif rounding_method == "round_prefer_floor":
-        closest_x_index = te.ceil(in_x - 0.5).astype("int32")
-    elif rounding_method == "round_prefer_ceil":
-        closest_x_index = te.floor(in_x + 0.5).astype("int32")
-    elif rounding_method == "floor":
-        # Add epsilon to floor to prevent gpu rounding errors.
-        epsilon = 1e-5
-        closest_x_index = te.floor(in_x + epsilon).astype("int32")
-    elif rounding_method == "ceil":
-        # Subract epsilon from ceil to prevent gpu rounding errors.
-        epsilon = 1e-5
-        closest_x_index = te.ceil(in_x - epsilon).astype("int32")
+    if isinstance(in_x, Fraction):
+        # Preferred path, if the initial sizes were an integer ratio.
+
+        numerator = in_x.numerator
+        denominator = in_x.denominator
+        if rounding_method in ("round", "round_prefer_floor") or boxes is not None:
+            return (numerator + denominator // 2) // denominator
+        elif rounding_method == "round_prefer_ceil":
+            return (numerator + (denominator + 1) // 2) // denominator
+        elif rounding_method == "floor":
+            return numerator // denominator
+        elif rounding_method == "ceil":
+            return (numerator + denominator - 1) // denominator
+        else:
+            raise ValueError("Uknown rounding method: {}".format(rounding_method))
+
     else:
-        raise ValueError("Uknown rounding method: {}".format(rounding_method))
-    return closest_x_index
+        # Preferred path, using floating-point values
+
+        if rounding_method == "round" or boxes is not None:
+            return te.round(in_x).astype("int32")
+        elif rounding_method == "round_prefer_floor":
+            return te.ceil(in_x - 0.5).astype("int32")
+        elif rounding_method == "round_prefer_ceil":
+            return te.floor(in_x + 0.5).astype("int32")
+        elif rounding_method == "floor":
+            # Add epsilon to floor to prevent gpu rounding errors.
+            epsilon = 1e-5
+            return te.floor(in_x + epsilon).astype("int32")
+        elif rounding_method == "ceil":
+            # Subract epsilon from ceil to prevent gpu rounding errors.
+            epsilon = 1e-5
+            return te.ceil(in_x - epsilon).astype("int32")
+        else:
+            raise ValueError("Uknown rounding method: {}".format(rounding_method))
 
 
 def _lerp(A, B, t):
     """Perform Linear interpolation in 1D"""
-    return A * (1.0 - t) + B * t
+    return (1.0 - t) * A + t * B

Review Comment:
   Just for curiosity, why the order matters here?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@tvm.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org