博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TensorFlow (RNN)深度学习 双向LSTM(BiLSTM)+CRF 实现 sequence labeling 序列标注问题 源码下载...
阅读量:7208 次
发布时间:2019-06-29

本文共 24059 字,大约阅读时间需要 80 分钟。

http://blog.csdn.net/scotfield_msn/article/details/60339415

在TensorFlow (RNN)深度学习下 双向LSTM(BiLSTM)+CRF 实现 sequence labeling 

双向LSTM+CRF跑序列标注问题

源码下载

 

去年底样子一直在做NLP相关task,是个关于序列标注问题。这 sequence labeling属于NLP的经典问题了,开始尝试用HMM,哦不,用CRF做baseline,by the way, 用的CRF++。

关于CRF的理论就不再啰嗦了,街货。顺便提下,CRF比HMM在理论上以及实际效果上都要好不少。但我要说的是CRF跑我这task还是不太乐观。P值0.6样子,R低的离谱,所以F1很不乐观。mentor告诉我说是特征不足,师兄说是这个task本身就比较难做,F1低算是正常了。

 

CRF做完baseline后,一直在着手用BiLSTM+CRF跑 sequence labeling,奈何项目繁多,没有多余的精力去按照正常的计划做出来。后来还是一点一点的,按照大牛们的步骤以及参考现有的代码,把 BiLSTM+CRF的实现拿下了。后来发现,跑出来的效果也不太理想……可能是这个task确实变态……抑或模型还要加强吧~

 

这里对比下CRF与LSTM的cell,先说RNN吧,RNN其实是比CNN更适合做序列问题的模型,RNN隐层当前时刻的输入有一部分是前一时刻的隐层输出,这使得他能通过循环反馈连接看到前面的信息,将一段序列的前面的context capture 过来参与此刻的计算,并且还具备非线性的拟合能力,这都是CRF无法超越的地方。而LSTM的cell很好的将RNN的梯度弥散问题优化解决了,他对门卫gate说:老兄,有的不太重要的信息,你该忘掉就忘掉吧,免得占用现在的资源。而双向LSTM就更厉害了,不仅看得到过去,还能将未来的序列考虑进来,使得上下文信息充分被利用。而CRF,他不像LSTM能够考虑长远的上下文信息,它更多地考虑整个句子的局部特征的线性加权组合(通过特征模板扫描整个句子),特别的一点,他计算的是联合概率,优化了整个序列,而不是拼接每个时刻的最优值。那么,将BILSTM与CRF一起就构成了还比较不错的组合,这目前也是学术界的流行做法~

 

另外针对目前的跑通结果提几个改进点:

1.+CNN,通过CNN的卷积操作去提取英文单词的字母细节。

2.+char representation,作用与上相似,提取更细粒度的细节。

3.考虑将特定的人工提取的规则融入到NN模型中去。

 

好了,叨了不少。codes time:

 

完整代码以及相关预处理的数据请移步github: 

注明:codes参考的是

 

requirements:

ubuntu14

python2.7

tensorflow 0.8

numpy

pandas0.15

 

BILSTM_CRF.py

 

