Skip to content

Fix SparseDenseMultiply gradient when the dense input is a scalar - #2319

Open
Sanjays2402 wants to merge 2 commits into
pymc-devs:mainfrom
Sanjays2402:fix/mulsd-scalar-grad
Open

Fix SparseDenseMultiply gradient when the dense input is a scalar#2319
Sanjays2402 wants to merge 2 commits into
pymc-devs:mainfrom
Sanjays2402:fix/mulsd-scalar-grad

Conversation

@Sanjays2402

Copy link
Copy Markdown

Description

SparseDenseMultiply.pullback returned the full dense gradient for its second input, but when that input is a scalar it was broadcast over every entry of the sparse matrix, so its gradient must be a scalar. pt.grad rejected the 2-d term with ValueError: SparseDenseMultiply.grad returned a term with 2 dimensions, but 0 are required. The gradient is now summed when the dense input is 0-d; the 2-d case is unchanged.

Related Issue

Checklist

Type of change

  • New feature / enhancement
  • Bug fix
  • Documentation
  • Maintenance
  • Other (please specify):

test_MulSD_scalar_grad (csc and csr) fails on main with the reported ValueError and passes with the fix. This change was prepared with AI assistance; the regression test was run locally and fails without the fix.

…calar

Multiplying a sparse matrix by a scalar broadcasts the scalar over every
entry, but SparseDenseMultiply.pullback returned the full dense gradient
for the second input. pt.grad then rejected it with

    ValueError: SparseDenseMultiply.grad returned a term with 2
    dimensions, but 0 are required.

Sum the contributions when the dense input is 0-d so the gradient has the
same number of dimensions as the input. Adds a regression test in
tests/sparse/test_math.py covering both csc and csr.

Closes pymc-devs#1338
Comment thread pytensor/sparse/math.py Outdated
if y.type.ndim == 0:
# y was broadcast against every entry of x, so its gradient is the
# sum of the contributions of all entries.
gy = gy.sum()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

do we have a sparse sum we should use instead of summing on the dense?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes — sp_sum handles it, switched to that in 3fdf0ae:

if y.type.ndim == 0:
    gy = sp_sum(x * gz, sparse_grad=True)
else:
    gy = psb.dense_from_sparse(x * gz)

x * gz is sparse, so the previous version densified an M x N array only to reduce it to a scalar. sp_sum(..., sparse_grad=True) reduces over x.data directly and its own grad stays structured, which matches what SparseDenseVectorMultiply.pullback already does one class down (sp_sum(x * gz, axis=0, sparse_grad=True)).

test_MulSD_scalar_grad still fails on the unpatched pullback with the original ValueError: ... returned a term with 2 dimensions, but 0 are required and passes with this. tests/sparse/test_math.py is 63 passed, 6 xfailed.

@ricardoV94 ricardoV94 added bug Something isn't working gradients sparse variables labels Aug 2, 2026
@ricardoV94

Copy link
Copy Markdown
Member

Thanks

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sparse MulSD Op gradient raises when dense is scalar

2 participants