Skip to content

pm.Data breaks broadcasting of different shapes #4967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
paw-lu opened this issue Aug 24, 2021 · 4 comments · Fixed by #5098
Closed

pm.Data breaks broadcasting of different shapes #4967

paw-lu opened this issue Aug 24, 2021 · 4 comments · Fixed by #5098

Comments

@paw-lu
Copy link
Contributor

paw-lu commented Aug 24, 2021

Description of your problem

Typically when you add shapes that are mismatched, broadcasting is expected.

# Numpy example of expected broadcasting
>>> np.array([[1, 2]]) + np.array([[1], [2]])
array([[2, 3],
       [3, 4]])

This works as expected when inputting a numpy array, but when fed through via pm.Data, the broadcasting does not work as expected, and raises an exception on the mismatched shapes.

Please provide a minimal, self-contained, and reproducible example.

"""This works!"""
import numpy as np
import pymc3 as pm

raw_data = np.array([[1], [2], [3]])

with pm.Model() as model:
    val = pm.Normal("val", mu=0, sd=10, shape=(1, 2))
    pm.Deterministic("add", var=val + raw_data)
"""This does not work!"""
import numpy as np
import pymc3 as pm

raw_data = np.array([[1], [2], [3]])

with pm.Model() as model:
    val = pm.Normal("val", mu=0, sd=10, shape=(1, 2))
    data = pm.Data("data", raw_data)  # New line
    pm.Deterministic("add", var=val + data)

Please provide the full traceback.

Complete error traceback
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-231-ccd5d08fd0d4> in <module>
      4     val = pm.Normal("val", mu=0, sd=10, shape=(1, 2))
      5     data = pm.Data("data", raw_data)
----> 6     pm.Deterministic("add", var=val + data)

~/.cache/pypoetry/virtualenvs/time-series-demand-5LaNRWUQ-py3.9/lib/python3.9/site-packages/theano/tensor/var.py in __add__(self, other)
     99     def __add__(self, other):
    100         try:
--> 101             return theano.tensor.basic.add(self, other)
    102         # We should catch the minimum number of exception here.
    103         # Otherwise this will convert error when Theano flags

~/.cache/pypoetry/virtualenvs/time-series-demand-5LaNRWUQ-py3.9/lib/python3.9/site-packages/theano/graph/op.py in __call__(self, *inputs, **kwargs)
    251 
    252         if config.compute_test_value != "off":
--> 253             compute_test_value(node)
    254 
    255         if self.default_output is not None:

~/.cache/pypoetry/virtualenvs/time-series-demand-5LaNRWUQ-py3.9/lib/python3.9/site-packages/theano/graph/op.py in compute_test_value(node)
    128     thunk.outputs = [storage_map[v] for v in node.outputs]
    129 
--> 130     required = thunk()
    131     assert not required  # We provided all inputs
    132 

~/.cache/pypoetry/virtualenvs/time-series-demand-5LaNRWUQ-py3.9/lib/python3.9/site-packages/theano/graph/op.py in rval()
    604 
    605         def rval():
--> 606             thunk()
    607             for o in node.outputs:
    608                 compute_map[o][0] = True

~/.cache/pypoetry/virtualenvs/time-series-demand-5LaNRWUQ-py3.9/lib/python3.9/site-packages/theano/link/c/basic.py in __call__(self)
   1769                 print(self.error_storage, file=sys.stderr)
   1770                 raise
-> 1771             raise exc_value.with_traceback(exc_trace)
   1772 
   1773 

ValueError: Input dimension mis-match. (input[0].shape[1] = 2, input[1].shape[1] = 1)

Please provide any additional information below.

Versions and main components

  • PyMC3 Version: 3.11.2
  • Aesara/Theano Version: 1.1.2
  • Python Version: 3.9.5
  • Operating system: CentOS Stream 8
  • How did you install PyMC3: (conda/pip) pip via poetry
@paw-lu
Copy link
Contributor Author

paw-lu commented Aug 24, 2021

Looked into it a bit more at it seems a quick fix is to use theano.shared and manually set the broadcastable arg.

Example:

"""This works!"""
import numpy as np
import pymc3 as pm
import theano

raw_data = np.array([[1], [2], [3]])

with pm.Model() as model:
    val = pm.Normal("val", mu=0, sd=10, shape=(1, 2))
    data = theano.shared(raw_data, broadcastable=(False, True))
    pm.Deterministic("add", var=val + data)

Problem is that I can't find a way to do this via pm.Data. Would a solution here be to add a broadcastable arg to pm.Data?

@michaelosthege
Copy link
Member

Problem is that I can't find a way to do this via pm.Data. Would a solution here be to add a broadcastable arg to pm.Data?

Maybe even forwarding unknown kwargs to shared() alltogether.
Another workaround is to pass only a vector and slice it with [:, None] or [None, :].

@paw-lu
Copy link
Contributor Author

paw-lu commented Oct 5, 2021

Maybe even forwarding unknown kwargs to shared() alltogether.

yeah that might be nice, I didn't know if shared was the primary thing pm.Data wrapped around, but if it's so, forwarding kwargs would be nice.

Good point on the None slicing!

@twiecki
Copy link
Member

twiecki commented Oct 5, 2021

I agree we should fwd args to shared.

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

Successfully merging a pull request may close this issue.

3 participants