首页 > 代码库 > CS224d 单隐层全连接网络处理英文命名实体识别tensorflow

CS224d 单隐层全连接网络处理英文命名实体识别tensorflow

什么是NER?

命名实体识别(NER)是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。命名实体识别是信息提取、问答系统、句法分析、机器翻译等应用领域的重要基础工具,作为结构化信息提取的重要步骤。

NER具体任务

1.确定实体位置 2.确定实体类别

给一个单词,我们需要根据上下文判断,它属于下面四类的哪一个,如果都不属于,则类别为0,即不是实体,所以这是一个需要分成 5 类的问题:

? Person (PER)? Organization (ORG)? Location (LOC)? Miscellaneous (MISC)

训练数据有两列,第一列是单词,第二列是标签。

EU    ORGrejects    OGerman    MISCPeter    PERBRUSSELS    LOC

2.模型:

输入层的 x^(t) 为以 x_t 为中心的窗口大小为3的上下文语境,x_t 是 one-hot 向量,x_t 与 L 作用后就是相应的词向量,词向量的长度为 d = 50 :

技术分享

建立一个只有一个隐藏层的神经网络,隐藏层维度是 100,y^ 就是得到的预测值,维度是 5:

技术分享

用交叉熵来计算误差:

技术分享

loss(J)对各个参数进行求导:

技术分享

技术分享

链式法则

技术分享

在 TensorFlow 中求导是自动实现的,这里用Adam优化算法更新梯度,不断地迭代,使得loss越来越小直至收敛。

3.具体实现:

def test_NER() 中,我们进行 max_epochs 次迭代,每次,用 training data 训练模型 得到一对 train_loss, train_acc,再用这个模型去预测 validation data,得到一对 val_loss, predictions,我们选择最小的 val_loss,并把相应的参数 weights 保存起来,最后我们是要用这些参数去预测 test data 的类别标签:

def test_NER():  config = Config()  with tf.Graph().as_default():    model = NERModel(config)       init = tf.initialize_all_variables()    saver = tf.train.Saver()    with tf.Session() as session:    # 最好的值时,它的 loss 它的 迭代次数 epoch      best_val_loss = float(‘inf‘)       best_val_epoch = 0      session.run(init)      for epoch in xrange(config.max_epochs):        print ‘Epoch {}‘.format(epoch)        start = time.time()        ###        train_loss, train_acc = model.run_epoch(session, model.X_train,                                                model.y_train)           # 2.用这个model去预测 dev 数据,得到loss 和 prediction        val_loss, predictions = model.predict(session, model.X_dev, model.y_dev)          print ‘Training loss: {}‘.format(train_loss)        print ‘Training acc: {}‘.format(train_acc)        print ‘Validation loss: {}‘.format(val_loss)        if val_loss < best_val_loss:                      best_val_loss = val_loss          best_val_epoch = epoch          if not os.path.exists("./weights"):            os.makedirs("./weights")          saver.save(session, ‘./weights/ner.weights‘)           if epoch - best_val_epoch > config.early_stopping:          break        ###        # 把 dev 的lable数据放进去,计算prediction的confusion        confusion = calculate_confusion(config, predictions, model.y_dev)         print_confusion(confusion, model.num_to_tag)        print ‘Total time: {}‘.format(time.time() - start)      # 再次加载保存过的 weights,用 test 数据做预测,得到预测结果      saver.restore(session, ‘./weights/ner.weights‘)          print ‘Test‘      print ‘=-=-=‘      print ‘Writing predictions to q2_test.predicted‘      _, predictions = model.predict(session, model.X_test, model.y_test)      save_predictions(predictions, "q2_test.predicted")   if __name__ == "__main__":  test_NER()
4.模型训练过程:
  • 首先导入数据 training,validation,test:
# Load the training setdocs = du.load_dataset(‘data/ner/train‘)# Load the dev set (for tuning hyperparameters)docs = du.load_dataset(‘data/ner/dev‘)# Load the test set (dummy labels only)docs = du.load_dataset(‘data/ner/test.masked‘)
  • 把单词转化成 one-hot 向量后,再转化成词向量:
def add_embedding(self):    # The embedding lookup is currently only implemented for the CPU    with tf.device(‘/cpu:0‘):      embedding = tf.get_variable(‘Embedding‘, [len(self.wv), self.config.embed_size])         # lookup window大小的context的word embedding      window = tf.nn.embedding_lookup(embedding, self.input_placeholder)                     window = tf.reshape(        window, [-1, self.config.window_size * self.config.embed_size])      return window
  • 建立神经层,包括用 xavier 去初始化第一层, L2 正则化和用 dropout 来减小过拟合的处理:
def add_model(self, window):    with tf.variable_scope(‘Layer1‘, initializer=xavier_weight_init()) as scope:              W = tf.get_variable(                                                        ‘W‘, [self.config.window_size * self.config.embed_size,                self.config.hidden_size])      b1 = tf.get_variable(‘b1‘, [self.config.hidden_size])      h = tf.nn.tanh(tf.matmul(window, W) + b1)      if self.config.l2:                                                          tf.add_to_collection(‘total_loss‘, 0.5 * self.config.l2 * tf.nn.l2_loss(W))        with tf.variable_scope(‘Layer2‘, initializer=xavier_weight_init()) as scope:      U = tf.get_variable(‘U‘, [self.config.hidden_size, self.config.label_size])      b2 = tf.get_variable(‘b2‘, [self.config.label_size])      y = tf.matmul(h, U) + b2      if self.config.l2:          tf.add_to_collection(‘total_loss‘, 0.5 * self.config.l2 * tf.nn.l2_loss(U))    output = tf.nn.dropout(y, self.dropout_placeholder)                                      return output
  • 用 cross entropy 来计算 loss:
def add_loss_op(self, y):    cross_entropy = tf.reduce_mean(                                             tf.nn.softmax_cross_entropy_with_logits(y, self.labels_placeholder))                   tf.add_to_collection(‘total_loss‘, cross_entropy)            loss = tf.add_n(tf.get_collection(‘total_loss‘))            return loss
  • 接着用 Adam Optimizer 把loss最小化:
 def add_training_op(self, loss):    optimizer = tf.train.AdamOptimizer(self.config.lr)    global_step = tf.Variable(0, name=‘global_step‘, trainable=False)    train_op = optimizer.minimize(loss, global_step=global_step)       return train_op

每一次训练后,得到了最小化 loss 相应的 weights。

完整程序见:code

CS224d 单隐层全连接网络处理英文命名实体识别tensorflow