在Jurafsky + Martin,第2版中实施前向/后向/鲍姆 - 韦尔奇

时间:2012-11-12 18:25:38

标签: algorithm machine-learning nlp

我正在实现前向后/ Baum-Welch算法,如Jurafsky + Martin的语音和语言处理(第2版)中所示,作为词性标注器。我的代码大致结构如下:

#Initialize transition probability matrix A and observation likelihood matrix B
(A,B) = init() #Assume this is correct

#Begin forward-backward/Baum-Welch algorithm
for training_sentence in training_data:
    (A,B) = forward_backward(A,B,training_sentence, vocabulary, hidden_state_set)

#Use new A,B to test
i = 0
for test_sentence in test_data:
    predicted_tag_sequence = viterbi(test_sentence, vocabulary, A,B)
    update_confusion_matrix(predicted_tag_sequence, actual_tag_sequences[i])
    i += 1

我的实现在调用forward_backward之前初始化A和B.然后,用于forward_backward的每次迭代的A,B是从前一次迭代计算的A,B。

我遇到过两个问题:

  1. 在第一次迭代之后,A和B非常稀疏,以至于forward_backward的未来迭代不会产生期望最大化步骤。
  2. 最后的A和B是如此稀疏,以至于在应用Viterbi时,每个单词都被分配了一些任意标记(因为A和B非常稀疏,句子上几乎任何标记序列的概率都是0)。
  3. 我可能做错了什么?我最关心的是理论:我是否正确使用前一次迭代中的A,B调用forward_backward?或者我应该使用我的初始A,B为forward_backward的所有迭代取我的最终A,B作为平均结果?如果我的代码在理论上很好,还有什么可能是错的?

2 个答案:

答案 0 :(得分:3)

不,你不应该在每个句子后更新A和B矩阵;每次通过训练数据时,A和B只应更新一次。您应该使用前一个迭代的A和B来计算每个句子的部分计数,然后对这些计数求和,得到新的A和B,以便下次传递数据。

程序应该是:

  1. 初始化A和B
  2. 对于每个句子,使用向前 - 向后计算预期计数
  3. 总结预期的计数以获得下一个A和B
  4. 重复步骤2和3直到收敛。

答案 1 :(得分:2)

可能是一个数字问题。在你的forward_backward中,你可能会将一大堆小数字相乘,这最终会使产品小于机器精度。如果是这种情况,您可以尝试使用日志。您应该将概率日志加在一起,而不是将“原始”概率相乘。