我正在尝试使用PyMC学习简单离散HMM的参数。我正在使用HMM上的Wiki页面为阳光充足的模型建模。该模型如下所示:
我正在使用以下先验。
theta_start_state ~ beta(20,10)
theta_transition_rainy ~beta(8,2)
theta_transition_sunny ~beta(2,8)
theta_emission_rainy ~ Dirichlet(3,4,3)
theta_emission_sunny ~ Dirichlet(10,6,4)
最初,我使用此设置创建如下的训练集。
## Some not so informative priors!
# Prior on start state
theta_start_state = pm.Beta('theta_start_state',12,8)
# Prior on transition from rainy
theta_transition_rainy = pm.Beta('transition_rainy',8,2)
# Prior on transition from sunny
theta_transition_sunny = pm.Beta('transition_sunny',2,8)
# Prior on emission from rainy
theta_emission_rainy = pm.Dirichlet('emission_rainy',[3,4,3])
# Prior on emission from sunny
theta_emission_sunny = pm.Dirichlet('emission_sunny',[10,6,4])
# Start state
x_train_0 = pm.Categorical('x_0',[theta_start_state, 1-theta_start_state])
N = 100
# Create a train set for hidden states
x_train = np.empty(N, dtype=object)
# Creating a train set of observations
y_train = np.empty(N, dtype=object)
x_train[0] = x_train_0
for i in xrange(1, N):
if x_train[i-1].value==0:
x_train[i] = pm.Categorical('x_train_%d'%i,[theta_transition_rainy, 1- theta_transition_rainy])
else:
x_train[i] = pm.Categorical('x_train_%d'%i,[theta_transition_sunny, 1- theta_transition_sunny])
for i in xrange(0,N):
if x_train[i].value == 0:
# Rain
y_train[i] = pm.Categorical('y_train_%d' %i, theta_emission_rainy)
else:
y_train[i] = pm.Categorical('y_train_%d' %i, theta_emission_sunny)
但是,我无法理解如何使用PyMC学习这些参数。我开始如下。
@pm.observed
def y(x=x_train, value =y_train):
N = len(x)
out = np.empty(N, dtype=object)
for i in xrange(0,N):
if x[i].value == 0:
# Rain
out[i] = pm.Categorical('y_%d' %i, theta_emission_rainy)
else:
out[i] = pm.Categorical('y_%d' %i, theta_emission_sunny)
return out
可以找到包含此代码的完整笔记本here。
除此之外:包含高斯的HMM代码的gist真的很难理解! (未记录)
根据以下答案,我尝试按如下方式更改代码:
@pm.stochastic(observed=True)
def y(value=y_train, hidden_states = x_train):
def logp(value, hidden_states):
logprob = 0
for i in xrange(0,len(hidden_states)):
if hidden_states[i].value == 0:
# Rain
logprob = logprob + pm.categorical_like(value[i], theta_emission_rainy)
else:
# Sunny
logprob = logprob + pm.categorical_like(value[i], theta_emission_sunny)
return logprob
下一步是创建模型然后运行MCMC算法。但是,以上
编辑过的代码也行不通。它给出ZeroProbability error
。
我不确定我是否正确解释了答案。
答案 0 :(得分:2)
对此有一些想法:
在您的似然函数中,您需要求和(对于所有时间步骤t)观察值的对数概率(分别为步行,购物和清洁)给出当前(采样)值多雨/晴天(即天气)同时进行步骤t。
<强>学习强>
如果您想学习模型的参数,您可能需要考虑切换到PyMC3,它更适合自动计算logp函数的渐变。但在这种情况下(因为你选择了共轭先验),这不是真正必要的。如果您不知道Conjugate Priors是什么,或者需要概述,请向维基百科询问共轭推荐列表,它有一篇很棒的文章。
根据您的目的,您可以在此处选择一些选项。如果您想从所有参数的后验分布中进行采样,只需像您一样指定您的MCMC模型,然后按推理按钮,之后只绘制并总结您感兴趣的参数的边际分布,然后您完成了。
如果您对边缘后验分布不感兴趣,而是寻找联合 MAP参数,则可以考虑使用期望最大化(EM)学习或模拟退火。两者都应该在MCMC框架内合理地运作。
对于EM学习,只需重复这些步骤直到收敛:
我会使用较小的学习速率因子,因此您不会陷入第一个局部最优(现在我们正在接近模拟退火):而不是将您从MCMC链中生成的N个样本视为实际通过将学习速率因子K / N缩放到超参数的更新,将它们视为K个观察值(对于值K
答案 1 :(得分:1)
突然出现的第一件事就是你的可能性的回报值。 PyMC期望标量返回值,而不是列表/数组。你需要在返回之前对数组求和。
此外,当您使用Dirichlet作为分类的先验时,PyMC会检测到并填写最后一个概率。以下是我对x_train
/ y_train
循环进行编码的方法:
p = []
for i in xrange(1, N):
# This will return the first variable if prev=0, and the second otherwise
p.append(pm.Lambda('p_%i' % i, lambda prev=x_train[i-1]: (theta_transition_rainy, theta_transition_sunny)[bool(prev)]))
x_train[i] = pm.Categorical('x_train_%i' % i, p[-1])
因此,您使用Lambda获取适当的概率,并将其用作分类的参数。