PyMC3中的简单隐马尔可夫模型抛出了Theano错误

时间:2016-08-05 21:59:28

标签: numpy theano hidden-markov-models pymc3

我是PyMC3,Theano和numpy的新手。只是试图在Stan手册中复制第一个“隐藏的”Markov模型 - 实际观察状态的那个。但是,我一直遇到与Theano有关的错误,numpy,以及PyMC3发行版后面发生的事情,这对我来说似乎有些神秘。我的模型代码如下:

import pandas as pd
dat_hmm = pd.read_csv('hmmVals.csv')
emission=dat_hmm.emission.values
state=dat_hmm.state.values

from pymc3 import Model, Dirichlet, Categorical
import numpy as np

basic_model = Model()

with basic_model:
    #Model constants:
    #num unique hidden states, num unique emissions, num instances
    K=3; V=9; T=10 
    alpha=np.ones(K); beta=np.ones(V)
    # Priors for unknown model parameters
    theta = np.empty(K, dtype=object) #theta=transmission
    phi = np.empty(K, dtype=object) #phi=emission
    #observed emission, state:
    w=np.empty(T, dtype=object); z=np.empty(T, dtype=object);
    for k in range(K):
        theta[k]=Dirichlet('theta'+str(k), alpha)
        phi[k]=Dirichlet('phi'+str(k), beta)
    # Likelihood (sampling distribution) of observations
    for t in range(T):
        w[t]=Categorical('w'+str(t),theta[state[t]], shape=1, observed=emission[t])
    for t in range(2, T):
        z[t]=Categorical('z'+str(t),phi[state[t-1]], shape=1,  observed=state[t])

行“w [t] =分类('w'+ str(t),theta [state [t]],shape = 1,observed = emission [t])”生成错误,但不生成错误= 0,填充w0,但在t = 1时生成索引超出范围的错误。代码行本身没有索引超出范围,因为state [1],theta [state [t]]和emission [t]都存在。错误消息是:

    Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/pymc3/distributions/distribution.py", line 25, in __new__
    return model.Var(name, dist, data)
  File "/usr/local/lib/python3.4/dist-packages/pymc3/model.py", line 306, in Var
    var = ObservedRV(name=name, data=data, distribution=dist, model=self)
  File "/usr/local/lib/python3.4/dist-packages/pymc3/model.py", line 581, in __init__
    self.logp_elemwiset = distribution.logp(data)
  File "/usr/local/lib/python3.4/dist-packages/pymc3/distributions/discrete.py", line 400, in logp
    a = tt.log(p[value])
  File "/usr/local/lib/python3.4/dist-packages/theano/tensor/var.py", line 532, in __getitem__
    lambda entry: isinstance(entry, Variable)))
  File "/usr/local/lib/python3.4/dist-packages/theano/gof/op.py", line 668, in __call__
    required = thunk()
  File "/usr/local/lib/python3.4/dist-packages/theano/gof/op.py", line 883, in rval
    fill_storage()
  File "/usr/local/lib/python3.4/dist-packages/theano/gof/cc.py", line 1707, in __call__
    reraise(exc_type, exc_value, exc_trace)
  File "/usr/local/lib/python3.4/dist-packages/six.py", line 686, in reraise
    raise value
IndexError: index out of bounds

我不知道将Numpy对象粘贴到PyMC3发行版中的智慧,或者使用其结果来尝试参数化另一个发行版,但我在Web上看到了一些相似的代码,减去了最后一部分。是否有可能没有好的方法在PyMC3中编写这样一个隐藏的Markov模型呢?

2 个答案:

答案 0 :(得分:2)

我找到了解决上述错误的方法。以下代码有效 - 没有错误,我至少可以使用Metropolis获得正确的参数估计值。

我犯了两个错误,并没有意识到他们是如此简单,因为我期待在Theano中发生一些复杂的事情。一个是我的数据是为Stan设置的,因此索引从1开始而不是0. Python将所有内容索引为0.我通过从每个值中减去1来更改数据文件。另一个错误是我使用theta(传输矩阵)来计算phi矩阵的单个发射,反之亦然。 Theta的排放时间太短了。

我希望我现在能理解的是,为什么NUTS采样器一直告诉我,我有一个非正定的缩放比例,即使我正在给它MAP估计。大都会工作,但很慢 - 这300个观察和1000个样本大约11分钟。另一个谜团是为什么PyMC3认为只花了几秒钟来计算样本。

