我正在处理一个包含物联网设备数据的数据集,我发现隐藏马尔可夫模型对我的用例非常有效。因此,我试图修改我在Tensorflow教程中找到的一些代码,教程链接在这里。与教程中显示的计数数据相比,该数据集包含观测变量的实数值。
特别是,我认为需要进行以下更改,以便HMM具有正态分布的发射。不幸的是,我找不到任何代码来改变模型以使用除泊松分布之外的其他发射分布。
我应该如何更改代码以发出正态分布的值?
# 定义表示未知对数率的变量trainable_log_rates = tf.Variable( np.log(np.mean(observed_counts)) + tf.random.normal([num_states]), name='log_rates')hmm = tfd.HiddenMarkovModel( initial_distribution=tfd.Categorical( logits=initial_state_logits), transition_distribution=tfd.Categorical(probs=transition_probs), observation_distribution=tfd.Poisson(log_rate=trainable_log_rates), num_steps=len(observed_counts))rate_prior = tfd.LogNormal(5, 5)def log_prob(): return (tf.reduce_sum(rate_prior.log_prob(tf.math.exp(trainable_log_rates))) + hmm.log_prob(observed_counts))optimizer = tf.keras.optimizers.Adam(learning_rate=0.1)@tf.function(autograph=False)def train_op(): with tf.GradientTape() as tape: neg_log_prob = -log_prob() grads = tape.gradient(neg_log_prob, [trainable_log_rates])[0] optimizer.apply_gradients([(grads, trainable_log_rates)]) return neg_log_prob, tf.math.exp(trainable_log_rates)
回答:
@的回答是正确的,在Tensorflow发布的示例中,你有一个隐藏马尔可夫模型,具有均匀的零分布([0.,0.,0.,0.])
,一个重对角线的转移矩阵,以及泊松分布的发射概率。
为了适应你的“正态”示例,你只需要将这些概率更改为正态分布。作为一个起点,假设你的发射概率是具有以下参数的正态分布:
training_loc = tf.Variable([0.,0.,0.,0.])training_scale = tf.Variable([1.,1.,1.,1.])
那么你的observation_distribution
将是:
observation_distribution = tfp.distributions.Normal(loc= training_loc, scale=training_scale )
最后,你还需要更改关于这些参数的先验知识,设置prior_loc
、prior_scale
。你可能希望考虑使用非信息性/弱信息性的先验,因为我看到你随后会对模型进行拟合。
所以你的代码应该类似于:
# 定义发射概率training_loc = tf.Variable([0.,0.,0.])training_scale = tf.Variable([1.,1.,1.])observation_distribution = tfp.distributions.Normal(loc= training_loc, scale=training_scale ) #更改为你想要的分布hmm = tfd.HiddenMarkovModel( initial_distribution=tfd.Categorical( logits=initial_state_logits), transition_distribution=tfd.Categorical(probs=transition_probs), observation_distribution=observation_distribution, num_steps=len(observed_counts))# 先验分布prior_loc = tfd.Normal(loc=0., scale=1.)prior_scale = tfd.HalfNormal(scale=1.)def log_prob(): log_probability = hmm.log_prob(data)#在这里使用你的训练数据 # 计算观测分布的均值和标准差的先验的对数概率 log_probability += tf.reduce_sum(prior_mean.log_prob(observation_distribution.loc)) log_probability += tf.reduce_sum(prior_scale.log_prob(observation_distribution.scale)) # 返回负对数概率,因为我们希望最小化这个量 return log_probability optimizer = tf.keras.optimizers.Adam(learning_rate=0.1)# 最后像示例中那样训练模型losses = tfp.math.minimize( lambda: -log_prob(), optimizer=tf.optimizers.Adam(learning_rate=0.1), num_steps=100)
所以现在,如果你查看你的参数training_loc
和training_scale
,它们应该已经拟合了值。