[python]   
 
 
  1. import math  
  2. import helper  
  3. import numpy as np  
  4. import tensorflow as tf  
  5. from tensorflow.models.rnn import rnn, rnn_cell  
  6.   
  7. class BILSTM_CRF(object):  
  8.       
  9.     def __init__(self, num_chars, num_classes, num_steps=200, num_epochs=100, embedding_matrix=None, is_training=True, is_crf=True, weight=False):  
  10.         # Parameter  
  11.         self.max_f1 = 0  
  12.         self.learning_rate = 0.002  
  13.         self.dropout_rate = 0.5  
  14.         self.batch_size = 128  
  15.         self.num_layers = 1     
  16.         self.emb_dim = 100  
  17.         self.hidden_dim = 100  
  18.         self.num_epochs = num_epochs  
  19.         self.num_steps = num_steps  
  20.         self.num_chars = num_chars  
  21.         self.num_classes = num_classes  
  22.           
  23.         # placeholder of x, y and weight  
  24.         self.inputs = tf.placeholder(tf.int32, [None, self.num_steps])  
  25.         self.targets = tf.placeholder(tf.int32, [None, self.num_steps])  
  26.         self.targets_weight = tf.placeholder(tf.float32, [None, self.num_steps])  
  27.         self.targets_transition = tf.placeholder(tf.int32, [None])  
  28.           
  29.         # char embedding  
  30.         if embedding_matrix != None:  
  31.             self.embedding = tf.Variable(embedding_matrix, trainable=False, name="emb", dtype=tf.float32)  
  32.         else:  
  33.             self.embedding = tf.get_variable("emb", [self.num_chars, self.emb_dim])  
  34.         self.inputs_emb = tf.nn.embedding_lookup(self.embedding, self.inputs)  
  35.         self.inputs_emb = tf.transpose(self.inputs_emb, [1, 0, 2])  
  36.         self.inputs_emb = tf.reshape(self.inputs_emb, [-1, self.emb_dim])  
  37.         self.inputs_emb = tf.split(0, self.num_steps, self.inputs_emb)  
  38.   
  39.         # lstm cell  
  40.         lstm_cell_fw = tf.nn.rnn_cell.BasicLSTMCell(self.hidden_dim)  
  41.         lstm_cell_bw = tf.nn.rnn_cell.BasicLSTMCell(self.hidden_dim)  
  42.   
  43.         # dropout  
  44.         if is_training:  
  45.             lstm_cell_fw = tf.nn.rnn_cell.DropoutWrapper(lstm_cell_fw, output_keep_prob=(1 - self.dropout_rate))  
  46.             lstm_cell_bw = tf.nn.rnn_cell.DropoutWrapper(lstm_cell_bw, output_keep_prob=(1 - self.dropout_rate))  
  47.   
  48.         lstm_cell_fw = tf.nn.rnn_cell.MultiRNNCell([lstm_cell_fw] * self.num_layers)  
  49.         lstm_cell_bw = tf.nn.rnn_cell.MultiRNNCell([lstm_cell_bw] * self.num_layers)  
  50.   
  51.         # get the length of each sample  
  52.         self.length = tf.reduce_sum(tf.sign(self.inputs), reduction_indices=1)  
  53.         self.length = tf.cast(self.length, tf.int32)    
  54.           
  55.         # forward and backward  
  56.         self.outputs, _, _ = rnn.bidirectional_rnn(  
  57.             lstm_cell_fw,   
  58.             lstm_cell_bw,  
  59.             self.inputs_emb,   
  60.             dtype=tf.float32,  
  61.             sequence_length=self.length  
  62.         )  
  63.           
  64.         # softmax  
  65.         self.outputs = tf.reshape(tf.concat(1, self.outputs), [-1, self.hidden_dim * 2])  
  66.         self.softmax_w = tf.get_variable("softmax_w", [self.hidden_dim * 2, self.num_classes])  
  67.         self.softmax_b = tf.get_variable("softmax_b", [self.num_classes])  
  68.         self.logits = tf.matmul(self.outputs, self.softmax_w) + self.softmax_b  
  69.   
  70.         if not is_crf:  
  71.             pass  
  72.         else:  
  73.             self.tags_scores = tf.reshape(self.logits, [self.batch_size, self.num_steps, self.num_classes])  
  74.             self.transitions = tf.get_variable("transitions", [self.num_classes + 1, self.num_classes + 1])  
  75.               
  76.             dummy_val = -1000  
  77.             class_pad = tf.Variable(dummy_val * np.ones((self.batch_size, self.num_steps, 1)), dtype=tf.float32)  
  78.             self.observations = tf.concat(2, [self.tags_scores, class_pad])  
  79.   
  80.             begin_vec = tf.Variable(np.array([[dummy_val] * self.num_classes + [0] for _ in range(self.batch_size)]), trainable=False, dtype=tf.float32)  
  81.             end_vec = tf.Variable(np.array([[0] + [dummy_val] * self.num_classes for _ in range(self.batch_size)]), trainable=False, dtype=tf.float32)   
  82.             begin_vec = tf.reshape(begin_vec, [self.batch_size, 1, self.num_classes + 1])  
  83.             end_vec = tf.reshape(end_vec, [self.batch_size, 1, self.num_classes + 1])  
  84.   
  85.             self.observations = tf.concat(1, [begin_vec, self.observations, end_vec])  
  86.   
  87.             self.mask = tf.cast(tf.reshape(tf.sign(self.targets),[self.batch_size * self.num_steps]), tf.float32)  
  88.               
  89.             # point score  
  90.             self.point_score = tf.gather(tf.reshape(self.tags_scores, [-1]), tf.range(0, self.batch_size * self.num_steps) * self.num_classes + tf.reshape(self.targets,[self.batch_size * self.num_steps]))  
  91.             self.point_score *= self.mask  
  92.               
  93.             # transition score  
  94.             self.trans_score = tf.gather(tf.reshape(self.transitions, [-1]), self.targets_transition)  
  95.               
  96.             # real score  
  97.             self.target_path_score = tf.reduce_sum(self.point_score) + tf.reduce_sum(self.trans_score)  
  98.               
  99.             # all path score  
  100.             self.total_path_score, self.max_scores, self.max_scores_pre  = self.forward(self.observations, self.transitions, self.length)  
  101.               
  102.             # loss  
  103.             self.loss = - (self.target_path_score - self.total_path_score)  
  104.           
  105.         # summary  
  106.         self.train_summary = tf.scalar_summary("loss", self.loss)  
  107.         self.val_summary = tf.scalar_summary("loss", self.loss)          
  108.           
  109.         self.optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(self.loss)   
  110.   
  111.     def logsumexp(self, x, axis=None):  
  112.         x_max = tf.reduce_max(x, reduction_indices=axis, keep_dims=True)  
  113.         x_max_ = tf.reduce_max(x, reduction_indices=axis)  
  114.         return x_max_ + tf.log(tf.reduce_sum(tf.exp(x - x_max), reduction_indices=axis))  
  115.   
  116.     def forward(self, observations, transitions, length, is_viterbi=True, return_best_seq=True):  
  117.         length = tf.reshape(length, [self.batch_size])  
  118.         transitions = tf.reshape(tf.concat(0, [transitions] * self.batch_size), [self.batch_size, 6, 6])  
  119.         observations = tf.reshape(observations, [self.batch_size, self.num_steps + 2, 6, 1])  
  120.         observations = tf.transpose(observations, [1, 0, 2, 3])  
  121.         previous = observations[0, :, :, :]  
  122.         max_scores = []  
  123.         max_scores_pre = []  
  124.         alphas = [previous]  
  125.         for t in range(1, self.num_steps + 2):  
  126.             previous = tf.reshape(previous, [self.batch_size, 6, 1])  
  127.             current = tf.reshape(observations[t, :, :, :], [self.batch_size, 1, 6])  
  128.             alpha_t = previous + current + transitions  
  129.             if is_viterbi:  
  130.                 max_scores.append(tf.reduce_max(alpha_t, reduction_indices=1))  
  131.                 max_scores_pre.append(tf.argmax(alpha_t, dimension=1))  
  132.             alpha_t = tf.reshape(self.logsumexp(alpha_t, axis=1), [self.batch_size, 6, 1])  
  133.             alphas.append(alpha_t)  
  134.             previous = alpha_t             
  135.               
  136.         alphas = tf.reshape(tf.concat(0, alphas), [self.num_steps + 2, self.batch_size, 6, 1])  
  137.         alphas = tf.transpose(alphas, [1, 0, 2, 3])  
  138.         alphas = tf.reshape(alphas, [self.batch_size * (self.num_steps + 2), 6, 1])  
  139.   
  140.         last_alphas = tf.gather(alphas, tf.range(0, self.batch_size) * (self.num_steps + 2) + length)  
  141.         last_alphas = tf.reshape(last_alphas, [self.batch_size, 6, 1])  
  142.   
  143.         max_scores = tf.reshape(tf.concat(0, max_scores), (self.num_steps + 1, self.batch_size, 6))  
  144.         max_scores_pre = tf.reshape(tf.concat(0, max_scores_pre), (self.num_steps + 1, self.batch_size, 6))  
  145.         max_scores = tf.transpose(max_scores, [1, 0, 2])  
  146.         max_scores_pre = tf.transpose(max_scores_pre, [1, 0, 2])  
  147.   
  148.         return tf.reduce_sum(self.logsumexp(last_alphas, axis=1)), max_scores, max_scores_pre          
  149.   
  150.     def train(self, sess, save_file, X_train, y_train, X_val, y_val):  
  151.         saver = tf.train.Saver()  
  152.   
  153.         char2id, id2char = helper.loadMap("char2id")  
  154.         label2id, id2label = helper.loadMap("label2id")  
  155.   
  156.         merged = tf.merge_all_summaries()  
  157.         summary_writer_train = tf.train.SummaryWriter('loss_log/train_loss', sess.graph)    
  158.         summary_writer_val = tf.train.SummaryWriter('loss_log/val_loss', sess.graph)       
  159.           
  160.         num_iterations = int(math.ceil(1.0 * len(X_train) / self.batch_size))  
  161.   
  162.         cnt = 0  
  163.         for epoch in range(self.num_epochs):  
  164.             # shuffle train in each epoch  
  165.             sh_index = np.arange(len(X_train))  
  166.             np.random.shuffle(sh_index)  
  167.             X_train = X_train[sh_index]  
  168.             y_train = y_train[sh_index]  
  169.             print "current epoch: %d" % (epoch)  
  170.             for iteration in range(num_iterations):  
  171.                 # train  
  172.                 X_train_batch, y_train_batch = helper.nextBatch(X_train, y_train, start_index=iteration * self.batch_size, batch_size=self.batch_size)  
  173.                 y_train_weight_batch = 1 + np.array((y_train_batch == label2id['B']) | (y_train_batch == label2id['E']), float)  
  174.                 transition_batch = helper.getTransition(y_train_batch)  
  175.                   
  176.                 _, loss_train, max_scores, max_scores_pre, length, train_summary =\  
  177.                     sess.run([  
  178.                         self.optimizer,   
  179.                         self.loss,   
  180.                         self.max_scores,   
  181.                         self.max_scores_pre,   
  182.                         self.length,  
  183.                         self.train_summary  
  184.                     ],   
  185.                     feed_dict={  
  186.                         self.targets_transition:transition_batch,   
  187.                         self.inputs:X_train_batch,   
  188.                         self.targets:y_train_batch,   
  189.                         self.targets_weight:y_train_weight_batch  
  190.                     })  
  191.   
  192.                 predicts_train = self.viterbi(max_scores, max_scores_pre, length, predict_size=self.batch_size)  
  193.                 if iteration % 10 == 0:  
  194.                     cnt += 1  
  195.                     precision_train, recall_train, f1_train = self.evaluate(X_train_batch, y_train_batch, predicts_train, id2char, id2label)  
  196.                     summary_writer_train.add_summary(train_summary, cnt)  
  197.                     print "iteration: %5d, train loss: %5d, train precision: %.5f, train recall: %.5f, train f1: %.5f" % (iteration, loss_train, precision_train, recall_train, f1_train)    
  198.                       
  199.                 # validation  
  200.                 if iteration % 100 == 0:  
  201.                     X_val_batch, y_val_batch = helper.nextRandomBatch(X_val, y_val, batch_size=self.batch_size)  
  202.                     y_val_weight_batch = 1 + np.array((y_val_batch == label2id['B']) | (y_val_batch == label2id['E']), float)  
  203.                     transition_batch = helper.getTransition(y_val_batch)  
  204.                       
  205.                     loss_val, max_scores, max_scores_pre, length, val_summary =\  
  206.                         sess.run([  
  207.                             self.loss,   
  208.                             self.max_scores,   
  209.                             self.max_scores_pre,   
  210.                             self.length,  
  211.                             self.val_summary  
  212.                         ],   
  213.                         feed_dict={  
  214.                             self.targets_transition:transition_batch,   
  215.                             self.inputs:X_val_batch,   
  216.                             self.targets:y_val_batch,   
  217.                             self.targets_weight:y_val_weight_batch  
  218.                         })  
  219.                       
  220.                     predicts_val = self.viterbi(max_scores, max_scores_pre, length, predict_size=self.batch_size)  
  221.                     precision_val, recall_val, f1_val = self.evaluate(X_val_batch, y_val_batch, predicts_val, id2char, id2label)  
  222.                     summary_writer_val.add_summary(val_summary, cnt)  
  223.                     print "iteration: %5d, valid loss: %5d, valid precision: %.5f, valid recall: %.5f, valid f1: %.5f" % (iteration, loss_val, precision_val, recall_val, f1_val)  
  224.   
  225.                     if f1_val > self.max_f1:  
  226.                         self.max_f1 = f1_val  
  227.                         save_path = saver.save(sess, save_file)  
  228.                         print "saved the best model with f1: %.5f" % (self.max_f1)  
  229.   
  230.     def test(self, sess, X_test, X_test_str, output_path):  
  231.         char2id, id2char = helper.loadMap("char2id")  
  232.         label2id, id2label = helper.loadMap("label2id")  
  233.         num_iterations = int(math.ceil(1.0 * len(X_test) / self.batch_size))  
  234.         print "number of iteration: " + str(num_iterations)  
  235.         with open(output_path, "wb") as outfile:  
  236.             for i in range(num_iterations):  
  237.                 print "iteration: " + str(i + 1)  
  238.                 results = []  
  239.                 X_test_batch = X_test[i * self.batch_size : (i + 1) * self.batch_size]  
  240.                 X_test_str_batch = X_test_str[i * self.batch_size : (i + 1) * self.batch_size]  
  241.                 if i == num_iterations - and len(X_test_batch) < self.batch_size:  
  242.                     X_test_batch = list(X_test_batch)  
  243.                     X_test_str_batch = list(X_test_str_batch)  
  244.                     last_size = len(X_test_batch)  
  245.                     X_test_batch += [[for j in range(self.num_steps)] for i in range(self.batch_size - last_size)]  
  246.                     X_test_str_batch += [['x' for j in range(self.num_steps)] for i in range(self.batch_size - last_size)]  
  247.                     X_test_batch = np.array(X_test_batch)  
  248.                     X_test_str_batch = np.array(X_test_str_batch)  
  249.                     results = self.predictBatch(sess, X_test_batch, X_test_str_batch, id2label)  
  250.                     results = results[:last_size]  
  251.                 else:  
  252.                     X_test_batch = np.array(X_test_batch)  
  253.                     results = self.predictBatch(sess, X_test_batch, X_test_str_batch, id2label)  
  254.                   
  255.                 for i in range(len(results)):  
  256.                     doc = ''.join(X_test_str_batch[i])  
  257.                     outfile.write(doc + "<@>" +" ".join(results[i]).encode("utf-8") + "\n")  
  258.   
  259.     def viterbi(self, max_scores, max_scores_pre, length, predict_size=128):  
  260.         best_paths = []  
  261.         for m in range(predict_size):  
  262.             path = []  
  263.             last_max_node = np.argmax(max_scores[m][length[m]])  
  264.             # last_max_node = 0  
  265.             for t in range(1, length[m] + 1)[::-1]:  
  266.                 last_max_node = max_scores_pre[m][t][last_max_node]  
  267.                 path.append(last_max_node)  
  268.             path = path[::-1]  
  269.             best_paths.append(path)  
  270.         return best_paths  
  271.   
  272.     def predictBatch(self, sess, X, X_str, id2label):  
  273.         results = []  
  274.         length, max_scores, max_scores_pre = sess.run([self.length, self.max_scores, self.max_scores_pre], feed_dict={
    self.inputs:X})  
  275.         predicts = self.viterbi(max_scores, max_scores_pre, length, self.batch_size)  
  276.         for i in range(len(predicts)):  
  277.             x = ''.join(X_str[i]).decode("utf-8")  
  278.             y_pred = ''.join([id2label[val] for val in predicts[i] if val != and val != 0])  
  279.             entitys = helper.extractEntity(x, y_pred)  
  280.             results.append(entitys)  
  281.         return results  
  282.   
  283.     def evaluate(self, X, y_true, y_pred, id2char, id2label):  
  284.         precision = -1.0  
  285.         recall = -1.0  
  286.         f1 = -1.0  
  287.         hit_num = 0  
  288.         pred_num = 0  
  289.         true_num = 0  
  290.         for i in range(len(y_true)):  
  291.             x = ''.join([str(id2char[val].encode("utf-8")) for val in X[i]])  
  292.             y = ''.join([str(id2label[val].encode("utf-8")) for val in y_true[i]])  
  293.             y_hat = ''.join([id2label[val] for val in y_pred[i]  if val != 5])  
  294.             true_labels = helper.extractEntity(x, y)  
  295.             pred_labels = helper.extractEntity(x, y_hat)  
  296.             hit_num += len(set(true_labels) & set(pred_labels))  
  297.             pred_num += len(set(pred_labels))  
  298.             true_num += len(set(true_labels))  
  299.         if pred_num != 0:  
  300.             precision = 1.0 * hit_num / pred_num  
  301.         if true_num != 0:  
  302.             recall = 1.0 * hit_num / true_num  
  303.         if precision > and recall > 0:  
  304.             f1 = 2.0 * (precision * recall) / (precision + recall)  
  305.         return precision, recall, f1    

 

