🐛 [Bug] torch.fmod returns a tiny value with the wrong sign when the float quotient rounds up
Los mantenedores suelen responder en 3 días
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 70/100
Línea de trabajo
Empieza en impl.elementwise.fmod y en su auxiliar trunc_div en py/torch_tensorrt/dynamo/conversion/impl/elementwise/ops.py, y revisa cómo se redondea hacia abajo el cociente en punto flotante antes de calcular el resto. Ejecuta el script de reproducción del issue en una máquina con CUDA y compáralo con torch.fmod para 4.2 / 1.4 y el caso del ajuste de 0.1. Se considera terminado cuando los resultados de fmod en punto flotante coinciden con PyTorch en signo y valor, y el comportamiento con enteros no cambia.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Bug Description
torch.fmod(a, b) on floating point tensors returns a tiny value with the wrong sign when a / b rounds up to a whole number. In float32, torch.fmod(4.2, 1.4) is 1.3999999 in PyTorch and -1.19e-07 in Torch-TensorRT. The result of fmod always has the sign of a, so a negative result for a positive a is never right. It shows up when wrapping values by a period: fmod(x, 0.1) for x = 0.1, 0.2, ..., 10.0 differs from PyTorch for 43 of the 100 values.
impl.elementwise.fmod in py/torch_tensorrt/dynamo/conversion/impl/elementwise/ops.py computes input - trunc_div(input, other) * other, and trunc_div takes FLOOR_DIV of |input| and |other|. For floats, the division is rounded before it's floored. In float32, 4.2 / 1.4 is 2.99999991, which rounds to 3.0, so the quotient comes out as 3 instead of 2 and input - 3 * other is just below zero. PyTorch computes fmod exactly and gets 2.
torch.remainder (%) gives the right result for these inputs.
To Reproduce
import torch
import torch_tensorrt
class Fmod(torch.nn.Module):
def forward(self, a, b):
return torch.fmod(a, b)
def trt(model, *args):
return torch_tensorrt.compile(model.eval().cuda(), ir="dynamo", inputs=list(args), min_block_size=1)(*args)
a = torch.tensor([4.2, -4.2, 0.7, 5.0], device="cuda")
b = torch.tensor([1.4, 1.4, 0.1, 3.0], device="cuda")
print(Fmod()(a, b).tolist())
print(trt(Fmod(), a, b).tolist())
# Wrapping multiples of 0.1 by 0.1
x = torch.arange(1, 101, device="cuda") * 0.1
period = torch.full_like(x, 0.1)
expected, got = Fmod()(x, period), trt(Fmod(), x, period)
print((got - expected).abs().gt(1e-3).sum().item(), "of", x.numel(), "differ")
Output:
[1.3999998569488525, -1.3999998569488525, 0.09999997913837433, 2.0]
[-1.1920928955078125e-07, 1.1920928955078125e-07, -2.2351741790771484e-08, 2.0]
43 of 100 differ
Expected behavior
The same results as PyTorch, which always have the sign of a.
Environment
- Torch-TensorRT Version: 2.14.0 (pip).
fmodandtrunc_divare the same on main. - PyTorch Version: 2.14.1+cu130
- CPU Architecture: x86_64
- OS: Ubuntu 26.04 (WSL2)
- How you installed PyTorch: pip
- Python version: 3.12
- CUDA version: 13.0 (TensorRT 11.1.0.106)
- GPU models and configuration: NVIDIA GeForce RTX 5060 Ti, driver 596.49
Additional context
I found this with torchparity, a tool I'm writing that runs PyTorch ops through converters and compares the results with eager PyTorch. I have a fix with tests and can open a PR. When the result has the sign opposite to input, it adds |other| back with the sign of input. Integer inputs are unchanged.
#4786 changes trunc_div for large integers and doesn't cover this.
- Lenguaje dominante
- Python
- Estrellas
- 3k
- Forks
- 421
- Merge medio
- 4 d 7 h
- PR fusionados (30 d)
- 62
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de pytorch/TensorRT
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
Los mantenedores suelen responder en 3 días
-
Removing ptq.hAbiertoStory: Build & Install & Packaging
Dificultad 1/5 Menos de una hora Aptitud para principiantes 65/100
Los mantenedores suelen responder en 3 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 22/100
Los mantenedores suelen responder en 3 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 18/100
Los mantenedores suelen responder en 3 días
-
Dificultad 3/5 Medio día Aptitud para principiantes 65/100
Los mantenedores suelen responder en 3 días
Todos los issues de pytorch/TensorRT
Issues similares
-
add entry to blockAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 65/100
StevenBlack/hosts#3299 ·
-
`garak --report` overwrites the input report when its name has no ".report"Posiblemente ocupada @0z5a la tomó hoy. Abiertoneeds-triage
Dificultad 2/5 Medio día Aptitud para principiantes 72/100
Los mantenedores suelen responder en 2 días
-
plot_graph crashes when a mesh node has no m2m edgePosiblemente ocupada @tygvi la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
mllam/neural-lam#883 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
future-agi/future-agi#4092 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
transcript analytics: a text whose only protected spans the prose pass redacts is withheld wholeAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
WingedGuardian/GENesis-AGI#4641 ·
Los mantenedores suelen responder en 1 día