tlopex commented on code in PR #20135:
URL: https://github.com/apache/tvm/pull/20135#discussion_r3858795108


##########
python/tvm/relax/frontend/torch/base_fx_graph_translator.py:
##########
@@ -572,23 +572,69 @@ def call_binary_op(op, lhs, rhs):
 
     def _pow(self, node: fx.Node) -> relax.Var:
         lhs, rhs = self.retrieve_args(node)
-        # torch integer pow returns an integer tensor, but relax.op.power 
legalizes to
-        # TOPI power which requires floating-point inputs. Decompose an 
integer base with
-        # a constant non-negative integer exponent into repeated 
multiplication instead.
-        if (
-            isinstance(lhs, relax.Expr)
-            and isinstance(lhs.ty, relax.TensorType)
-            and lhs.ty.dtype.matches_code(DataTypeCode.INT, DataTypeCode.UINT)
-            and isinstance(rhs, int)
-            and not isinstance(rhs, bool)
-            and rhs >= 0
-        ):
-            if rhs == 0:
-                return self.block_builder.emit(relax.op.ones_like(lhs))
-            result = lhs
-            for _ in range(rhs - 1):
-                result = self.block_builder.emit(relax.op.multiply(result, 
lhs))
-            return result
+        if isinstance(lhs, relax.Expr) and isinstance(lhs.ty, 
relax.TensorType):
+            lhs_dtype = lhs.ty.dtype
+            is_integer_base = lhs_dtype.matches_code(DataTypeCode.INT, 
DataTypeCode.UINT)
+            is_float_base = lhs_dtype.matches_code(DataTypeCode.FLOAT, 
DataTypeCode.BFLOAT)
+
+            # A Python float promotes an integer tensor to PyTorch's default 
floating-point
+            # dtype. ExportedProgram records the inferred dtype, while plain 
FX does not.
+            if is_integer_base and isinstance(rhs, float):
+                output_meta = node.meta.get("val")
+                output_dtype = self._convert_data_type(
+                    output_meta.dtype
+                    if isinstance(output_meta, self.torch.Tensor)
+                    else self.torch.get_default_dtype()
+                )
+                lhs = self.block_builder.emit(relax.op.astype(lhs, 
output_dtype))
+                lhs_dtype = lhs.ty.dtype
+                is_integer_base = False
+                is_float_base = True
+
+            # Match the scalar conversion used by PyTorch's floating-point 
power kernels.
+            exponent_dtype = {
+                "float16": self.torch.float16,
+                "bfloat16": self.torch.bfloat16,
+                "float32": self.torch.float64,
+                "float64": self.torch.float64,
+            }.get(str(lhs_dtype))
+            if (
+                is_float_base
+                and exponent_dtype is not None
+                and isinstance(rhs, int | float)
+                and not isinstance(rhs, bool)
+            ):
+                rhs = self.torch.scalar_tensor(rhs, dtype=exponent_dtype, 
device="cpu").item()
+
+            is_nonnegative_integral_exponent = (
+                isinstance(rhs, int) and not isinstance(rhs, bool) and rhs >= 0
+            ) or (isinstance(rhs, float) and rhs >= 0 and rhs.is_integer())
+
+            # TOPI power requires floating-point inputs, and some backends do 
not preserve
+            # the sign of a negative base for integral exponents. Decompose 
after applying
+            # PyTorch's dtype promotion so Python integer and float scalars 
behave alike.
+            if (is_integer_base or is_float_base) and 
is_nonnegative_integral_exponent:
+                exponent = int(rhs)
+                if exponent == 0:
+                    return self.block_builder.emit(relax.op.ones_like(lhs))
+
+                # Exponentiation by squaring avoids linear graph growth for 
large exponents.

Review Comment:
   The dtype and exponent-conversion handling looks reasonable, but decomposing 
floating-point `pow` into repeated multiplications changes PyTorch’s numerical 
semantics because every intermediate `float16`/`bfloat16` multiplication is 
rounded. e.g. `float16(0.361) ** 17` is nonzero in PyTorch but becomes zero in 
TVM, while `bfloat16(1.1) ** 100` produces `15872` in PyTorch and `14848` in 
TVM. Please preserve the `pow` kernel’s effective precision when fixing 
negative-base behavior and add numerical tests with nontrivial low-precision 
inputs; the current `-1` tests only verify exponent parity.



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to