util.py

 

[python]   
 
 
  1. #encoding:utf-8  
  2. import re  
  3. import os  
  4. import csv  
  5. import time  
  6. import pickle  
  7. import numpy as np  
  8. import pandas as pd  
  9.   
  10. def getEmbedding(infile_path="embedding"):  
  11.     char2id, id_char = loadMap("char2id")  
  12.     row_index = 0  
  13.     with open(infile_path, "rb") as infile:  
  14.         for row in infile:  
  15.             row = row.strip()  
  16.             row_index += 1  
  17.             if row_index == 1:  
  18.                 num_chars = int(row.split()[0])  
  19.                 emb_dim = int(row.split()[1])  
  20.                 emb_matrix = np.zeros((len(char2id.keys()), emb_dim))  
  21.                 continue  
  22.             items = row.split()  
  23.             char = items[0]  
  24.             emb_vec = [float(val) for val in items[1:]]  
  25.             if char in char2id:  
  26.                 emb_matrix[char2id[char]] = emb_vec  
  27.     return emb_matrix  
  28.   
  29. def nextBatch(X, y, start_index, batch_size=128):  
  30.     last_index = start_index + batch_size  
  31.     X_batch = list(X[start_index:min(last_index, len(X))])  
  32.     y_batch = list(y[start_index:min(last_index, len(X))])  
  33.     if last_index > len(X):  
  34.         left_size = last_index - (len(X))  
  35.         for i in range(left_size):  
  36.             index = np.random.randint(len(X))  
  37.             X_batch.append(X[index])  
  38.             y_batch.append(y[index])  
  39.     X_batch = np.array(X_batch)  
  40.     y_batch = np.array(y_batch)  
  41.     return X_batch, y_batch  
  42.   
  43. def nextRandomBatch(X, y, batch_size=128):  
  44.     X_batch = []  
  45.     y_batch = []  
  46.     for i in range(batch_size):  
  47.         index = np.random.randint(len(X))  
  48.         X_batch.append(X[index])  
  49.         y_batch.append(y[index])  
  50.     X_batch = np.array(X_batch)  
  51.     y_batch = np.array(y_batch)  
  52.     return X_batch, y_batch  
  53.   
  54. # use "0" to padding the sentence  
  55. def padding(sample, seq_max_len):  
  56.     for i in range(len(sample)):  
  57.         if len(sample[i]) < seq_max_len:  
  58.             sample[i] += [for _ in range(seq_max_len - len(sample[i]))]  
  59.     return sample  
  60.   
  61. def prepare(chars, labels, seq_max_len, is_padding=True):  
  62.     X = []  
  63.     y = []  
  64.     tmp_x = []  
  65.     tmp_y = []  
  66.   
  67.     for record in zip(chars, labels):  
  68.         c = record[0]  
  69.         l = record[1]  
  70.         # empty line  
  71.         if c == -1:  
  72.             if len(tmp_x) <= seq_max_len:  
  73.                 X.append(tmp_x)  
  74.                 y.append(tmp_y)  
  75.             tmp_x = []  
  76.             tmp_y = []  
  77.         else:  
  78.             tmp_x.append(c)  
  79.             tmp_y.append(l)   
  80.     if is_padding:  
  81.         X = np.array(padding(X, seq_max_len))  
  82.     else:  
  83.         X = np.array(X)  
  84.     y = np.array(padding(y, seq_max_len))  
  85.   
  86.     return X, y  
  87.   
  88. def extractEntity(sentence, labels):  
  89.     entitys = []  
  90.     re_entity = re.compile(r'BM*E')  
  91.     m = re_entity.search(labels)  
  92.     while m:  
  93.         entity_labels = m.group()  
  94.         start_index = labels.find(entity_labels)  
  95.         entity = sentence[start_index:start_index + len(entity_labels)]  
  96.         labels = list(labels)  
  97.         # replace the "BM*E" with "OO*O"  
  98.         labels[start_index: start_index + len(entity_labels)] = ['O' for i in range(len(entity_labels))]   
  99.         entitys.append(entity)  
  100.         labels = ''.join(labels)  
  101.         m = re_entity.search(labels)  
  102.     return entitys  
  103.   
  104. def loadMap(token2id_filepath):  
  105.     if not os.path.isfile(token2id_filepath):  
  106.         print "file not exist, building map"  
  107.         buildMap()  
  108.   
  109.     token2id = {}  
  110.     id2token = {}  
  111.     with open(token2id_filepath) as infile:  
  112.         for row in infile:  
  113.             row = row.rstrip().decode("utf-8")  
  114.             token = row.split('\t')[0]  
  115.             token_id = int(row.split('\t')[1])  
  116.             token2id[token] = token_id  
  117.             id2token[token_id] = token  
  118.     return token2id, id2token  
  119.   
  120. def saveMap(id2char, id2label):  
  121.     with open("char2id", "wb") as outfile:  
  122.         for idx in id2char:  
  123.             outfile.write(id2char[idx] + "\t" + str(idx)  + "\r\n")  
  124.     with open("label2id", "wb") as outfile:  
  125.         for idx in id2label:  
  126.             outfile.write(id2label[idx] + "\t" + str(idx) + "\r\n")  
  127.     print "saved map between token and id"  
  128.   
  129. def buildMap(train_path="train.in"):  
  130.     df_train = pd.read_csv(train_path, delimiter='\t', quoting=csv.QUOTE_NONE, skip_blank_lines=False, header=None, names=["char", "label"])  
  131.     chars = list(set(df_train["char"][df_train["char"].notnull()]))  
  132.     labels = list(set(df_train["label"][df_train["label"].notnull()]))  
  133.     char2id = dict(zip(chars, range(1, len(chars) + 1)))  
  134.     label2id = dict(zip(labels, range(1, len(labels) + 1)))  
  135.     id2char = dict(zip(range(1, len(chars) + 1), chars))  
  136.     id2label =  dict(zip(range(1, len(labels) + 1), labels))  
  137.     id2char[0] = "<PAD>"  
  138.     id2label[0] = "<PAD>"  
  139.     char2id["<PAD>"] = 0  
  140.     label2id["<PAD>"] = 0  
  141.     id2char[len(chars) + 1] = "<NEW>"  
  142.     char2id["<NEW>"] = len(chars) + 1  
  143.   
  144.     saveMap(id2char, id2label)  
  145.       
  146.     return char2id, id2char, label2id, id2label  
  147.   
  148. def getTrain(train_path, val_path, train_val_ratio=0.99, use_custom_val=False, seq_max_len=200):  
  149.     char2id, id2char, label2id, id2label = buildMap(train_path)  
  150.     df_train = pd.read_csv(train_path, delimiter='\t', quoting=csv.QUOTE_NONE, skip_blank_lines=False, header=None, names=["char", "label"])  
  151.   
  152.     # map the char and label into id  
  153.     df_train["char_id"] = df_train.char.map(lambda x : -if str(x) == str(np.nan) else char2id[x])  
  154.     df_train["label_id"] = df_train.label.map(lambda x : -if str(x) == str(np.nan) else label2id[x])  
  155.       
  156.     # convert the data in maxtrix  
  157.     X, y = prepare(df_train["char_id"], df_train["label_id"], seq_max_len)  
  158.   
  159.     # shuffle the samples  
  160.     num_samples = len(X)  
  161.     indexs = np.arange(num_samples)  
  162.     np.random.shuffle(indexs)  
  163.     X = X[indexs]  
  164.     y = y[indexs]  
  165.       
  166.     if val_path != None:  
  167.         X_train = X  
  168.         y_train = y   
  169.         X_val, y_val = getTest(val_path, is_validation=True, seq_max_len=seq_max_len)  
  170.     else:  
  171.         # split the data into train and validation set  
  172.         X_train = X[:int(num_samples * train_val_ratio)]  
  173.         y_train = y[:int(num_samples * train_val_ratio)]  
  174.         X_val = X[int(num_samples * train_val_ratio):]  
  175.         y_val = y[int(num_samples * train_val_ratio):]  
  176.   
  177.     print "train size: %d, validation size: %d" %(len(X_train), len(y_val))  
  178.   
  179.     return X_train, y_train, X_val, y_val  
  180.   
  181. def getTest(test_path="test.in", is_validation=False, seq_max_len=200):  
  182.     char2id, id2char = loadMap("char2id")  
  183.     label2id, id2label = loadMap("label2id")  
  184.   
  185.     df_test = pd.read_csv(test_path, delimiter='\t', quoting=csv.QUOTE_NONE, skip_blank_lines=False, header=None, names=["char", "label"])  
  186.       
  187.     def mapFunc(x, char2id):  
  188.         if str(x) == str(np.nan):  
  189.             return -1  
  190.         elif x.decode("utf-8") not in char2id:  
  191.             return char2id["<NEW>"]  
  192.         else:  
  193.             return char2id[x.decode("utf-8")]  
  194.   
  195.     df_test["char_id"] = df_test.char.map(lambda x:mapFunc(x, char2id))  
  196.     df_test["label_id"] = df_test.label.map(lambda x : -if str(x) == str(np.nan) else label2id[x])  
  197.       
  198.     if is_validation:  
  199.         X_test, y_test = prepare(df_test["char_id"], df_test["label_id"], seq_max_len)  
  200.         return X_test, y_test  
  201.     else:  
  202.         df_test["char"] = df_test.char.map(lambda x : -if str(x) == str(np.nan) else x)  
  203.         X_test, _ = prepare(df_test["char_id"], df_test["char_id"], seq_max_len)  
  204.         X_test_str, _ = prepare(df_test["char"], df_test["char_id"], seq_max_len, is_padding=False)  
  205.         print "test size: %d" %(len(X_test))  
  206.         return X_test, X_test_str  
  207.   
  208. def getTransition(y_train_batch):  
  209.     transition_batch = []  
  210.     for m in range(len(y_train_batch)):  
  211.         y = [5] + list(y_train_batch[m]) + [0]  
  212.         for t in range(len(y)):  
  213.             if t + 1 == len(y):  
  214.                 continue  
  215.             i = y[t]  
  216.             j = y[t + 1]  
  217.             if i == 0:  
  218.                 break  
  219.             transition_batch.append(i * 6 + j)  
  220.     transition_batch = np.array(transition_batch)  
  221.     return transition_batch  

train.py

 

 

[python]   
 
 
  1. import time  
  2. import helper  
  3. import argparse  
  4. import numpy as np  
  5. import pandas as pd  
  6. import tensorflow as tf  
  7. from BILSTM_CRF import BILSTM_CRF  
  8.   
  9. # python train.py train.in model -v validation.in -c char_emb -e 10 -g 2  
  10.   
  11. parser = argparse.ArgumentParser()  
  12. parser.add_argument("train_path", help="the path of the train file")  
  13. parser.add_argument("save_path", help="the path of the saved model")  
  14. parser.add_argument("-v","--val_path", help="the path of the validation file", default=None)  
  15. parser.add_argument("-e","--epoch", help="the number of epoch", default=100, type=int)  
  16. parser.add_argument("-c","--char_emb", help="the char embedding file", default=None)  
  17. parser.add_argument("-g","--gpu", help="the id of gpu, the default is 0", default=0, type=int)  
  18.   
  19. args = parser.parse_args()  
  20.   
  21. train_path = args.train_path  
  22. save_path = args.save_path  
  23. val_path = args.val_path  
  24. num_epochs = args.epoch  
  25. emb_path = args.char_emb  
  26. gpu_config = "/cpu:0"  
  27. #gpu_config = "/gpu:"+str(args.gpu)  
  28. num_steps = 200 # it must consist with the test  
  29.   
  30. start_time = time.time()  
  31. print "preparing train and validation data"  
  32. X_train, y_train, X_val, y_val = helper.getTrain(train_path=train_path, val_path=val_path, seq_max_len=num_steps)  
  33. char2id, id2char = helper.loadMap("char2id")  
  34. label2id, id2label = helper.loadMap("label2id")  
  35. num_chars = len(id2char.keys())  
  36. num_classes = len(id2label.keys())  
  37. if emb_path != None:  
  38.     embedding_matrix = helper.getEmbedding(emb_path)  
  39. else:  
  40.     embedding_matrix = None  
  41.   
  42. print "building model"  
  43. config = tf.ConfigProto(allow_soft_placement=True)  
  44. with tf.Session(config=config) as sess:  
  45.     with tf.device(gpu_config):  
  46.         initializer = tf.random_uniform_initializer(-0.1, 0.1)  
  47.         with tf.variable_scope("model", reuse=None, initializer=initializer):  
  48.             model = BILSTM_CRF(num_chars=num_chars, num_classes=num_classes, num_steps=num_steps, num_epochs=num_epochs, embedding_matrix=embedding_matrix, is_training=True)  
  49.   
  50.         print "training model"  
  51.         tf.initialize_all_variables().run()  
  52.         model.train(sess, save_path, X_train, y_train, X_val, y_val)  
  53.   
  54.         print "final best f1 is: %f" % (model.max_f1)  
  55.   
  56.         end_time = time.time()  
  57.         print "time used %f(hour)" % ((end_time - start_time) / 3600)  

test.py

 

 

[python]   
 
 
  1. import time  
  2. import helper  
  3. import argparse  
  4. import numpy as np  
  5. import pandas as pd  
  6. import tensorflow as tf  
  7. from BILSTM_CRF import BILSTM_CRF  
  8.   
  9. # python test.py model test.in test.out -c char_emb -g 2  
  10.   
  11. parser = argparse.ArgumentParser()  
  12. parser.add_argument("model_path", help="the path of model file")  
  13. parser.add_argument("test_path", help="the path of test file")  
  14. parser.add_argument("output_path", help="the path of output file")  
  15. parser.add_argument("-c","--char_emb", help="the char embedding file", default=None)  
  16. parser.add_argument("-g","--gpu", help="the id of gpu, the default is 0", default=0, type=int)  
  17. args = parser.parse_args()  
  18.   
  19. model_path = args.model_path  
  20. test_path = args.test_path  
  21. output_path = args.output_path  
  22. gpu_config = "/cpu:0"  
  23. emb_path = args.char_emb  
  24. num_steps = 200 # it must consist with the train  
  25.   
  26. start_time = time.time()  
  27.   
  28. print "preparing test data"  
  29. X_test, X_test_str = helper.getTest(test_path=test_path, seq_max_len=num_steps)  
  30. char2id, id2char = helper.loadMap("char2id")  
  31. label2id, id2label = helper.loadMap("label2id")  
  32. num_chars = len(id2char.keys())  
  33. num_classes = len(id2label.keys())  
  34. if emb_path != None:  
  35.     embedding_matrix = helper.getEmbedding(emb_path)  
  36. else:  
  37.     embedding_matrix = None  
  38.   
  39. print "building model"  
  40. config = tf.ConfigProto(allow_soft_placement=True)  
  41. with tf.Session(config=config) as sess:  
  42.     with tf.device(gpu_config):  
  43.         initializer = tf.random_uniform_initializer(-0.1, 0.1)  
  44.         with tf.variable_scope("model", reuse=None, initializer=initializer):  
  45.             model = BILSTM_CRF(num_chars=num_chars, num_classes=num_classes, num_steps=num_steps, embedding_matrix=embedding_matrix, is_training=False)  
  46.   
  47.         print "loading model parameter"  
  48.         saver = tf.train.Saver()  
  49.         saver.restore(sess, model_path)  
  50.   
  51.         print "testing"  
  52.         model.test(sess, X_test, X_test_str, output_path)  
  53.   
  54.         end_time = time.time()  
  55.         print "time used %f(hour)" % ((end_time - start_time) / 3600)  

 

相关预处理的数据请参考github: 

你可能感兴趣的文章
读取Ini文件字段
查看>>
asp获取来源Url
查看>>
第一次实验
查看>>
Redis基础操作
查看>>
clob大数据转换为多行数据
查看>>
bootstrap的流式布局
查看>>
如何通过线程池异步调用
查看>>
Squid配置详解
查看>>
070104_微积分:随机变量及其分布(二项分布,均匀分布,正态分布)
查看>>
LeetCode – Refresh – Binary Tree Zigzag Level Order Traversal
查看>>
python操作三大主流数据库(13)python操作redis之新闻项目实战①新闻数据的导入
查看>>
2013夏,iDempiere来了 - v1.0c Installers (Devina LTS Release) 2013-06-27
查看>>
每天一个linux命令(22):find 命令的参数详解
查看>>
然后是几点(15)
查看>>
15.节点属性
查看>>
ISO-8859-1编码
查看>>
PHP 代码评审的 10 个提示
查看>>
你知道吗?Web的26项基本概念和技术
查看>>
方案优化:网站实现扫描二维码关注微信公众号,自动登陆网站并获取其信息...
查看>>
Leetcode | Balanced Binary Tree
查看>>