Skip to content

Fix Cat and Stack reading the layout only from the first input - #6479

Open
rootkiller6788 wants to merge 4 commits into
NVIDIA:mainfrom
rootkiller6788:fix-join-layout-from-each-input
Open

Fix Cat and Stack reading the layout only from the first input#6479
rootkiller6788 wants to merge 4 commits into
NVIDIA:mainfrom
rootkiller6788:fix-join-layout-from-each-input

Conversation

@rootkiller6788

Copy link
Copy Markdown

Cat and Stack only looked at the first input when deciding the output layout. GetInputLayout loops over every input but grabbed input 0 in each iteration, which meant:

  • when the first input had no layout and a later one did, the layout was dropped (Cat) or the op raised a misleading "requires a non-empty input layout" error (Stack with axis_name);
  • two non-empty layouts that disagreed were accepted silently instead of raising the documented "All non-empty input layouts must match" error.

The change makes the loop read input i instead of input 0. I added tests covering a layout carried only by the second input (for both Cat and Stack) and the conflicting-layout error path.

The loop in TensorJoin::GetInputLayout was meant to go over all inputs, but it fetched input 0 every iteration. As a result a layout carried only by a later input was dropped, and two non-empty layouts that disagreed were never flagged.
Covers a layout that lives only on the second input for both Cat and Stack, and conflicting non-empty layouts being rejected with an error.
@copy-pr-bot

copy-pr-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@greptile-apps

greptile-apps Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

The production fix appears correct, but the PR is not ready to merge because the new regression tests fail before constructing a pipeline.

Findings

  1. P1 Pipeline factory is not invoked
  2. P2 Zip can silently truncate

Summary

  • Changes GetInputLayout to inspect input i rather than repeatedly inspecting input zero.
  • Adds CPU and GPU coverage for layouts supplied by later inputs.
  • Adds reference-based coverage for empty, boundary, single-sample, negative-axis, and conflicting-layout cases.
  • Refactors the tests to use @pipeline_def, but currently returns the decorated factory without constructing the pipeline.

Reviews (2) · Last reviewed commit: "Cover more cases in the new join tests"

Comment thread dali/test/python/operator_1/test_join.py Outdated
Comment thread dali/test/python/operator_1/test_join.py Outdated
@JanuszL

JanuszL commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

@rootkiller6788 thank you for your contribution. Can you please check Greptile review comments?

The first version used the old Pipeline context manager and set_outputs, which the repo asks new tests to avoid. Rewrote them around a small helper that builds the pipeline, so the upcoming cases are easy to add.

Signed-off-by: rootkiller6788 <c8688rickowens@outlook.com>
Single-sample batches, a 1x1 and an empty sample, plus a negative axis for Cat. The layout conflict is now checked on both devices, and for Stack as well - that one only looks at the input layouts when axis_name is given, so it needs the name set to be covered at all.

Signed-off-by: rootkiller6788 <c8688rickowens@outlook.com>
outputs.append(op(*operands, **kwargs))
return tuple(outputs)

return join_pipeline

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Pipeline factory is not invoked

_join_pipeline returns the function produced by @pipeline_def, but callers treat it as a constructed pipeline and call pipe.run(). Because the decorated function must first be invoked, these tests raise AttributeError: 'function' object has no attribute 'run' before exercising Cat or Stack.

Suggested change
return join_pipeline
return join_pipeline()

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

def join_pipeline():
inputs = [
_layout_input(shape, value, batch_size, layout)
for value, layout in zip(values, layouts)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Zip can silently truncate

This loop assumes values and layouts have equal lengths but uses plain zip, which can silently omit inputs if the lengths diverge. The repository directive requires strict=True when paired sequences are expected to have equal cardinality, and that requirement must be satisfied before merging.

Suggested change
for value, layout in zip(values, layouts)
for value, layout in zip(values, layouts, strict=True)

Rule Used: Use zip(a, b, strict=True) (Python 3.10+) when i... (source)

@rootkiller6788

Copy link
Copy Markdown
Author

Thanks for the review — both points are addressed. The new tests now build their pipelines with @pipeline_def rather than the legacy Pipeline + set_outputs (473711a). The follow-up commit expands coverage: single-sample batches, the smallest non-empty 1×1 sample, an empty sample, and a negative axis at the edge of Cat's accepted range. The layout-conflict check now runs on both CPU and GPU, and for Stack too — Stack only inspects input layouts when axis_name is given, so the name must be set for that path to be exercised at all. Both files pass black and flake8.

outputs.append(op(*operands, **kwargs))
return tuple(outputs)

return join_pipeline

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] _join_pipeline returns join_pipeline — the function object produced by @pipeline_def — not a constructed Pipeline. Per pipeline_def's own docstring, the decorated function must be called to get a Pipeline (pipe = my_pipe(...)). Every caller here does pipe = _join_pipeline(...) then pipe.run(), so all four new tests (test_cat_layout_from_any_input, test_stack_layout_from_any_input, test_cat_layout_mismatch, test_stack_layout_mismatch) fail immediately with AttributeError: 'function' object has no attribute 'run' before touching Cat or Stack. Confirmed independently of Greptile's suggestion below — same fix: return join_pipeline().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants