pymc icon indicating copy to clipboard operation
pymc copied to clipboard

Error w/ `deepcopy` of pymc v4 model

Open hectormz opened this issue 3 years ago • 6 comments

Error w/ deepcopy of pymc v4 model

This used to work on pymc3 and theano-pymc

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

from copy import deepcopy

import numpy as np
import pymc as pm

RANDOM_SEED = 8927
rng = np.random.default_rng(RANDOM_SEED)

# True parameter values
alpha, sigma = 1, 1
beta = [1, 2.5]

# Size of dataset
size = 100

# Predictor variable
X1 = np.random.randn(size)
X2 = np.random.randn(size) * 0.2

# Simulate outcome variable
Y = alpha + beta[0] * X1 + beta[1] * X2 + rng.normal(size=size) * sigma

basic_model = pm.Model()

with basic_model:

    # Priors for unknown model parameters
    alpha = pm.Normal("alpha", mu=0, sigma=10)
    beta = pm.Normal("beta", mu=0, sigma=10, shape=2)
    sigma = pm.HalfNormal("sigma", sigma=1)

    # Expected value of outcome
    mu = alpha + beta[0] * X1 + beta[1] * X2

    # Likelihood (sampling distribution) of observations
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)

model_copy = deepcopy(basic_model)

Please provide the full traceback.

Complete error traceback
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [9], in <cell line: 41>()
     38     # Likelihood (sampling distribution) of observations
     39     Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
---> 41 model_copy = deepcopy(basic_model)

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:270, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268 if state is not None:
    269     if deep:
--> 270         state = deepcopy(state, memo)
    271     if hasattr(y, '__setstate__'):
    272         y.__setstate__(state)

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:230, in _deepcopy_dict(x, memo, deepcopy)
    228 memo[id(x)] = y
    229 for key, value in x.items():
--> 230     y[deepcopy(key, memo)] = deepcopy(value, memo)
    231 return y

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:230, in _deepcopy_dict(x, memo, deepcopy)
    228 memo[id(x)] = y
    229 for key, value in x.items():
--> 230     y[deepcopy(key, memo)] = deepcopy(value, memo)
    231 return y

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:270, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268 if state is not None:
    269     if deep:
--> 270         state = deepcopy(state, memo)
    271     if hasattr(y, '__setstate__'):
    272         y.__setstate__(state)

    [... skipping similar frames: _deepcopy_dict at line 230 (1 times), deepcopy at line 146 (1 times)]

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:270, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268 if state is not None:
    269     if deep:
--> 270         state = deepcopy(state, memo)
    271     if hasattr(y, '__setstate__'):
    272         y.__setstate__(state)

    [... skipping similar frames: deepcopy at line 146 (1 times)]

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:230, in _deepcopy_dict(x, memo, deepcopy)
    228 memo[id(x)] = y
    229 for key, value in x.items():
--> 230     y[deepcopy(key, memo)] = deepcopy(value, memo)
    231 return y

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:205, in _deepcopy_list(x, memo, deepcopy)
    203 append = y.append
    204 for a in x:
--> 205     append(deepcopy(a, memo))
    206 return y

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:270, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268 if state is not None:
    269     if deep:
--> 270         state = deepcopy(state, memo)
    271     if hasattr(y, '__setstate__'):
    272         y.__setstate__(state)

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:230, in _deepcopy_dict(x, memo, deepcopy)
    228 memo[id(x)] = y
    229 for key, value in x.items():
--> 230     y[deepcopy(key, memo)] = deepcopy(value, memo)
    231 return y

File ~\AppData\Local\Programs\Python\Python39\lib\copy.py:153, in deepcopy(x, memo, _nil)
    151 copier = getattr(x, "__deepcopy__", None)
    152 if copier is not None:
--> 153     y = copier(memo)
    154 else:
    155     reductor = dispatch_table.get(cls)

File ~\.virtualenvs\pymc4-venv\lib\site-packages\aesara\link\basic.py:142, in Container.__deepcopy__(self, memo)
    132 r = type(self)(
    133     deepcopy(self.type, memo=memo),
    134     deepcopy(self.storage, memo=memo),
   (...)
    138     name=deepcopy(self.name, memo=memo),
    139 )
    140 # Work around NumPy deepcopy of ndarray with 0 dimension that
    141 # don't return an ndarray.
--> 142 if r.storage[0] is not None and not self.type.is_valid_value(r.storage[0]):
    143     assert not data_was_in_memo
    144     assert self.type.is_valid_value(self.storage[0])

TypeError: is_valid_value() missing 1 required positional argument: 'strict'

Versions and main components

  • PyMC Version: 4.0
  • Aesara Version: 2.66
  • Python Version: 3.9
  • Operating system: Windows
  • How did you install PyMC: pip

hectormz avatar Jun 14 '22 16:06 hectormz

Originally posted in aesara (https://github.com/aesara-devs/aesara/issues/992), but it was more appropriate to post here.

hectormz avatar Jun 14 '22 16:06 hectormz

If it is an aesara issue we need to find a MWE that only uses aesara.

twiecki avatar Jun 14 '22 16:06 twiecki

@twiecki that would be most helpful, but I don't know pymc internals well enough to extract out the aesara. If someone else is able to try or give guidance, that would be great.

hectormz avatar Jun 14 '22 17:06 hectormz

@twiecki I believe @brandonwillard has solved the issue with https://github.com/aesara-devs/aesara/pull/995 I'd be happy to close this issue once those changes in aesara can be tested in pymc

hectormz avatar Jun 14 '22 21:06 hectormz

Not sure if this is worth adding a test, as it was a pure Aesara bug and the original example was using PyMC in a pretty uncommon (?) way.

ricardoV94 avatar Jun 20 '22 09:06 ricardoV94

Sure, understandable. I have no idea if anyone else does this. Anyway, it now works with the latest:

aesara==2.7.3
pymc==4.0.1

hectormz avatar Jun 24 '22 05:06 hectormz

sounds fixed

michaelosthege avatar Aug 13 '22 14:08 michaelosthege