TypeError: Invalid Use of Observed Data Variable

I attempted to execute one of my previous models using the latest version of Pymc. This model had previously run without any problems in older versions. However, in the current version, I encountered the following error. I am keen to execute the model as it is, and I am seeking guidance on how to circumvent this error or if there is a workaround available. Your assistance in resolving this matter would be greatly appreciated.

with pm.Model() as model:
V = pm.Uniform(“V”, 100000, 600000)
Y0 = pm.Uniform(“Y_0”, 0, 30.48)
Z0 = pm.Uniform(“Z_0”, 0, 111.76)
t_min = pm.HalfNormal(“t_min”, sigma=0.0001)
sigma = pm.HalfNormal(“sigma”, sigma=0.00002)
X0 = pm.Uniform(“X_0”, 0, 30.48)
r = pm.Deterministic(
“distance”,
pm.math.sqrt(((X0 - sen_x)) ** 2 + ((Y0 - sen_y)) ** 2 + ((Z0 - sen_z)) ** 2),
)
DT = pm.Deterministic(“arrival time”, r / V - t_min)
p= pm.Beta(“p”,2,2,shape=dt1.shape)

alpha = pm.Bernoulli(
    "indicator", p=p, shape=dt1.shape
)  
OBS= pm.Normal('obs', mu=DT, sigma=sigma,observed=dt1*(1-alpha)+dt2*(alpha))

TypeError: Variables that depend on other nodes cannot be used for observed data.The data variable was: Add.0

I found a dirty way of passing this funny error! Please share if there is a clean way of doing it:

OBS= pm.Normal('obs', mu=DT-dt1*(1-alpha)+dt2*(alpha), sigma=sigma,observed=dt1.shape[0]*[0])

As the error indicates, your observed values need to be the “bottom line” – you can’t do any modeling on them. Since you don’t actually observe the quantity dt1*(1-alpha)+dt2*(alpha) (since you don’t observe alpha), it doesn’t make any sense as written.

Also, I’m not sure I understand your dirty fix. You changed all the observed values to zero, and that doesn’t seem like it should be right. What is the actual data you want to model? My uninformed guess is that you have some kind of mixture model, but everything is somewhat jumbled together.

No, I moved the observed value to the left side by subtracting it from the mean. This is technically correct because ideally, this summation should equal zero. That’s why the observed value appears to be zero, but in reality, it is included in the mean value of your likelihood.

The technique you observed can be classified as a model selection technique. Alpha plays a role in selecting the best data for this model. Imagine that each combination of dt1 and dt2 represents one model, and alpha helps determine which one provides better data for this model.

This model, as I mentioned, was functional in an older version of pymc dating back to 2019. I also published a paper on its advanced setup. I returned to it for further research and noticed that they had made changes to how errors are handled. Now, errors are taken into account when there is a parameter in the observed part, which logically seems reasonable but may not be the best choice for advanced modeling.

I highly recommend changing this approach to just issuing a warning and allowing the sampler to carry out its job without imposing this constraint.

When one wants to intervene on the logp of a model directly, which using parameters for observed is doing, the right tool is to use a pm.Potential. Something like pm.Potential("pot", pm.logp(pm.Normal.dist(), f(data, rvs))

I doesn’t make sense to try to write a PyMC model with a dynamic observed, because observed is not part of the generative/forward graph. For instance, it wouldn’t have any effect on prior or posterior predictive sampling.

This actually touches on a subtle difference between PyMC V3 and V4/5. In the older version one defines a logp model (for which PyMC tried its best to guess corresponding random graph) and now one writes a random graph (for which PyMC tries its best to guess a corresponding logp graph).

1 Like

Nice explanation, thanks. Can we write potential in the example I shared?

You mean the original example in this thread? If so, yes. You just wrap logp(dist, value=observed) inside a Potential. observed is whatever you want it to be.

1 Like

Thanks, I never did that before. Hope I can find an example, or you are generous enough to give me more detail.

I grabbed your original example, and filled in the missing variables with dumb placeholders:

import pymc as pm
import numpy as np

sen_x = 1.0
sen_y = 2.0
sen_z = 3.0
dt1 = np.zeros((5, 3))
dt2 = np.ones((5, 3))
with pm.Model() as model:
    V = pm.Uniform('V', 100000, 600000)
    Y0 = pm.Uniform('Y_0', 0, 30.48)
    Z0 = pm.Uniform('Z_0', 0, 111.76)
    t_min = pm.HalfNormal('tsen_x_min', sigma=0.0001)
    sigma = pm.HalfNormal('sigma', sigma=0.00002)
    X0 = pm.Uniform('X_0', 0, 30.48)
    r = pm.Deterministic(
    'distance',
        pm.math.sqrt(((X0 - sen_x)) ** 2 + ((Y0 - sen_y)) ** 2 + ((Z0 - sen_z)) ** 2),
    )
    DT = pm.Deterministic('arrival time', r / V - t_min)
    p= pm.Beta('p', 2, 2, shape = dt1.shape)
    
    alpha = pm.Bernoulli(
        "indicator", p=p, shape=dt1.shape
    )

    observed_value = dt1 * (1 - alpha) + dt2 * (alpha)
    pm.Potential("obs", pm.logp(pm.Normal.dist(mu=DT, sigma=sigma), value=observed_value))

model.point_logps()
{'V': -1.39,
 'Y_0': -1.39,
 'Z_0': -1.39,
 'tsen_x_min': -0.73,
 'sigma': -0.73,
 'X_0': -1.39,
 'p': -14.71,
 'indicator': -10.4,
 'obs': -18747713327.18}
2 Likes

Thank you so much, Ricardo. I really appreciate your help, and I’m eager to give it a try. Your kindness means a lot to me.