pymc icon indicating copy to clipboard operation
pymc copied to clipboard

Problem with Categorical distribution with tensor probabilities

Open Armavica opened this issue 3 years ago • 5 comments

Description of your problem

Hi, I can't seem to use the Categorical distribution with tensor probabilities.

import pymc3 as pm

with pm.Model() as model:
    p = pm.Uniform('p', 0, 1)
    c = pm.Categorical('c', [p, 1-p])
Complete error traceback
Traceback (most recent call last):
  File "/home/virgile/.miniconda3/envs/gadX/lib/python3.9/site-packages/pymc3/theanof.py", line 83, in floatX
    return X.astype(theano.config.floatX)
AttributeError: 'list' object has no attribute 'astype'

During handling of the above exception, another exception occurred:

TypeError: float() argument must be a string or a number, not 'TransformedRV'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/virgile/src/airthings/t.py", line 7, in <module>
    c = pm.Categorical('c', [p, 1-p])
  File "/home/virgile/.miniconda3/envs/gadX/lib/python3.9/site-packages/pymc3/distributions/distribution.py", line 121, in __new__
    dist = cls.dist(*args, **kwargs)
  File "/home/virgile/.miniconda3/envs/gadX/lib/python3.9/site-packages/pymc3/distributions/distribution.py", line 130, in dist
    dist.__init__(*args, **kwargs)
  File "/home/virgile/.miniconda3/envs/gadX/lib/python3.9/site-packages/pymc3/distributions/discrete.py", line 1347, in __init__
    p = tt.as_tensor_variable(floatX(p))
  File "/home/virgile/.miniconda3/envs/gadX/lib/python3.9/site-packages/pymc3/theanof.py", line 86, in floatX
    return np.asarray(X, dtype=theano.config.floatX)
ValueError: setting an array element with a sequence.

Please provide any additional information below.

Versions and main components

  • PyMC/PyMC3 Version: 3.11.4
  • Aesara/Theano Version: 1.1.2 (theano)
  • Python Version: 3.9.10
  • Operating system: linux
  • How did you install PyMC/PyMC3: conda

Armavica avatar Feb 22 '22 23:02 Armavica

Try with c = pm.Categorical('c', pm.math.stack([p, 1-p])), otherwise it's probably trying to convert that list of TensorVariables to a numpy array

ricardoV94 avatar Feb 23 '22 07:02 ricardoV94

Thank you, it is working now. Would you like me to add this snippet of code somewhere in the documentation so that other people can find it too and not be confused like me? Or would it make sense to make the distribution recognize what we are trying to do and apply the stack operation automatically?

Armavica avatar Feb 23 '22 19:02 Armavica

@Armavica We should check what happens in version 4, as many things have changed. If it still fails we should fix it.

ricardoV94 avatar Feb 26 '22 06:02 ricardoV94

Still failing in here, but with a different error message. Seems like the .dist() method is checking about whether p is a list (true in this case), but then asking for Boolean operations on the elements in p without checking whether the elements in p are themselves tensors? Does that seem right?

Error

TypeError Traceback (most recent call last) Input In [3], in <cell line: 1>() 1 with pm.Model() as model: 2 p = pm.Uniform('p', 0, 1) ----> 3 c = pm.Categorical('c', [p, 1-p])

File ~/Documents/code/pymc/pymc/pymc/distributions/distribution.py:649, in Discrete.new(cls, name, *args, **kwargs) 646 if kwargs.get("transform", None): 647 raise ValueError("Transformations for discrete distributions") --> 649 return super().new(cls, name, *args, **kwargs)

File ~/Documents/code/pymc/pymc/pymc/distributions/distribution.py:267, in Distribution.new(cls, name, rng, dims, initval, observed, total_size, transform, *args, **kwargs) 263 rng = model.next_rng() 265 # Create the RV and process dims and observed to determine 266 # a shape by which the created RV may need to be resized. --> 267 rv_out, dims, observed, resize_shape = _make_rv_and_resize_shape( 268 cls=cls, dims=dims, model=model, observed=observed, args=args, rng=rng, **kwargs 269 ) 271 if resize_shape: 272 # A batch size was specified through dims, or implied by observed. 273 rv_out = change_rv_size(rv_var=rv_out, new_size=resize_shape, expand=True)

File ~/Documents/code/pymc/pymc/pymc/distributions/distribution.py:166, in _make_rv_and_resize_shape(cls, dims, model, observed, args, **kwargs) 163 """Creates the RV and processes dims or observed to determine a resize shape.""" 164 # Create the RV without dims information, because that's not something tracked at the Aesara level. 165 # If necessary we'll later replicate to a different size implied by already known dims. --> 166 rv_out = cls.dist(*args, **kwargs) 167 ndim_actual = rv_out.ndim 168 resize_shape = None

File ~/Documents/code/pymc/pymc/pymc/distributions/discrete.py:1257, in Categorical.dist(cls, p, **kwargs) 1254 @classmethod 1255 def dist(cls, p, **kwargs): 1256 if isinstance(p, np.ndarray) or isinstance(p, list): -> 1257 if (np.asarray(p) < 0).any(): 1258 raise ValueError(f"Negative p parameters are not valid, got: {p}") 1259 p_sum = np.sum([p], axis=-1)

File ~/anaconda3/envs/pymc-dev-py39/lib/python3.9/site-packages/aesara/tensor/var.py:67, in _tensor_py_operators.bool(self) 65 return True 66 else: ---> 67 raise TypeError("Variables do not support boolean operations.")

cluhmann avatar Mar 22 '22 01:03 cluhmann

Yes it was a recent check we added. We should check if the list elements are not TensorVariables before attempting that check

Same for the multinomial I think

ricardoV94 avatar Mar 22 '22 05:03 ricardoV94