文章目录
在用LSTM+CRF做命名实体识别任务时,由于pytorch框架的crf需要自己实现,网上的很多教程都跳过了一些关键部分导致自己难以理解。本文用来记录自己的相关理解,仅针对线性链式的CRF。欢迎指正。
1. log linear model
CRF、MEMM、N元逻辑回归都属于log linear model。我们先来理解这个大类。
p
(
y
∣
x
;
w
∣
J
∣
)
=
exp
(
w
∣
J
∣
⋅
F
∣
J
∣
(
x
,
y
)
)
∑
y
′
∈
Y
exp
(
w
∣
J
∣
⋅
F
∣
J
∣
(
x
,
y
′
)
)
p ( y | x ; \boldsymbol { w }_{|J|} ) = \frac { \exp ( \boldsymbol { w }_{|J|} \cdot \boldsymbol F_{|J|} ( x , y ) ) } { \sum _ { y ^ { \prime } \in \mathcal { Y } } \exp \left( \boldsymbol { w }_{|J|} \cdot \boldsymbol F_{|J|} \left( x , y ^ { \prime } \right) \right) }
p(y∣x;w∣J∣)=∑y′∈Yexp(w∣J∣⋅F∣J∣(x,y′))exp(w∣J∣⋅F∣J∣(x,y))
其中
w
\boldsymbol { w }
w为模型参数,
F
∣
J
∣
(
x
,
y
)
\boldsymbol { F }_{|J|}( x , y )
F∣J∣(x,y)为给定输入特征
x
x
x,输出标签
y
y
y的特征向量。
注意:这里模型参数和特征向量都为J, 物理意义是该模型一共有J个特征。点乘表示用这J个特征计算一个分数。与NLP任务中输入序列长度无关!
1.2 逻辑回归
各种log linear model模型的区别,仅仅是在特征函数 F ∣ J ∣ ( x , y ) \boldsymbol { F }_{|J|}( x , y ) F∣J∣(x,y)的定义不同。对于逻辑回归,假设特征x长度为M, 标签类别数为N, 那么 J = M ∗ N J=M*N J=M∗N。且 F j = f l a t e n ( x × I y = C ) F_j=flaten(\boldsymbol x \times \boldsymbol I_{y=C}) Fj=flaten(x×Iy=C)
1.1 CRF与逻辑回归的区别
CRF与逻辑回归的不同,在于
- (1)CRF的特征函数
F
∣
J
∣
(
x
,
y
)
\boldsymbol { F }_{|J|}( x , y )
F∣J∣(x,y)考虑了输入数据中的时序信息
F ∣ J ∣ ( x , y ) = ∑ i = 2 T f ∣ J ∣ ( x i , y i , y i − 1 ) (1.1) \boldsymbol { F }_{|J|}( x , y )=\sum_{i=2}^Tf_{|J|}(x_i, y_i, y_{i-1}) \tag{1.1} F∣J∣(x,y)=i=2∑Tf∣J∣(xi,yi,yi−1)(1.1) - (2)CRF的y与x都增加了一个维度,即序列长度T
2. NER中的LSTM+CRF
2.1 CRF的特征定义
对于NER任务中,序列长度为T,标签类别数为n的数据,LSTM的输出特征矩阵 B T × n B_{T\times n} BT×n作为CRF层的输入, B i , j B_{i,j} Bi,j为第 i i i个时间步为标签 j j j的概率。NER任务的CRF中我们定义了两个特征函数:
- 输入特征B (代码中的feats, 可以理解为发射矩阵emission)
- 和转移特征A (代码中的transition矩阵)
权重
w
=
[
1
,
1
]
w=[1,1]
w=[1,1] (这里之所以可以直接假设权重值,是因为训练过程中LSTM层的输出分布B、转移分数A分布可以动态调整,因此w可以设置固定值)
现在重写CRF的特征如下,并将其定义为score:
s
c
o
r
e
(
y
∣
A
,
B
)
=
w
∣
J
∣
⋅
F
∣
J
∣
(
x
,
y
)
)
=
w
⋅
∑
i
=
2
T
f
∣
J
∣
(
x
i
,
y
i
,
y
i
−
1
)
=
B
1
,
y
1
+
∑
i
=
2
T
(
B
i
,
y
i
+
A
y
i
−
1
,
y
i
)
\begin{aligned} score(y|A,B) &=\boldsymbol { w }_{|J|} \cdot \boldsymbol F_{|J|} ( x , y ) )\\ &=\boldsymbol { w } \cdot \sum_{i=2}^Tf_{|J|}(x_i, y_i, y_{i-1})\\ &=B_{1, y_1}+\sum_{i=2}^T(B_{i,y_i} + A_{y_{i-1},y_i}) \end{aligned}
score(y∣A,B)=w∣J∣⋅F∣J∣(x,y))=w⋅i=2∑Tf∣J∣(xi,yi,yi−1)=B1,y1+i=2∑T(Bi,yi+Ayi−1,yi)
理解了这两个特征,就成功的将CRF于NER任务结合了。下面要知道如何估计特征参数,即反向传播A和B。
2.2 参数估计
CRF的参数估计使用的是最大似然法,损失函数 l o g _ l i k e h o o d log\_likehood log_likehood也就是对数似然函数。
对于一个训练样本,有一个输入序列x和一个tag序列y。x经过LSTM层得到特征矩阵B。
我们的目标是求现有参数下的概率
p
(
y
∣
A
,
B
)
p(\boldsymbol y|A, B)
p(y∣A,B),并最大化这个值,按照老规矩使用其负对数作为loss, 回到log-linear model的定义,:
l
o
s
s
=
−
l
o
g
(
p
(
y
∣
A
,
B
)
)
=
−
l
o
g
(
e
x
p
(
s
c
o
r
e
(
y
∣
A
,
B
)
)
∑
y
^
e
x
p
(
s
c
o
r
e
(
y
^
∣
A
,
B
)
)
)
=
l
o
g
(
∑
y
^
e
x
p
(
s
c
o
r
e
(
y
^
∣
A
,
B
)
)
)
−
s
c
o
r
e
(
y
∣
A
,
B
)
=
l
o
g
_
s
u
m
_
e
x
p
(
s
c
o
r
e
(
y
^
∣
A
,
B
)
)
)
−
s
c
o
r
e
(
y
∣
A
,
B
)
\begin{aligned} loss &= -log(p(\boldsymbol y|A,B) )\\ &= -log(\frac{exp(score(y|A,B))}{\sum_{\hat y}exp(score(\hat y|A,B))})\\ &=log(\sum_{\hat y}exp(score(\hat y|A,B))) - score(y|A,B)\\ &=log\_sum\_exp(score(\hat y|A,B)))- score(y|A,B) \end{aligned}
loss=−log(p(y∣A,B))=−log(∑y^exp(score(y^∣A,B))exp(score(y∣A,B)))=log(y^∑exp(score(y^∣A,B)))−score(y∣A,B)=log_sum_exp(score(y^∣A,B)))−score(y∣A,B)
一旦loss确定,剩下的事就可以交给pytorch框架来自动优化了。但是上面这个loss怎么计算呢? s c o r e ( y ∣ A , B ) score(y|A,B) score(y∣A,B)这一项好说,线性复杂度O(T)。
2.3 全局正则项的计算推导
Z
=
l
o
g
(
∑
y
^
e
x
p
(
s
c
o
r
e
(
y
^
∣
A
,
B
)
)
)
Z = log(\sum_{\hat y}exp(score(\hat y|A,B)))
Z=log(∑y^exp(score(y^∣A,B)))这一项,如果用暴力计算,就是要先算出每一个时间步的所有可能路径,复杂度为
O
(
T
n
T
)
O(Tn^T)
O(TnT), 类别数目
n
n
n稍多一点就会爆炸。需要想办法消掉指数复杂度,而很巧的是,这确实可以在输入序列上转换为子问题,从而使用动态规划算法。根据上述score的计算公式,可以将输入序列长度为
T
T
T的正则项写为:
Z
=
l
o
g
(
∑
y
^
e
x
p
(
s
c
o
r
e
(
y
^
(
1
,
T
−
1
)
∣
A
,
B
)
+
s
c
o
r
e
(
y
^
(
T
−
1
,
T
)
∣
A
,
B
)
)
)
=
l
o
g
(
∑
y
^
(
e
s
c
o
r
e
(
y
^
(
1
,
T
−
1
)
∣
A
,
B
)
⋅
e
s
c
o
r
e
(
y
^
(
T
−
1
,
T
)
∣
A
,
B
)
)
)
Z=log(\sum_{\hat y}exp(score(\hat y^{(1,T-1)}|A,B)+score(\hat y^{(T-1,T)}|A,B)))\\ =log(\sum_{\hat y}(e^{score(\hat y^{(1,T-1)}|A,B)}\cdot e^{score(\hat y^{(T-1,T)}|A,B)}))
Z=log(y^∑exp(score(y^(1,T−1)∣A,B)+score(y^(T−1,T)∣A,B)))=log(y^∑(escore(y^(1,T−1)∣A,B)⋅escore(y^(T−1,T)∣A,B)))
注意这里
s
c
o
r
e
(
y
^
(
T
−
1
,
T
)
∣
A
,
B
)
=
B
T
,
y
T
+
A
y
T
−
1
,
y
T
score(\hat y^{(T-1,T)}|A,B)=B_{T,y_T} + A_{y_{T-1},y_T}
score(y^(T−1,T)∣A,B)=BT,yT+AyT−1,yT,表示所有路径在第T-1到第T步增加的分数,有
n
2
n^2
n2个值,将其作为系数,合并同类项:
Z
(
T
)
=
l
o
g
(
∑
e
s
c
o
r
e
(
y
^
(
T
−
1
,
T
)
∣
A
,
B
)
)
∑
y
^
(
e
s
c
o
r
e
(
y
^
(
1
,
T
−
1
)
∣
A
,
B
)
)
=
Z
(
T
−
1
)
+
l
o
g
_
s
u
m
_
e
x
p
(
s
c
o
r
e
(
y
^
(
T
−
1
,
T
)
∣
A
,
B
)
)
Z^{(T)}=log(\sum e^{score(\hat y^{(T-1,T)}|A,B)}) \sum_{\hat y}(e^{score(\hat y^{(1,T-1)}|A,B)})\\ =Z^{(T-1)}+log\_sum\_exp(score(\hat y^{(T-1,T)}|A,B))
Z(T)=log(∑escore(y^(T−1,T)∣A,B))y^∑(escore(y^(1,T−1)∣A,B))=Z(T−1)+log_sum_exp(score(y^(T−1,T)∣A,B))
到这里就该知道是标准的动态规划了,并且时间复杂度为
O
(
T
n
2
)
O(Tn^2)
O(Tn2)。
3. 一码两用:锁定CRF转移矩阵参数等价于交叉熵损失
通过锁定CRF中transition矩阵的参数,即将里面的每一个值都初始化为0,并且训练过程中不更新这一层的参数。那么这时的损失函数变为下面这个式子:
l
o
s
s
=
−
l
o
g
(
p
(
y
∣
B
)
)
=
−
l
o
g
(
e
x
p
(
s
c
o
r
e
(
y
∣
B
)
)
∑
y
^
e
x
p
(
s
c
o
r
e
(
y
^
∣
A
,
B
)
)
)
=
l
o
g
(
∑
y
^
e
x
p
(
s
c
o
r
e
(
y
^
∣
B
)
)
)
−
s
c
o
r
e
(
y
∣
B
)
=
Z
−
s
c
o
r
e
(
y
∣
B
)
\begin{aligned} loss &= -log(p(\boldsymbol y|B) )\\ &= -log(\frac{exp(score(y|B))}{\sum_{\hat y}exp(score(\hat y|A,B))})\\ &=log(\sum_{\hat y}exp(score(\hat y|B))) - score(y|B)\\ &=Z- score(y|B) \end{aligned}
loss=−log(p(y∣B))=−log(∑y^exp(score(y^∣A,B))exp(score(y∣B)))=log(y^∑exp(score(y^∣B)))−score(y∣B)=Z−score(y∣B)
由于转移分数全部为0,因此
s
c
o
r
e
(
y
^
∣
B
)
score(\hat y|B)
score(y^∣B)实际上等于整个发射矩阵的和:
Z
=
l
o
g
(
∑
y
^
e
x
p
(
∑
i
=
1
T
∑
j
=
1
n
B
i
j
)
)
Z=log(\sum_{\hat y}exp(\sum_{i=1}^T\sum_{j=1}^nB_ij))
Z=log(y^∑exp(i=1∑Tj=1∑nBij))
所以有:
l
o
s
s
=
Z
−
s
c
o
r
e
(
y
∣
B
)
=
l
o
g
(
∑
y
^
e
x
p
(
∑
i
=
1
T
∑
j
=
1
n
B
i
,
j
)
)
−
∑
i
=
1
T
B
i
,
y
′
=
∑
i
=
1
T
(
l
o
g
∑
y
^
e
∑
j
=
1
n
B
i
,
j
−
l
o
g
(
e
B
i
,
y
′
)
)
=
−
∑
i
=
1
T
l
o
g
e
B
i
,
y
′
∑
y
^
e
∑
j
=
1
n
B
i
,
j
\begin{aligned} loss &= Z-score(y|B) \\ &=log(\sum_{\hat y}exp(\sum_{i=1}^T\sum_{j=1}^nB_{i,j})) - \sum_{i=1}^TB_{i,y'}\\ &=\sum_{i=1}^T(log\sum_{\hat y}e^{\sum_{j=1}^nB_{i,j}}-log(e^{B_{i,y'}}))\\ &=-\sum_{i=1}^Tlog\frac{e^{B_{i,y'}}}{\sum_{\hat y}e^{\sum_{j=1}^nB_{i,j}}} \end{aligned}
loss=Z−score(y∣B)=log(y^∑exp(i=1∑Tj=1∑nBi,j))−i=1∑TBi,y′=i=1∑T(logy^∑e∑j=1nBi,j−log(eBi,y′))=−i=1∑Tlog∑y^e∑j=1nBi,jeBi,y′
其中
B
i
,
y
′
B_{i,y'}
Bi,y′为真实标签对应分数。最小化这个损失相当于最大化每个时间步的真实标签对应的emission分数。与标准的softmax+交叉熵损失等价。