2

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

#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)。

我可能做错了什么?我最大的担忧是理论上的:我在上一次迭代中使用 A、B 调用 forward_backward 是否正确?或者我应该将我的初始 A,B 用于 forward_backward 的所有迭代,将我的最终 A,B 作为结果的平均值?如果我的代码理论上没问题,还有什么问题?

4

2 回答 2

3

不,您不应该在每个句子之后更新 A 和 B 矩阵;每次通过训练数据时,A 和 B 应该只更新一次。您应该使用上一次迭代的 A 和 B 来计算每个句子的部分计数,然后将这些计数相加以获得新的 A 和 B 以便下一次遍历数据。

程序应该是:

  1. 初始化 A 和 B
  2. 对于每个句子,使用 forward-backward 计算预期计数
  3. 将预期计数相加得到下一个 A 和 B
  4. 重复步骤 2 和 3,直到收敛。
于 2012-11-15T17:14:02.410 回答
2

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

于 2012-11-12T20:11:48.903 回答