为什么调质的mcmc适合收敛性不好?

时间:2019-05-26 21:49:32

标签: python numpy curve-fitting mcmc emcee

我正在尝试使用y=mx+c使简单的直线parallel-tempered mcmc类型适合某些合成数据。我的目标是仅仅能够理解如何使用它,以便以后可以将其应用于一些更复杂的模型。我正在尝试的示例是在简单的主持人代码中已经完成的操作的副本: http://dfm.io/emcee/current/user/line/ 但我不想使用mcmc,而是要使用并行调解的mcmc: http://dfm.io/emcee/current/user/pt/

这是一个有效的代码:

import numpy as np
from emcee import PTSampler
import emcee

# Choose the "true" parameters.
m_true = -0.9594
b_true = 4.294
f_true = 0.534

# Generate some synthetic data from the model.
N = 50
x = np.sort(10*np.random.rand(N))
yerr = 0.1+0.5*np.random.rand(N)
y = m_true*x+b_true
y += np.abs(f_true*y) * np.random.randn(N)
y += yerr * np.random.randn(N)


def lnlike(theta, x, y, yerr):
    m, b, lnf = theta
    model = m * x + b
    inv_sigma2 = 1.0/(yerr**2 + model**2*np.exp(2*lnf))
    return -0.5*(np.sum((y-model)**2*inv_sigma2 - np.log(inv_sigma2)))
def lnprior(theta):
    m, b, lnf = theta
    if -5.0 < m < 0.5 and 0.0 < b < 10.0 and -10.0 < lnf < 1.0:
        return 0.0
    return -np.inf
def lnprob(theta, x, y, yerr):
    lp = lnprior(theta)
    if not np.isfinite(lp):
        return -np.inf
    return lp + lnlike(theta, x, y, yerr)

import scipy.optimize as op
nll = lambda *args: -lnlike(*args)
result = op.minimize(nll, [m_true, b_true, np.log(f_true)], args=(x, y, yerr))
m_ml, b_ml, lnf_ml = result["x"]
init = [0.5, m_ml, b_ml, lnf_ml]

ntemps = 10
nwalkers = 100
ndim = 3
from multiprocessing import Pool
pos = np.random.uniform(low=-1, high=1, size=(ntemps, nwalkers, ndim))
for i in range(ntemps):
    #initialize parameters near scipy optima
    pos[i:,] = np.array([result["x"] + 1e-4*np.random.randn(ndim) for i in range(nwalkers)])
pool = Pool(processes=4)
sampler=PTSampler(ntemps,nwalkers, ndim, lnlike, lnprior, loglargs=(x, y, yerr), pool=pool)# args=(x, y, yerr))
#burn-in 
sampler.run_mcmc(pos, 1000)
sampler.reset()
sampler.run_mcmc(pos, 10000, thin=10)
samples = sampler.chain.reshape((-1, ndim))
print('Number of posterior samples is {}'.format(samples.shape[0]))
#print best fit value together with errors
print(map(lambda v: (v[1], v[2]-v[1], v[1]-v[0]),
                             zip(*np.percentile(samples, [16, 50, 84],
                                                axis=0))))

import corner
fig = corner.corner(samples, labels=["$m$", "$b$", "$\ln\,f$"],
                      truths=[m_true, b_true, np.log(f_true)])
fig.savefig("triangle.png")

运行此代码时,唯一的问题是我获得了与真实值相去甚远的最佳参数值。从任何意义上说,增加步行者或样本的数量都无济于事。有人可以建议为什么tempered-mcmc在这里不工作吗?

更新

我发现了一个有用的软件包,名为ptemceehttps://pypi.org/project/ptemcee/#description),尽管该软件包的文档不存在。看来此套件可能有用,对如何使用此套件实施相同线性拟合的任何帮助也将受到高度赞赏。

1 个答案:

答案 0 :(得分:0)

我修改了几行

import time
import numpy as np
from emcee import PTSampler
import corner
import matplotlib.pyplot as plt
import scipy.optimize as op

t1 = time.time()

np.random.seed(6) # To reproduce results
# Choose the "true" parameters.
m_true = -0.9594
b_true = 4.294
f_true = 0.534

# Generate some synthetic data from the model.
N = 50
x = np.sort(10 * np.random.rand(N))
yerr = 0.1 + 0.5 * np.random.rand(N)
y_1 = m_true * x + b_true
y = np.abs(f_true * y_1) * np.random.randn(N) + y_1
y += yerr * np.random.randn(N)

plt.plot(x, y, 'o')


# With emcee

def lnlike(theta, x, y, yerr):
    m, b, lnf = theta
    model = m * x + b
    inv_sigma2 = 1.0/(yerr**2 + model**2*np.exp(2*lnf))
    return -0.5*(np.sum((y-model)**2*inv_sigma2 - np.log(inv_sigma2)))
def lnprior(theta):
    m, b, lnf = theta
    if -5.0 < m < 0.5 and 0.0 < b < 10.0 and -10.0 < lnf < 1.0:
        return 0.0
    return -np.inf
def lnprob(theta, x, y, yerr):
    lp = lnprior(theta)
    if not np.isfinite(lp):
        return -np.inf
    return lp + lnlike(theta, x, y, yerr)


nll = lambda *args: -lnlike(*args)
result = op.minimize(nll, [m_true, b_true, np.log(f_true)], args=(x, y, yerr))
m_ml, b_ml, lnf_ml = result["x"]

init = [0.5, m_ml, b_ml, lnf_ml]

ntemps = 10
nwalkers = 100
ndim = 3

pos = np.random.uniform(low=-1, high=1, size=(ntemps, nwalkers, ndim))
for i in range(ntemps):
    pos[i:, :] = np.array([result["x"] + 1e-4*np.random.randn(ndim) for i in range(nwalkers)])

sampler = PTSampler(ntemps, nwalkers, ndim, lnlike, lnprior, loglargs=(x, y, yerr), threads=4) # args=(x, y, yerr))

#burn-in 
print(pos.shape)
sampler.run_mcmc(pos, 100)
sampler.reset()
sampler.run_mcmc(pos, 5000, thin=10)
samples = sampler.chain.reshape((-1, ndim))

print('Number of posterior samples is {}'.format(samples.shape[0]))

#print best fit value together with errors

p1, p2, p3 = map(lambda v: (v[1], v[2]-v[1], v[1]-v[0]),
                             zip(*np.percentile(samples, [16, 50, 84],
                                                axis=0)))

print(p1, '\n', p2, '\n', p3)

fig = corner.corner(samples, labels=["$m$", "$b$", "$\ln\,f$"],
                      truths=[m_true, b_true, np.log(f_true)])

t2 = time.time()

print('It took {:.3f} s'.format(t2 - t1))

plt.show()

通过corner得到的数字是:

enter image description here

重要的一行是

sampler = PTSampler(ntemps, nwalkers, ndim, lnlike, lnprior, loglargs=(x, y, yerr), threads=4)

我用threads=4代替了Pool

仔细查看此行print(p1, '\n', p2, '\n', p3),它会显示m_trueb_truef_true的值:

(-1.277782877669762, 0.5745273177144817, 2.0813620981463297) 
(4.800481378230051, 3.1747356851201163, 2.245189235990341) 
(-0.9391847529845194, 1.1196053087321716, 3.6017609114364273)

对于f,您需要np.exp(-0.93918),它是0.3909,接近0.534。尽管错误还不错(-1.277除外),但您获得的值接近({{1}与-0.9594相比较,4.84.294相比较)。我的意思是,您希望得到确切的数字吗?使用这种方法,在我的计算机上需要111秒钟才能完成,这正常吗?

让我们尝试一些不同的东西。让我们清楚一点:添加f时,问题并不容易。我将使用f_true(您不需要知道如何使用pymc3,我想检查pymc3找到的结果)。

emcee

摘要是

import time
import numpy as np
import corner
import matplotlib.pyplot as plt
import pymc3 as pm

t1 = time.time()

np.random.seed(6)
# Choose the "true" parameters.
m_true = -0.9594
b_true = 4.294
f_true = 0.534

# Generate some synthetic data from the model.
N = 50
x = np.sort(10 * np.random.rand(N))
yerr = 0.1 + 0.5 * np.random.rand(N)
y_1 = m_true * x + b_true
y = np.abs(f_true * y_1) * np.random.randn(N) + y_1
y += yerr * np.random.randn(N)

plt.plot(x, y, 'o')


with pm.Model() as model: # model specifications in PyMC3 are wrapped in a with-statement
    # Define priors
    f = pm.HalfCauchy('f', beta=5)
    m = pm.Normal('m', 0, sd=20)
    b = pm.Normal('b', 0, sd=20)

    mu2 = b + m * x
    sigma2 = yerr**2 + f**2 * (y_1)**2

    post = pm.Normal('y', mu=mu2, sd=pm.math.sqrt(sigma2), observed=y)

with model:
    trace = pm.sample(2000, tune=2000)

print(pm.summary(trace))
pm.traceplot(trace)

all_values = np.stack([trace.get_values('b'), trace.get_values('m'), trace.get_values('f')], axis=1)

fig2 = corner.corner(all_values, labels=["$b$", "$m$", "$f$"],
                      truths=[b_true, m_true, f_true])

t2 = time.time()

print('It took {:.3f} s'.format(t2 - t1))

plt.show()

重要的部分是列 mean sd mc_error hpd_2.5 hpd_97.5 n_eff Rhat m -0.995545 0.067818 0.001174 -1.123187 -0.857653 2685.610018 1.000121 b 4.398158 0.332526 0.005585 3.767336 5.057909 2746.736563 1.000201 f 0.425442 0.063884 0.000904 0.311037 0.554446 4195.591204 1.000309 ,您会看到mean找到的值接近真实值。 pymc3hpd_2.5列是hpd_97.5fb的错误。花了14秒。

我用m得到的数字是

enter image description here

您会说corner的结果不是很好,但是如果您确实想要更高的准确性,则必须修改此函数:

emcee

著名的prior。在这种情况下,它是平坦的,并且由于有很多先验...