这是对PyMC: Parameter estimation in a Markov system
的跟进我有一个系统,它由每个时间步的位置和速度定义。系统的行为定义为:
vel = vel + damping * dt
pos = pos + vel * dt
所以,这是我的PyMC模型。要估算vel
,pos
,最重要的是damping
。
# PRIORS
damping = pm.Normal("damping", mu=-4, tau=(1 / .5**2))
# we assume some system noise
tau_system_noise = (1 / 0.1**2)
# the state consist of (pos, vel); save in lists
# vel: we can't judge the initial velocity --> assume it's 0 with big std
vel_states = [pm.Normal("v0", mu=-4, tau=(1 / 2**2))]
# pos: the first pos is just the observation
pos_states = [pm.Normal("p0", mu=observations[0], tau=tau_system_noise)]
for i in range(1, len(observations)):
new_vel = pm.Normal("v" + str(i),
mu=vel_states[-1] + damping * dt,
tau=tau_system_noise)
vel_states.append(new_vel)
pos_states.append(
pm.Normal("s" + str(i),
mu=pos_states[-1] + new_vel * dt,
tau=tau_system_noise)
)
# we assume some observation noise
tau_observation_noise = (1 / 0.5**2)
obs = pm.Normal("obs", mu=pos_states, tau=tau_observation_noise, value=observations, observed=True)
这是我进行抽样的方式:
mcmc = pm.MCMC([damping, obs, vel_states, pos_states])
mcmc.sample(50000, 25000)
pm.Matplot.plot(mcmc.get_node("damping"))
damping_samples = mcmc.trace("damping")[:]
print "damping -- mean:%f; std:%f" % (mean(damping_samples), std(damping_samples))
print "real damping -- %f" % true_damping
damping
的值由前者支配。即使我改变之前的Uniform或其他什么,情况仍然如此。
我做错了什么?它与前面的例子非常相似,只是与另一层有关。
此问题的完整IPython笔记本可在此处找到:http://nbviewer.ipython.org/github/sotte/random_stuff/blob/master/PyMC%20-%20HMM%20Dynamic%20System.ipynb
[编辑:一些澄清&抽样代码。]
[EDIT2:@Chris的回答没有帮助。我无法使用AdaptiveMetropolis
,因为* _states似乎不是模型的一部分。]
答案 0 :(得分:1)
该模型存在一些问题,再次查看它。首先,您没有将所有PyMC对象添加到模型中。您刚刚添加了[damping, obs]
。您应该将所有PyMC节点传递给模型。
另请注意,您无需同时拨打Model
和MCMC
。这很好:
model = pm.MCMC([damping, obs, vel_states, pos_states])
PyMC的最佳工作流程是将模型保存在与运行逻辑不同的文件中。这样,您只需导入模型并将其传递给MCMC
:
import my_model
model = pm.MCMC(my_model)
或者,您可以将模型编写为函数,返回locals
(或vars
),然后将函数作为MCMC
的参数调用。例如:
def generate_model():
# put your model definition here
return locals()
model = pm.MCMC(generate_model())
答案 1 :(得分:1)
假设您了解模型的结构 - 您正在进行参数估计,而不是系统识别 - 您可以将PyMC模型构建为回归,具有未知阻尼,初始位置和初始速度作为参数以及位置数组,你的观察。
也就是说,PM类表示点质量系统:
pm = PM(true_damping)
positions, velocities = pm.integrate(true_pos, true_vel, N, dt)
# Assume little system noise
std_system_noise = 0.05
tau_system_noise = 1.0/std_system_noise**2
# Treat the real positions as observations
observations = positions + np.random.randn(N,)*std_system_noise
# Damping is modelled with a Uniform prior
damping = mc.Uniform("damping", lower=-4.0, upper=4.0, value=-0.5)
# Initial position & velocity unknown -> assume Uniform priors
init_pos = mc.Uniform("init_pos", lower=-1.0, upper=1.0, value=0.5)
init_vel = mc.Uniform("init_vel", lower=0.0, upper=2.0, value=1.5)
@mc.deterministic
def det_pos(d=damping, pi=init_pos, vi=init_vel):
# Apply damping, init_pos and init_vel estimates and integrate
pm.damping = d.item()
pos, vel = pm.integrate(pi, vi, N, dt)
return pos
# Standard deviation is modelled with a Uniform prior
std_pos = mc.Uniform("std", lower=0.0, upper=1.0, value=0.5)
@mc.deterministic
def det_prec_pos(s=std_pos):
# Precision, based on standard deviation
return 1.0/s**2
# The observations are based on the estimated positions and precision
obs_pos = mc.Normal("obs", mu=det_pos, tau=det_prec_pos, value=observations, observed=True)
# Create the model and sample
model = mc.Model([damping, init_pos, init_vel, det_prec_pos, obs_pos])
mcmc = mc.MCMC(model)
mcmc.sample(50000, 25000)
完整列表如下: https://gist.github.com/stuckeyr/7762371
增加N和减少dt将显着提高您的估计值。
答案 2 :(得分:0)
你的意思是不合理的?它们是否先于之前收缩?阻尼似乎有一个相当紧凑的方差 - 如果你给它一个更加分散的先验呢?
此外,您可以尝试在* _states数组上使用AdaptiveMetropolis
采样器:
my_model.use_step_method(AdaptiveMetropolis, my_model.vel_states)
它有时会更好地混合相关变量,因为这些可能是。
答案 3 :(得分:0)
我认为您的初始方法很好并且应该可以工作,除了“obs”变量未包含在提供给MCMC的节点列表中(参见笔记本中的[10])。包含此变量后,MCMC解算器运行正常,并强制执行模型指定的条件依赖项。我想重复Chris提出的观点,即最好在不同的文件或函数下定义模型以避免这种错误。
你没有得到正确结果的原因是你的先验被任意选择,在某些情况下,这些数值使得模型很难正确混合以便收敛。您的玩具问题试图估计阻尼值,使得位置收敛到观察位置的矢量。为此,您的模型应该能够灵活地在很宽的范围内选择速度和阻尼值,以便在从一个时间步进到下一个时间步时可以纠正位置/速度的随机误差。否则,由于您的Euler集成方案,错误会继续传播。我认为克里斯在他建议选择更加分散的先验时提到了同样的事情。
我建议使用每个Normal变量的tau值。例如,我更改了以下值:
damping = pm.Normal("damping", mu=0, tau=1/20.**2) # was tau=1/2.**2
new_vel = pm.Normal("v" + str(i),
mu=vel_states[-1] + damping * dt,
tau=(1/2.**2)) # was tau=tau_system_noise=(1 / 0.5**2)
tau_observation_noise = (1 / 0.005**2) # was 1 / 0.5**2
您可以看到修改后的文件here。
底部的情节显示位置确实在收敛。速度到处都是。估计的阻尼平均值为6.9,与-1.5非常不同。也许您可以通过为先验选择合适的值来获得更好的估算。