簡體   English   中英

PyMC:分層隱馬爾可夫模型

[英]PyMC: Hierachical Hidden Markov Model

這是PyMC的后續工作:Markov系統中的參數估計

我有一個由每個時間步長的位置和速度定義的系統。 系統的行為定義為:

vel = vel + damping * dt
pos =  pos + vel * dt

所以,這是我的PyMC模型。 估計velpos和最重要的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節點傳遞給模型。

另外,請注意,您無需同時調用ModelMCMC 這可以:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM