-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Variables in logp and dlogp functions used in find_MAP
are not always aligned
#5923
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
Can you add the print results? |
I just tried an upgrade to v4 yesterday, and a lot of the diagnostics for my project use import numpy as np
from scipy import stats
import pymc as pm
n_individuals = 1000
alpha = 30
beta = 0.3
sigma = 5
height = np.random.uniform(130, 170, n_individuals)
mu = alpha + beta * (height-height.mean())
weight = stats.norm.rvs(loc=mu, scale=sigma, size=n_individuals)
with pm.Model() as model:
alpha = pm.Normal('alpha', mu=50, sigma=10)
beta = pm.Lognormal('beta', mu=0, sigma=1)
sigma = pm.Uniform('sigma', lower=0, upper=10)
mu = alpha + beta * (height-height.mean())
weight = pm.Normal('height', mu=mu, sigma=sigma, observed=weight)
mean_q = pm.find_MAP()
print(mean_q) I get the output: {'alpha': array(1.0025977e+14), 'beta_log__': array(-2.51355127e+13), 'sigma_interval__': array(-8.65309668e+12), 'beta': array(0.), 'sigma': array(0.)} Using PyMC3 instead works well, producing this output: {'alpha': array(29.88057992), 'beta_log__': array(-1.14830438), 'sigma_interval__': array(0.0518484), 'beta': array(0.31717412), 'sigma': array(5.12959197)} The instability can be avoided in v4 by specifying a closer starting position like so: mean_q = pm.find_MAP(start={
alpha: 25.,
beta: 1.,
sigma: 5.,
}) But this produces {'alpha': array(26.18118026), 'beta_log__': array(-1.23207473), 'sigma_interval__': array(0.71096296), 'beta': array(0.29168678), 'sigma': array(6.70613904)} so n_individuals = 1000
alpha = 30
beta = 0.3
sigma = 5
height = np.random.uniform(130, 170, n_individuals)
mu = alpha + beta * (height-height.mean())
weight = stats.norm.rvs(loc=mu, scale=sigma, size=n_individuals)
with pm.Model() as model:
alpha = pm.Normal('alpha', mu=50, sigma=10)
beta = pm.Lognormal('beta', mu=0, sigma=1)
sigma = pm.Uniform('sigma', lower=0, upper=10)
mu = alpha + beta * (height-height.mean())
weight = pm.Normal('height', mu=mu, sigma=sigma, observed=weight)
trace = pm.sample(1000, tune=1000)
pm.summary(trace) produces:
|
I also suspect that this is the same issue as #5848. |
Hm, if we remove the transformed variables, and run the optimizer manually, I get good results, but import numpy as np
from scipy import stats
import pymc
n_individuals = 1000
alpha = 30
beta = 0.3
sigma = 5
height = np.random.uniform(130, 170, n_individuals)
mu = alpha + beta * (height-height.mean())
weight = stats.norm.rvs(loc=mu, scale=sigma, size=n_individuals)
with pymc.Model() as model:
alpha = pymc.Normal('alpha', mu=50, sigma=10)
#beta = pymc.Lognormal('beta', mu=0, sigma=1)
log_beta = pymc.Normal('log_beta', mu=0, sigma=1)
beta = at.exp(log_beta)
#sigma = pymc.Uniform('sigma', lower=0, upper=10)
raw = pymc.Normal("raw", sigma=10)
sigma = (at.tanh(raw) + 1) / 2 * 10
mu = alpha + beta * (height-height.mean())
weight = pymc.Normal('height', mu=mu, sigma=sigma, observed=weight)
mean_q = pymc.find_MAP()
print(mean_q)
from scipy import optimize
func = model.compile_logp(jacobian=False)
dfunc = model.compile_dlogp(jacobian=False)
start = {'alpha': np.array(50.), 'log_beta': np.array(0.), 'raw': np.array(0.)}
def to_array(point):
return np.stack(list(point.values()))
def to_dict(x):
return {name: val for name, val in zip(start, x)}
optimize.minimize(lambda x: -func(to_dict(x)), to_array(start), jac=lambda x: -dfunc(to_dict(x))) gives
|
I played around a bit with rearranging the order that variables are declared in, which does change the output of import numpy as np
from scipy import stats
import pymc
import aesara.tensor as at
n_individuals = 1000
alpha = 30
beta = 0.3
sigma = 5
height = np.random.uniform(130, 170, n_individuals)
mu = alpha + beta * (height-height.mean())
weight = stats.norm.rvs(loc=mu, scale=sigma, size=n_individuals)
with pymc.Model() as model:
#beta = pymc.Lognormal('beta', mu=0, sigma=1)
#sigma = pymc.Uniform('sigma', lower=0, upper=10)
alpha = pymc.Normal('alpha', mu=50, sigma=10)
log_beta = pymc.Normal('log_beta', mu=0, sigma=1)
beta = at.exp(log_beta)
raw = pymc.Normal("raw", sigma=10)
sigma = (at.tanh(raw) + 1) / 2 * 10
mu = alpha + beta * (height-height.mean())
weight = pymc.Normal('height', mu=mu, sigma=sigma, observed=weight)
mean_q = pymc.find_MAP(vars=[raw, log_beta, alpha])
print(mean_q) I suspect that the problem has to do with these lines in Although Python3 dictionaries are technically ordered now, I don't think that the use of In addition, the order of the variables in the output of the gradient function compiled by |
OK, I've figured this out. First off, the stochastic behavior was my own fault, and not a bug. I was accidentally resampling After looking closely, I take back what I said about the vars_dict = {var.name: var for var in vars}
rvs = [model.values_to_rvs[vars_dict[name]]
for name, _, _ in x0.point_map_info] This fixes the primary problem, which is that the gradient information being passed to The second problem is that for some data sets, find_MAP just doesn't work very well unless it's initialized very close to the optimal point, and this has kind of always been true. At least for the data here, performance is far more consistent if the |
Nice find @quantheory! However, it seems that function will now compute the gradient wrt to variables we are not sampling, as I have the impression that I have no opinion about the |
Thanks! I believe that var_names = {var.name for var in vars}
x0 = DictToArrayBijection.map(
{var_name: value for var_name, value in start.items() if var_name in var_names}
) Because In any case, it is a requirement of |
I know they will match, my concern was that under the hood we would be computing the gradient wrt to the constant values we are not sampling (but which are passed from the We could actually compile a logp/dlogp where we set those to constants, but that's another matter. |
Oh! I understand your concern. My modification should not introduce any unnecessary dimensions to the gradient, regardless of the I will try to put together a PR tomorrow, but I am on a series of tight deadlines for the next month or so (ending my current project), meaning that I can't guarantee a fast response to feedback. I'd prefer it if someone more experienced can shepard this through, but if not, I'll do what I can. |
Shouldn't we use This used to work: func = pymc_model.logp_dlogp_function()
func.size
func.set_extra_values({})
x0 = func.array_to_dict(pymc_model.initial_point())
func(x0) |
@aseyboldt I think we followed a simple refactoring strategy, as Line 45 in ed74406
We should definitely avoid computing the two outputs separately, either via the Regarding the API change of the |
@quantheory no worries about speed. If you open a PR with the option for devs to modify it, we can also help if you find yourself out of time! |
find_MAP
find_MAP
find_MAP
are not always aligned
find_MAP
are not always alignedfind_MAP
are not always aligned
Hi, that's great to know. Thanks @quantheory :) |
In this reproducible example, sampling from the model gives the correct
parameter estimates while
pymc.find_MAP()
does not.(I just installed the latest pymc version using conda in a new environment on Ubuntu)
I am modeling weight as a function of height, here is some simulated data:
When the prior for alpha is centered on the true value of alpha,
find_MAP() correctly estimates the values for alpha, beta and sigma:
However, when the true value of alpha differs from the prior mean,
beta and sigma are estimated to be 0:
Sampling from the model still returns the correct values for all three parameters:
So I am wondering if this is a bug or if find_MAP() is supposed to fail in the second case.
If latter, I would have expected some error or warning being put out by the function.
The text was updated successfully, but these errors were encountered: