fix(NeighborhoodAttention): correct axis bound in neighborhood clamp mask#1
Open
qiaozhijian wants to merge 1 commit into
Open
Conversation
…mask split() returns (t, h_row, w_col), but mask_mod clamped h_row with the width upper bound (cw-1-kw2) and w_col with the height upper bound (ch-1-kh2) — the axis bounds were swapped. Latent under square training (ch==cw makes the two bounds equal); on non-square grids (ch!=cw) the width-direction columns get clamped to the height upper bound, corrupting the neighborhood mask on the wider half of the image. Fix: clamp each axis with its own bound. Rename qx/qy -> qh/qw for clarity. Behavior unchanged for square grids. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
NeighborhoodAttention._make_maskhas a latent bug in themask_modneighborhood clamp: the per-axis upper bounds for the height and width axes are swapped.split()returns(t, h_row, w_col)(row-major:rem // cwis the row/height index,rem % cwis the column/width index). Butmask_modclamped:qx) with the width upper boundcw - 1 - kw2, andqy) with the height upper boundch - 1 - kh2.Each axis's neighborhood boundary clamp must use its own axis size. The bounds were bound to the wrong axes.
This is latent because the model is trained/evaluated on square grids (
ch == cw), where the two upper bounds are equal and the swap is elementwise-identical — so the bug never surfaces. On non-square grids (ch != cw, e.g. 16:9 → 18×32 latent), the width-direction columns get clamped to the height upper bound, corrupting the neighborhood mask on the wider half of the image.Reproduction
Non-square grid
ct,ch,cw = 1,18,32(i.e. 288×512 / 16), kernel(1,7,7). Right-edge queryq_idx = 31(h_row=0, w_col=31), list thew_cols it attends to:attended w_cols: [11, 12, 13, 14, 15, 16, 17]— a right-edge query attends to the middle columns (clamped to the height bound 14). Wrong.attended w_cols: [25, 26, 27, 28, 29, 30, 31]— right-edge query attends the right-edge columns (clamped tocw-1-kw2 = 28). Correct.Square-grid equivalence
For square grids the fix is provably a no-op. Verified by comparing the old vs new
mask_modoutput for all(q_idx, kv_idx)pairs onch=cw ∈ {16, 18, 32}:So existing square-resolution checkpoints/behavior are unaffected.
Fix
Clamp each axis with its own bound; rename
qx/qy→qh/qw(andkx/ky→kh_/kw_) for clarity.Only this one function is touched.
Made with Cursor