-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Homogenous data incorectly treated #4389
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
Comments
I can certainly look into it. 👍 The first step would obviously be tracking down the source of this problem. Then we can figure out whether these other data/shape issues are related. |
That's bizarre, no idea what could be causing this but seems like theano might be the source. @brandonwillard any idea? |
From that example alone, I don't see anything indicating a Theano-specific issue. |
Try printing the log-likelihood graphs for the working and non-working models using Otherwise, what is |
Then it could be in the code that is processing what gets passed to |
Can't say the debugger is my favourite tool to use, but I can see if I make any headway. I already confirmed that the observed data itself does not seem to change, so it seems unrelated to #3640. If I don't seem to be making much progress, I'll report back. |
No obvious causes, but maybe my digging can provide some clues for those more intimately familiar with the inner workings of pymc/theano. To try and triangulate a bit, I focused on 3 different data scenarios: with pm.Model() as model:
numpyData = np.zeros(10)
numpyData2 = np.zeros(10)
numpyData2[0] = 1
pmData = pm.Data('pmData', numpyData)
# data is a numpy array exclusively filled with zeros
npVar = pm.Bernoulli('npVar', p=p[0], observed=numpyData)
# data is a numpy array with a single 1
npVar2 = pm.Bernoulli('npVar2', p=p[1], observed=numpyData2)
# data is a pm.Data object filled with zeros
pmVar = pm.Bernoulli('pmVar', p=p[2], observed=pmData) The first is the problematic version, the other two work. print(type(npVar))
print(type(npVar2))
print(type(pmVar))
So far so good. print(type(npVar.observations))
print(type(npVar2.observations))
print(type(pmVar.observations))
So the variable defined using print(npVar.observations.dtype)
print(npVar2.observations.dtype)
print(pmVar.observations.dtype)
Seems fine. print(npVar.dtype)
print(npVar2.dtype)
print(pmVar.dtype)
Ok. A bit odd. Presumably this happens when building the ObservedRV out of the pm.Data rather the numpy array. print(npVar.shape.eval())
print(npVar2.shape.eval())
print(pmVar.shape.eval())
Ok, so obviously some difficulties with getting the shape of the pm.Data version of variable. But in the end all the shapes look to be equivalent. And finally: theano.printing.debugprint(npVar)
theano.printing.debugprint(npVar2)
theano.printing.debugprint(pmVar)
Nothing here seems obviously off to me, though these debugging messages aren't exactly transparent. Is there anything here that sets off alarm bells for anyone? Or anything that suggests directions to go digging? |
The only thing that jumps out to me is |
For example, such terms are generated by expressions like the following: >>> import numpy as np
>>> import theano.tensor as tt
>>> tt.as_tensor(np.r_[0, 0, 0])
TensorConstant{(3,) of 0} |
I would say that the discrepancy between the dtypes is bad. Also, it looks like This is also the reason why you're seeing that optimization error in Theano. In other words, it looks like there's a bug in the N.B.: the following will raise an exception for that error so that one can investigate further with their debugger of choice: import theano
with theano.config.change_flags(on_opt_error="raise"):
pmVar.shape.eval() |
I don't know if this helps, but I noticed that this issue does not happen with the equivalent model using Binomial distributions. with pm.Model() as model:
pmData = pm.Data('pmData', numpyData)
p = pm.Beta('p', alpha=1, beta=1, shape=3)
# data is a numpy array exclusively filled with zeros
npVar = pm.Bernoulli('npVar', p=p[0], observed=numpyData)
# data is a numpy array with a single 1
npVar2 = pm.Bernoulli('npVar2', p=p[1], observed=numpyData2)
# data is a pm.Data object filled with zeros
pmVar = pm.Bernoulli('pmVar', p=p[2], observed=pmData)
model.check_test_point()
p_logodds__ -4.16
npVar -0.69
npVar2 -6.93
pmVar -6.93
Name: Log-probability of test_point, dtype: float64 with pm.Model() as model:
pmData = pm.Data('pmData', numpyData)
p = pm.Beta('p', alpha=1, beta=1, shape=3)
# data is a numpy array exclusively filled with zeros
npVar = pm.Binomial('npVar', n=1, p=p[0], observed=numpyData)
# data is a numpy array with a single 1
npVar2 = pm.Binomial('npVar2', n=1, p=p[1], observed=numpyData2)
# data is a pm.Data object filled with zeros
pmVar = pm.Binomial('pmVar', n=1, p=p[2], observed=pmData)
model.check_test_point()
p_logodds__ -4.16
npVar -6.93
npVar2 -6.93
pmVar -6.93
Name: Log-probability of test_point, dtype: float64 |
Also using pm.Bernoulli.dist(p=.5).logp(numpyData).eval()
ERROR (theano.gof.opt): Optimization failure due to: constant_folding
ERROR (theano.gof.opt): node: Elemwise{switch,no_inplace}(TensorConstant{(10,) of 1}, TensorConstant{(1,) of -0..1805599453}, TensorConstant{(1,) of -inf})
ERROR (theano.gof.opt): TRACEBACK:
ERROR (theano.gof.opt): Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/theano/gof/opt.py", line 2129, in process_node
replacements = lopt.transform(node)
File "/usr/local/lib/python3.6/dist-packages/theano/tensor/opt.py", line 7061, in constant_folding
required = thunk()
File "/usr/local/lib/python3.6/dist-packages/theano/gof/op.py", line 884, in rval
thunk()
File "/usr/local/lib/python3.6/dist-packages/theano/gof/cc.py", line 1845, in __call__
raise exc_value.with_traceback(exc_trace)
ValueError: Input dimension mis-match. (input[0].shape[0] = 10, input[1].shape[0] = 1)
array([-0.69314718]) |
Also the new logcdf method works fine. Does it mean it might be an issue with the logp method? Edit: Found it! It's an issue with print(tt.switch(numpyData, 1, 0).eval())
print(tt.switch(numpyData2, 1, 0).eval())
[0]
[1 0 0 0 0 0 0 0 0 0] |
This line (and the equivalent one for the should be I wonder if this kind of issue might crop up in other places... |
Good find! Using integers and booleans is always dicey, but the |
@brandonwillard has already fixed the Theano issue! Do we need to do anything here? An immediate solution that does not depends on synching to the next Theano release is to change those 2 lines in the logp to use Even if we do nothing, should we at least add a maintenance release note? |
🎉 If we just switch to the latest Theano-PyMC, it seems to me that we don't have anything to fix here, right? |
@AlexAndorra yes, 3.11 will depend on Theano-PyMC 1.1. If you want to add a line to the release notes about this, please do so in #4405 and link/close this issue in the commit message. |
Can't we just open a simple PR where just release notes are updated and link to the fixing PR on the Theano-PyMC repo? |
Technially the upgrade to Theano-PyMC |
If you're already set up to do it I'd appreciate that! I can do it too, but setting up the fork to push on other people's forks is always a bit annoying |
closed by #4405 |
Over on discourse, Argantonio65 reported a problem when trying out a toy coin-flipping example. In playing around with it a bit, it seems that a numpy array consisting exclusively of ones[zeros] is treated as a single (scalar) one[zero] regardless of the actual length of the numpy array. Adding even a single zero[one] seems to cause the true length to be acknowledged. Similarly, wrapping the array in a
pm.Data
object also seems to yield correct behavior.Here is a condensed version illustrating the insensitivity to sample size when the data is just a vector of ones.
This displays the following:
Changing the 3 likelihood lines so that they use
pm.Data
:yields the expected behavior:
Augmenting the data with a single tail/failure:
also yields the expected behavior.
Versions and main components
The text was updated successfully, but these errors were encountered: