命名实体识别任务,先实现基于窗口的基线模型,然后进阶到RNN和GRU。中间利用对自动机的模拟和推导展示RNN的缺点,演示梯度剪裁的作用。这是Latex解答,代码已提交,最后还有一个彩蛋。
命名实体识别初步
定位命名实体并将其分类到:
-
人名PER
-
组织名ORG
-
地名LOC
-
其他MISC
加上非命名实体O一共5类。连续的标注视为同一个实体。比如样本$x^{(t)}$与标注$y^{(t)}$以及预测结果$\hat{y}^{(t)}$:
系统一共识别出3个命名实体,在token级别和entity级别各有评测方法。
token级别
-
P值为预测出的正确非O标签比上预测出的全部非O标签,于是$p=\frac{3}{4}$
-
R值为预测出的正确非O标签比上正确答案的全部非O标签,于是$r=\frac{3}{6}$
-
$F_1$值是两者的调和平均:$F_1=\frac{2pr}{p+r}=\frac{6}{10}$
entity级别
-
P值为完美(不残缺不多余)识别的实体数量比上预测出的所有实体数量,于是$p=\frac{1}{3}$
-
R值为完美识别的实体数量比上正确答案中的实体数量,于是$r=\frac{1}{3}$
-
$F_1$值是两者的调和平均:$F_1=\frac{2pr}{p+r}=\frac{1}{3}$
1 A window into NER
基线模型使用半径$w$窗口中的特征$\boldsymbol{\tilde{x}}^{(t)}$预测$\boldsymbol{y}^{(t)}$ :
模型为一个以ReLU为激活函数的隐藏层的神经网络,输出层为softmax,损失函数为交叉熵:
$$\begin{align}
%
\boldsymbol{e}^{(t)} &= [ \boldsymbol{x}^{(t-w)}L, \dots, \boldsymbol{x}^{(t)}L, \dots, \boldsymbol{x}^{(t+w)}L ] \nonumber \\
%
\boldsymbol{h}^{(t)} &= \text{ReLU}(\boldsymbol{e}^{(t)}W + \boldsymbol{b}_{1}) \nonumber \\
%
\hat{\boldsymbol{y}}^{(t)} &= \text{softmax}(\boldsymbol{h}^{(t)}U + \boldsymbol{b}_{2}) \nonumber \\
%
J &= \text{CE}(\boldsymbol{y}^{(t)}, \hat{\boldsymbol{y}}^{(t)}) \nonumber \\
%
\text{CE}(\boldsymbol{y}^{(t)}, \hat{\boldsymbol{y}}^{(t)}) &= -\sum_{i} y_{i}^{(t)} \log(\hat{y}_{i}^{(t)})\text{ , } \nonumber
\end{align}$$
其中$L \in \mathbb{R}^{V \times D}$是词嵌入,$\boldsymbol{h}^{(t)}$ 维度为 $H$,$\hat{\boldsymbol{y}}^{(t)}$ 维度 $C$, $V$是词表大小,$D$ 是词嵌入维度,$H$是隐藏层维度,$C$是分类数目(此处为5)。
a 概念
请列举有歧义的命名实体?
太多了:
方地/nr, 的/ude1, 茶/n, 喝/vg, 个/q, 一罐/mq
通常命名实体中含有低频词,为了泛化必须引入除了字符之外的特征,比如词性。这次作业为了简单,只使用字符特征。
b 维度和复杂度
如果窗口大小为$w$,则窗口特征$\boldsymbol{e}^{(t)}$的维度是$(2w + 1) \times D$的行向量。$W$是$((2w + 1) \times D)\times H$的矩阵。$U$是$H \times C$的矩阵。
对长$T$的句子来讲,计算复杂度是$O((2w+1)DHT)$,这是因为从输入到隐藏层是计算瓶颈。
c 实现基线模型
就贴个最重要的predict方法吧:
def add_prediction_op(self): """Adds the 1-hidden-layer NN: h = Relu(xW + b1) h_drop = Dropout(h, dropout_rate) pred = h_dropU + b2 Recall that we are not applying a softmax to pred. The softmax will instead be done in the add_loss_op function, which improves efficiency because we can use tf.nn.softmax_cross_entropy_with_logits When creating a new variable, use the tf.get_variable function because it lets us specify an initializer. Use tf.contrib.layers.xavier_initializer to initialize matrices. This is TensorFlow's implementation of the Xavier initialization trick we used in last assignment. Note: tf.nn.dropout takes the keep probability (1 - p_drop) as an argument. The keep probability should be set to the value of dropout_rate. Returns: pred: tf.Tensor of shape (batch_size, n_classes) """ x = self.add_embedding() dropout_rate = self.dropout_placeholder ### YOUR CODE HERE (~10-20 lines) b1 = tf.get_variable(name='b1', shape = [self.config.hidden_size,], \ initializer=tf.contrib.layers.xavier_initializer(seed=1)) b2 = tf.get_variable(name='b2', shape = [self.config.n_classes], \ initializer=tf.contrib.layers.xavier_initializer(seed=2)) W = tf.get_variable(name='W', shape = [self.config.n_window_features * self.config.embed_size, self.config.hidden_size], \ initializer=tf.contrib.layers.xavier_initializer(seed=3)) U = tf.get_variable(name='U', shape = [self.config.hidden_size, self.config.n_classes], \ initializer=tf.contrib.layers.xavier_initializer(seed=4)) z1 = tf.matmul(x,W) + b1 h = tf.nn.relu(z1) h_drop = tf.nn.dropout(h, dropout_rate) pred = tf.matmul(h_drop,U) + b2 ### END YOUR CODE return pred
d 分析结果
DEBUG:Token-level confusion matrix: go\gu PER ORG LOC MISC O PER 2968 26 84 16 55 ORG 147 1621 131 65 128 LOC 48 88 1896 26 36 MISC 37 40 54 1030 107 O 42 46 18 39 42614 DEBUG:Token-level scores: label acc prec rec f1 PER 0.99 0.92 0.94 0.93 ORG 0.99 0.89 0.77 0.83 LOC 0.99 0.87 0.91 0.89 MISC 0.99 0.88 0.81 0.84 O 0.99 0.99 1.00 0.99 micro 0.99 0.98 0.98 0.98 macro 0.99 0.91 0.89 0.90 not-O 0.99 0.89 0.87 0.88 INFO:Entity level P/R/F1: 0.82/0.85/0.84
最拖后腿的是机构名识别,经常误识别为人名或非NER。
由于窗口的限制,模型不擅长做完整连续的识别,如果增大窗口则会有所进步。
窗口=2
DEBUG:Token-level confusion matrix: go\gu PER ORG LOC MISC O PER 2995 23 50 10 71 ORG 148 1679 96 52 117 LOC 54 65 1910 24 41 MISC 40 51 48 1029 100 O 34 42 25 29 42629 DEBUG:Token-level scores: label acc prec rec f1 PER 0.99 0.92 0.95 0.93 ORG 0.99 0.90 0.80 0.85 LOC 0.99 0.90 0.91 0.90 MISC 0.99 0.90 0.81 0.85 O 0.99 0.99 1.00 0.99 micro 0.99 0.98 0.98 0.98 macro 0.99 0.92 0.89 0.91 not-O 0.99 0.91 0.88 0.90 INFO:Entity level P/R/F1: 0.85/0.87/0.86
q3_gru.py add_prediction_op() 中dynamic_rnn应该取output而不是state吧?
outputs, state = tf.nn.dynamic_rnn(cell, x, dtype=tf.float32)
output = outputs[:, -1]
preds = tf.sigmoid(output)
代码提示里有写“returns the final state as a prediction”
3 GRU–a latch–ii这道题目的最后一种情况,即h(t−1)=1, x(t)=1,为何h~(t)必须为0?是否可以是这种情况:h~(t)=1, 而z(t)=0,仍然可以使h(t)=1。
博主请抽空指点一下,谢谢
3 GRU a latch ii这个题的最后一种情况,当x_t=h_t=1时,h~t为什么只能为0?h~t和z_t同为1,h_t也能为1,对不对?楼主能抽空答疑一下吗,谢谢。
谢谢博主= =!
因为用的win10,作业要求用python2.7,但没有对应的tensorFlow版本….(也是醉了)
全靠您的代码,我才可以校对
很谢谢