import pandas as pd

dat_hmm = pd.read_csv('hmmVals.csv')

emission=dat_hmm.emission.values
state=dat_hmm.state.values

from pymc3 import Model, Dirichlet, Categorical
import numpy as np

basic_model = Model()

with basic_model:
    #Model constants:
    K=3; V=9; T=300 #num unique hidden states, num unique emissions, num instances
    alpha=np.ones(K); beta=np.ones(V)
    # Priors for unknown model parameters
    theta = np.empty(K, dtype=object) #theta=transmission
    phi = np.empty(K, dtype=object) #phi=emission
    w=np.empty(T, dtype=object); z=np.empty(T, dtype=object); #observed emission, state
    for k in range(K):
        theta[k]=Dirichlet('theta'+str(k), alpha)
        phi[k]=Dirichlet('phi'+str(k), beta)
    #Likelihood (sampling distribution) of observationss
    for t in range(2, T):
        z[t]=Categorical('z'+str(t),theta[state[t-1]], shape=1,  observed=state[t])
    for t in range(T):
        w[t]=Categorical('w'+str(t),phi[state[t]], shape=1, observed=emission[t])

答案 1 :(得分:1)

我还尝试在pymc3中实现HMM,但我遇到了类似的问题。我刚刚找到了一种以矢量化方式实现两级HMM的方法(说实话,我的模型不是隐藏的,但隐藏的部分可以轻松添加 - 我对状态变量的描述进行了矢量化)。我不确定这是否是最有效的方法,但我针对定义状态的简单for循环测试了此代码。下面的代码在不到一分钟的时间内运行1000个数据点,而for循环需要几个小时。

以下是代码:

import numpy as np
import theano.tensor as tt
import pymc3 as pm

class HMMStates(pm.Discrete):
    """
    Hidden Markov Model States
    Parameters
    ----------
    P1 : tensor
        probability to remain in state 1
    P2 : tensor
        probability to move from state 2 to state 1

    """

    def __init__(self, PA=None, P1=None, P2=None,
                 *args, **kwargs):
        super(HMMStates, self).__init__(*args, **kwargs)
        self.PA = PA
        self.P1 = P1
        self.P2 = P2
        self.mean = 0.

    def logp(self, x):
        PA = self.PA
        P1 = self.P1
        P2 = self.P2

        # now we need to create an array with probabilities
        # so that for x=A: PA=P1, PB=(1-P1)
        # and for x=B: PA=P2, PB=(1-P2)
        length = x.shape[0]
        P1T = tt.tile(P1,(length-1,1)).T
        P2T = tt.tile(P2,(length-1,1)).T

        P = tt.switch(x[:-1],P1T,P2T).T

        x_i = x[1:]
        ou_like = pm.Categorical.dist(P).logp(x_i)
        return pm.Categorical.dist(PA).logp(x[0]) + tt.sum(ou_like)

此类创建HMM的状态。要调用它,您可以执行以下操作:

theta = np.ones(2) # prior for probabilities
with pm.Model() as model:
    # 2 state model
    # P1 is probablility to stay in state 1
    # P2 is probability to move from state 2 to state 1
    P1 = pm.Dirichlet('P1', a=theta)
    P2 = pm.Dirichlet('P2', a=theta)

    PA = pm.Deterministic('PA',P2/(P2+1-P1))

    states = HMMStates('states',PA,P1,P2, observed=data)

    start = pm.find_MAP()

    trace = pm.sample(5000, start=start)

只是为了展示旧代码的样子:

with pm.Model() as model:
    # 2 state model
    # P1 is probablility to stay in state 1
    # P2 is probability to move from state 2 to state 1
    P1 = pm.Dirichlet('P1', a=np.ones(2))
    P2 = pm.Dirichlet('P2', a=np.ones(2))

    PA = pm.Deterministic('PA',P2/(P2+1-P1))

    state = pm.Categorical('state0',PA, observed=data[0])
    for i in range(1,N_chain):
        state = pm.Categorical('state'+str(i), tt.switch(data[i-1],P1,P2), observed=data[i])

    start = pm.find_MAP()

    trace = pm.sample(5000, start=start)