Skip to content

Commit 1eb5cbb

Browse files
committed
[Relax][Frontend][Torch] Clamp diagonal length to zero for out-of-range offsets
For an out-of-range offset (|offset| >= max(extent1, extent2)), PyTorch's torch.diagonal returns an empty diagonal of shape (0,). The lowering computed diag_len = min(extent1, extent2 - offset), which could go negative: e.g. a (3, 4) input with offset=5 gave diag_len=-1 and incompatible slice extents (the einsum then failed to broadcast extents 2 and 0), and offset=6 even produced an incorrect non-empty shape. Clamp diag_len with tirx.max(0, ...) in both the positive- and negative-offset branches so an out-of-range offset lowers to an empty diagonal, matching PyTorch. Add in-tree regression coverage for out-of-range positive and negative offsets.
1 parent d519b97 commit 1eb5cbb

2 files changed

Lines changed: 17 additions & 2 deletions

File tree

python/tvm/relax/frontend/torch/base_fx_graph_translator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,11 +1302,11 @@ def _diagonal(self, node: fx.Node) -> relax.Var:
13021302
n = shape.values[dim1]
13031303
m = shape.values[dim2]
13041304
if offset >= 0:
1305-
diag_len = tirx.min(n, m - offset)
1305+
diag_len = tirx.max(0, tirx.min(n, m - offset))
13061306
begin1, end1 = 0, diag_len
13071307
begin2, end2 = offset, offset + diag_len
13081308
else:
1309-
diag_len = tirx.min(n + offset, m)
1309+
diag_len = tirx.max(0, tirx.min(n + offset, m))
13101310
begin1, end1 = -offset, -offset + diag_len
13111311
begin2, end2 = 0, diag_len
13121312

tests/python/relax/test_frontend_from_exported_program.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,6 +3399,21 @@ def forward(self, x):
33993399
verify_model_numerically(DirectDiagonal(), (torch.randn(3, 4),))
34003400
verify_model_numerically(DirectTrace(), (torch.randn(4, 4),))
34013401

3402+
# Out-of-range offsets (|offset| >= max(extent1, extent2)) are valid in
3403+
# PyTorch and yield an empty diagonal of shape (0,); the lowering must
3404+
# clamp the diagonal length to zero instead of producing negative slice
3405+
# extents or a wrong non-empty shape.
3406+
class DirectDiagonalOutOfRange(Module):
3407+
def __init__(self, offset):
3408+
super().__init__()
3409+
self.offset = offset
3410+
3411+
def forward(self, x):
3412+
return torch.diagonal(x, self.offset, 0, 1)
3413+
3414+
for offset in [4, 5, 6, -3, -4, -5, -6]:
3415+
verify_model_numerically(DirectDiagonalOutOfRange(offset), (torch.randn(3, 4),))
3416+
34023417

34033418
def test_outer():
34043419
class Outer(torch.nn.Module):

0 commit comments

Comments
 (0)