Open hposborn opened 3 months ago
Ok, it looks like using pm.Potential(gp.log_likelihood(y-extra_model))
is the way to go:
with pm.Model() as model:
Rs=pm.Normal("Rs",mu=0.8,sigma=0.02)
Ms=pm.Normal("Ms",mu=0.78,sigma=0.02)
P=pm.Normal("P",mu=12.6,sigma=0.01)
t0=pm.Normal("t0",mu=3.21,sigma=0.04)
log_rprs=pm.Normal("log_rprs",mu=-4,sigma=3,initval=-2)
rprs=pm.Deterministic("rprs",pm.math.exp(log_rprs))
rpl=pm.Deterministic("rpl",rprs*Rs*109.2)
b=xo.distributions.ImpactParameter("b",ror=rprs,initval=0.4)
orb = xo.orbits.KeplerianOrbit(r_star=Rs,m_star=Ms,period=P,t0=t0,b=b)
u_stars = xo.distributions.QuadLimbDark("u_star", testval=np.array([0.3, 0.2]))
lightcurve=pm.Deterministic('lightcurve',1000*xo.LimbDarkLightCurve(u_stars).get_light_curve(orbit=xo.orbits.KeplerianOrbit(r_star=Rs,m_star=Ms,period=P,t0=t0,b=b), r=rprs*Rs, t=t))
logjit =pm.Normal('logjit', mu=np.log(np.std(flux)), sigma=1)
#Initialising GP:
sigma=pm.InverseGamma("sigma", **pmx.utils.estimate_inverse_gamma_parameters(lower=np.nanmedian(flux_err),
upper=np.ptp(flux),target=0.01))
w0=pm.InverseGamma("w0", **pmx.utils.estimate_inverse_gamma_parameters(lower=(2*np.pi)/10,
upper=(2*np.pi)/0.2,target=0.01))
kernel = celerite2.pymc.terms.SHOTerm(sigma=sigma, w0=w0, Q=1/np.sqrt(2))
mean_flux = pm.Normal("mean_flux", mu=0.0, sigma=0.5*np.nanstd(flux))
gp = celerite2.pymc.GaussianProcess(kernel, mean=mean_flux, t=t, diag=flux_err** 2 + pm.math.exp(logjit)**2)
loglik=pm.Potential("loglik", gp.log_likelihood(flux-pm.math.sum(lightcurve,axis=1)))
gp_pred=pm.Deterministic("gp_pred", gp.predict(flux-pm.math.sum(lightcurve,axis=1), return_var=False))
#nomarg_trans_init_soln=pm.find_MAP()
nomarg_trans_trace=pm.sample()
plt.plot(t,flux,'.',alpha=0.6)
plt.plot(t,np.nanmedian(nomarg_trans_trace.posterior['gp_pred'].values+nomarg_trans_trace.posterior['lightcurve'].values[:,:,:,0],axis=(0,1)),'-')
plt.savefig("MWE_fit_nomarg_trans.png")
So that seems to fix it! Though I am apprehensive about this as having a bit of a blackbox likelihood function - sometimes that doesn't play ball with some arviz functions like WAIC
, so any advice on directly calling pm.Normal or gp.marginal would still be useful imho.
I am having issues using celerite2 with PYMC. In the past (with PyMC3) I always used
gp.marginal(observed=y-extra_model)
in order to sample models which included both GP and other variables (i.e. a transit model) and this had no issue. For whatever reason that is no longer the case with PyMCv5 and I getTypeError: Variables that depend on other nodes cannot be used for observed data.
. I thought an easy alternative would be to initialise withgp.compute()
, generate a predicted GP curve withgp.predict()
, and then model everything the "classical" way in PyMC usingpm.Normal(mu=gp_pred+extra_model, sigma=y_err, observed=y)
. But this gives completely different, and horrendously overfitted, results from usinggp.marginal()
for the same model. (see below)So I would love some advice on how to model combined celerite + additional functions: a) Is there any way to sample using
gp.marginal()
where the observed data can depend on other PyMC parameters? For example, maybe themean
function could be more than a single value but to haveN_t
values and we can put the transit model in that way? b) How should sampling within PyMC be done if usinggp.marginal()
withy-extra_model
is not possible? Should we be usinggp.predict()
for this purpose at all, or is there just a step I'm missing which is causing the drastic overfitting?Some code as a MWE:
The anticipated behaviour, using
gp.marginal()
(no transit):The arviz summary:
So a GP-only model works fine.
The behaviour when including an additional non-celerite mean function (with
exoplanet
transit):Output:
I have verified that the same error occurs across different computers (both my M2 Mac and linux server).
The behaviour when sampling with the output of
gp.predict()
:The arviz summary:
This is clearly extremely over-fitted for some reason...