Skip to content

Commit 0cd3c80

Browse files
_aten_to_core: extend replace_cat dynamic-axis promotion to handle still-dynamic siblings
The previous replace_cat fix uses ``coreai.reshape(inp, new_shape)`` with a Python list to promote a dynamic non-concat axis to its known static size before the concat. The list form materializes the shape as an ``int32`` constant tensor, so every entry must be a real int — there is no slot for the dynamic-size sentinel. When a cat input has both a promotable axis (sibling has a known static size) and an axis that is dynamic on every input (no static sibling), post-promotion ``new_shape`` is a mix of concrete ints and the dynamic sentinel; passing it to the list-form reshape raises ``OverflowError: Python integer -9223372036854775808 out of bounds for int32``. Split ``replace_cat`` into two reshape paths: - All axes static post-promotion: keep the list-form reshape. - Some axes still dynamic post-promotion: build the shape vector at runtime — ``coreai.get_shape(inp)`` for the still-dynamic axes, ``coreai.constant`` slices for the promoted axes, concat along axis 0 to get a rank-1 ``int32`` Value, and pass that to Value-form ``coreai.ReshapeOp`` with a partially-static result type. Adds a numerical regression that exercises the mixed path: a 4-D cat where one input has a sibling-promotable axis and another axis that stays dynamic on every input. Verified to fail with the list-form-only fix and pass with this delta.
1 parent 1c26f1f commit 0cd3c80

2 files changed

Lines changed: 46 additions & 1 deletion

File tree

coreai_torch/_aten_to_core.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,26 @@ def known_static(axis: int) -> int | None:
974974
for a in range(rank)
975975
]
976976
if new_shape != list(inp.type.shape):
977-
inp = coreai.reshape(inp, new_shape)
977+
if all(s != dyn for s in new_shape):
978+
# All axes static post-promotion: list-form reshape packs
979+
# the shape into an int32 constant tensor.
980+
inp = coreai.reshape(inp, new_shape)
981+
else:
982+
# Mixed static / dynamic post-promotion: build the shape
983+
# vector at runtime by mixing the input's actual sizes
984+
# (via coreai.get_shape) for the still-dynamic axes with
985+
# constants for the promoted axes.
986+
runtime_shape = coreai.cast(coreai.get_shape(inp), dtype=np.int32)
987+
parts = [
988+
coreai.constant([s], dtype=np.int32)
989+
if s != dyn
990+
else coreai.slice_(runtime_shape, [a], [a + 1], [1])
991+
for a, s in enumerate(new_shape)
992+
]
993+
result_type = RankedTensorType.get(new_shape, inp.type.element_type)
994+
inp = coreai.ReshapeOp(
995+
inp, coreai.concat(0, parts), results=[result_type]
996+
).result
978997
promoted.append(inp)
979998
inputs = promoted
980999

tests/ops/test_ops.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,32 @@ def forward(self, a: Tensor, b: Tensor) -> Tensor:
10241024
dynamic_shapes=({1: torch.export.Dim.AUTO}, {}),
10251025
)
10261026

1027+
async def test_partial_static_promotion_with_dynamic_axes(self) -> None:
1028+
"""A cat input has one non-concat axis that is statically known
1029+
via a sibling AND another non-concat axis that is dynamic on every
1030+
input. After promoting the first axis to its static size, the
1031+
second axis remains dynamic, so the lowering must build the
1032+
reshape's shape vector at runtime."""
1033+
1034+
class CatModel(nn.Module):
1035+
def forward(self, a: Tensor, b: Tensor) -> Tensor:
1036+
return torch.cat([a, b], dim=2)
1037+
1038+
a = torch.rand(2, 4, 5, 6)
1039+
b = torch.rand(2, 4, 7, 6)
1040+
# Mark dim 1 of `a` dynamic (sibling `b` has static 4 there → must be
1041+
# promoted) and dim 0 of both inputs dynamic (no static sibling →
1042+
# remains dynamic post-promotion, forcing the runtime-shape path).
1043+
await validate_numerical_output(
1044+
model=CatModel().eval(),
1045+
a=a,
1046+
b=b,
1047+
dynamic_shapes=(
1048+
{0: torch.export.Dim.AUTO, 1: torch.export.Dim.AUTO},
1049+
{0: torch.export.Dim.AUTO},
1050+
),
1051+
)
1052+
10271053

10281054
@pytest.mark.parametrize("dynamic", [False, True])
10291055
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)