尝试一下使用双向LSTM加CRF来进行分词,使用的语料为Bakeoff 2005。
可以将分词看成一个序列标注问题,我们要做的是对句子中的每个字打上标签(s,b,m,e),s表示单字词,b表示词的开始,m表示词的中间,e表示词的结束,例如:
词 | 标签 |
---|---|
将 | s |
举行 | be |
音乐会 | bme |
波澜壮阔 | bmme |
假设输入的句子表示为 X = ( x 1 , x 2 , . . . , x n ) X=(x_1,x_2,...,x_n) X=(x1,x2,...,xn),P为双向LSTM的输出经过全连接层后映射的分数矩阵,其维度为 n × k n\times k n×k,k为标签的个数。 P i , j P_{i,j} Pi,j表示句子中第i个字对应的的第j个标签的分数。预测的标签序列表示为 y = ( y 1 , y 2 , . . . , y n ) y=(y_1, y_2,..., y_n) y=(y1,y2,...,yn),定义其分数为:
s ( X , y ) = ∑ i = 0 n A y i , y i + 1 + ∑ i = 0 n P i , y i s(X, y)=\sum_{i=0}^n{A_{y_i,y_{i+1}}} + \sum_{i=0}^nP_{i, y_i} s(X,y)=i=0∑nAyi,yi+1+i=0∑nPi,yi其中,A表示标签的转移矩阵, A i , j A_{i,j} Ai,j表示标签i与标签j之间的过渡的分数,A为模型训练的参数矩阵。 y 0 y_0 y0和 y n y_n yn表示一个句子的开始和结束标签。对所有可能的标签序列进行softmax就是某个预测标签序列的概率: p ( y ∣ X ) = e s ( X ∣ y ) ∑ y ~ ∈ Y X e s ( X ∣ y ~ ) p(y|X)=\frac{e^{s(X|y)}}{\sum_{\tilde{y}\in Y_X}e^{s(X|\tilde{y})}} p(y∣X)=∑y~∈YXes(X∣y~)es(X∣y),在训练时,最小化其负对数似然: − l o g ( p ( y ∣ X ) ) = − s ( X ∣ y ) + l o g ( ∑ y ~ ∈ Y X e s ( X ∣ y ~ ) ) -log(p(y|X))=-s(X|y)+log(\sum_{\tilde{y}\in Y_X}e^{s(X|\tilde{y})}) −log(p(y∣X))=−s(X∣y)+log(y~∈YX∑es(X∣y~))其中, Y X Y_X YX表示句子X所有可能的标签序列,计算后一项需要使用递推计算的技巧,在解码时我们需要利用viterbi算法找出分数最高的标签序列作为输出: y ∗ = argmax y ~ ∈ Y X s ( X , y ~ ) y^*=\underset{\tilde{y}\in Y_X}{\operatorname{argmax}}s(X,\tilde{y}) y∗=y~∈YXargmaxs(X,y~)对于递推计算和viterbi算法的解释,可以参考:
我按照上述教程1写了个简单的示例,但不支持batch训练。所以本文改而使用pytorch-crf库演示分词效果。
代码详见GitHub:https://github.com/uhauha2929/ML_learn/blob/master/NLP/CRF/bilstm_crf2.py
对该语料测试集进行测试,并使用该语料自带的评测脚本:
perl scripts/score gold/pku_training_words.utf8 gold/pku_test_gold.utf8 test_segmentation.utf8 > score.utf8
输出文件内容如下:
=== SUMMARY:
=== TOTAL INSERTIONS: 2297
=== TOTAL DELETIONS: 3616
=== TOTAL SUBSTITUTIONS: 7036
=== TOTAL NCHANGE: 12949
=== TOTAL TRUE WORD COUNT: 104372
=== TOTAL TEST WORD COUNT: 103053
=== TOTAL TRUE WORDS RECALL: 0.898
=== TOTAL TEST WORDS PRECISION: 0.909
=== F MEASURE: 0.904
=== OOV Rate: 0.058
=== OOV Recall Rate: 0.499
=== IV Recall Rate: 0.922