[英]PyMC: Hierachical Hidden Markov Model
這是PyMC的后續工作:Markov系統中的參數估計
我有一個由每個時間步長的位置和速度定義的系統。 系統的行為定義為:
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似乎不是模型的一部分。]
該模型存在兩個問題,請再次查看。 首先,您沒有將所有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
(或vars
),然后調用該函數作為MCMC
的參數。 例如:
def generate_model():
# put your model definition here
return locals()
model = pm.MCMC(generate_model())
假設您知道模型的結構-您正在進行參數估計,而不是系統識別-您可以將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將顯着改善您的估計。
你說的不合理是什么意思? 他們朝着先前的方向收縮嗎? 阻尼似乎有一個非常緊密的差異-如果您給它一個更分散的先驗會怎樣?
另外,您可以嘗試在* _states數組上使用AdaptiveMetropolis
采樣器:
my_model.use_step_method(AdaptiveMetropolis, my_model.vel_states)
有時,它們對於相關變量的混合效果更好,因為它們可能是這樣。
我認為您的初始方法很好,並且應該可以工作,除了提供給MCMC的節點列表中未包括“ obs”變量(請參閱筆記本中的In [10])。 包含此變量后,MCMC求解器可以正常運行,並且可以強制執行模型指定的條件依賴項。 我想重復克里斯的觀點,最好是在另一個文件中或在函數下定義模型以避免這種錯誤。
之所以不能獲得正確的結果,是因為您的先驗是任意選擇的,並且在某些情況下,這些值使得模型很難正確混合以收斂。 您的玩具問題試圖估計阻尼值,以使位置收斂到觀察位置的向量。 為此,您的模型應具有靈活性,可以在較寬的范圍內選擇速度和阻尼值,以便在從一個時間步長轉到下一個時間步長時,可以校正位置/速度中的隨機誤差。 否則,由於您的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
您可以在此處查看修改后的文件。
底部的圖顯示位置確實在收斂。 到處都是速度。 估計的阻尼平均值為6.9,與-1.5非常不同。 也許您可以通過為先驗選擇適當的值來獲得更好的估計。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.