TensorFlow25: 使用深度学习做阅读理解+完形填空

记的在学生时代,英语考试有这么一种类型的题,叫:阅读理解。首先让你读一段洋文材料,然后回答一些基于这个洋文材料提的问题。

我先给你出一道阅读理解

Big Panda learned to code when he was 21. He live in China and have no life, feel like a big loser. But here is one thing Panda want you to remember…it´s never too late! You can do anything if you put your heart on it!

____ is the loser.(下划线处该填什么呢?)

我出的这道填空题,对人来说轻而易举,但是要让机器回答就很难了。机器阅读和理解人类语言是非常有挑战性的。

本帖就使用TensorFlow练习一个阅读理解,看看准确率能到什么程度。

使用的数据集

本帖只使用”非死不可”提供的《Children’s Book Test》数据集。

TensorFlow练习25: 使用深度学习做阅读理解+完形填空

数据预处理
[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import re  
  2. import random  
  3. import ast  
  4. import itertools  
  5. import pickle  
  6. import numpy as np  
  7.    
  8. train_data_file = './CBTest/data/cbtest_NE_train.txt'  
  9. valid_data_file = './CBTest/data/cbtest_NE_valid_2000ex.txt'  
  10.    
  11. def preprocess_data(data_file, out_file):  
  12.     # stories[x][0]  tories[x][1]  tories[x][2]  
  13.     stories = []  
  14.     with open(data_file) as f:  
  15.         story = []  
  16.         for line in f:  
  17.             line = line.strip()  
  18.             if not line:  
  19.                 story = []  
  20.             else:  
  21.                 _, line = line.split(' '1)  
  22.                 if line:  
  23.                     if '\t' in line:  
  24.                         q, a, _, answers = line.split('\t')  
  25.                         # tokenize  
  26.                         q = [s.strip() for s in re.split('(\W+)+', q) if s.strip()]  
  27.                         stories.append((story, q, a))  
  28.                     else:  
  29.                         line = [s.strip() for s in re.split('(\W+)+', line) if s.strip()]  
  30.                         story.append(line)  
  31.    
  32.     samples = []  
  33.     for story in stories:  
  34.         story_tmp = []  
  35.         content = []  
  36.         for c in story[0]:  
  37.             content += c  
  38.         story_tmp.append(content)  
  39.         story_tmp.append(story[1])  
  40.         story_tmp.append(story[2])  
  41.    
  42.         samples.append(story_tmp)  
  43.    
  44.     random.shuffle(samples)  
  45.     print(len(samples))  
  46.    
  47.     with open(out_file, "w") as f:  
  48.         for sample in samples:  
  49.             f.write(str(sample))  
  50.             f.write('\n')  
  51.    
  52. preprocess_data(train_data_file, 'train.data')  
  53. preprocess_data(valid_data_file, 'valid.data')  
  54.    
  55. # 创建词汇表  
  56. def read_data(data_file):  
  57.     stories = []  
  58.     with open(data_file) as f:  
  59.         for line in f:  
  60.             line = ast.literal_eval(line.strip())  
  61.             stories.append(line)  
  62.     return stories  
  63.    
  64.    
  65. stories = read_data('train.data') + read_data('valid.data')  
  66.    
  67. content_length = max([len(s) for s, _, _ in stories])  
  68. question_length = max([len(q) for _, q, _ in stories])  
  69. print(content_length, question_length)  
  70.    
  71. vocab = sorted(set(itertools.chain(*(story + q + [answer] for story, q, answer in stories))))  
  72. vocab_size = len(vocab) + 1  
  73. print(vocab_size)  
  74. word2idx = dict((w, i + 1for i,w in enumerate(vocab))  
  75. pickle.dump((word2idx, content_length, question_length, vocab_size), open('vocab.data'"wb"))  
  76.    
  77. # From keras 补齐  
  78. def pad_sequences(sequences, maxlen=None, dtype='int32',  
  79.                   padding='post', truncating='post', value=0.):  
  80.     lengths = [len(s) for s in sequences]  
  81.    
  82.     nb_samples = len(sequences)  
  83.     if maxlen is None:  
  84.         maxlen = np.max(lengths)  
  85.    
  86.     # take the sample shape from the first non empty sequence  
  87.     # checking for consistency in the main loop below.  
  88.     sample_shape = tuple()  
  89.     for s in sequences:  
  90.         if len(s) > 0:  
  91.             sample_shape = np.asarray(s).shape[1:]  
  92.             break  
  93.    
  94.     x = (np.ones((nb_samples, maxlen) + sample_shape) * value).astype(dtype)  
  95.     for idx, s in enumerate(sequences):  
  96.         if len(s) == 0:  
  97.             continue  # empty list was found  
  98.         if truncating == 'pre':  
  99.             trunc = s[-maxlen:]  
  100.         elif truncating == 'post':  
  101.             trunc = s[:maxlen]  
  102.         else:  
  103.             raise ValueError('Truncating type "%s" not understood' % truncating)  
  104.    
  105.         # check `trunc` has expected shape  
  106.         trunc = np.asarray(trunc, dtype=dtype)  
  107.         if trunc.shape[1:] != sample_shape:  
  108.             raise ValueError('Shape of sample %s of sequence at position %s is different from expected shape %s' %  
  109.                              (trunc.shape[1:], idx, sample_shape))  
  110.    
  111.         if padding == 'post':  
  112.             x[idx, :len(trunc)] = trunc  
  113.         elif padding == 'pre':  
  114.             x[idx, -len(trunc):] = trunc  
  115.         else:  
  116.             raise ValueError('Padding type "%s" not understood' % padding)  
  117.     return x  
  118.    
  119. # 转为向量  
  120. def to_vector(data_file, output_file):  
  121.     word2idx, content_length, question_length, _ = pickle.load(open('vocab.data'"rb"))  
  122.       
  123.     X = []  
  124.     Q = []  
  125.     A = []  
  126.     with open(data_file) as f_i:  
  127.         for line in f_i:  
  128.             line = ast.literal_eval(line.strip())  
  129.             x = [word2idx[w] for w in line[0]]  
  130.             q = [word2idx[w] for w in line[1]]  
  131.             a = [word2idx[line[2]]]  
  132.    
  133.             X.append(x)  
  134.             Q.append(q)  
  135.             A.append(a)  
  136.    
  137.     X = pad_sequences(X, content_length)  
  138.     Q = pad_sequences(Q, question_length)  
  139.    
  140.     with open(output_file, "w") as f_o:  
  141.         for i in range(len(X)):  
  142.             f_o.write(str([X[i].tolist(), Q[i].tolist(), A[i]]))  
  143.             f_o.write('\n')  
  144.    
  145. to_vector('train.data''train.vec')  
  146. to_vector('valid.data''valid.vec')  
  147.    
  148.    
  149. """ 
  150. # to_word 
  151. word2idx, content_length, question_length, _ = pickle.load(open('vocab.data', "rb")) 
  152.   
  153. def get_value(dic,value): 
  154.     for name in dic: 
  155.         if dic[name] == value: 
  156.             return name 
  157.   
  158. with open('train.vec') as f: 
  159.     for line in f: 
  160.         line = ast.literal_eval(line.strip()) 
  161.         for word in line[0]: 
  162.             print(get_value(word2idx, word)) 
  163. """  

生成的文件:vocab.data词汇表、train.vec、valid.vec数据的向量表示。

训练

TensorFlow练习25: 使用深度学习做阅读理解+完形填空https://arxiv.org/pdf/1606.02245v4.pdf
[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import tensorflow as tf  
  2. import pickle  
  3. import numpy as np  
  4. import ast  
  5. from collections import defaultdict  
  6.    
  7. train_data = 'train.vec'  
  8. valid_data = 'valid.vec'  
  9.    
  10. word2idx, content_length, question_length, vocab_size = pickle.load(open('vocab.data'"rb"))  
  11. print(content_length, question_length, vocab_size)  
  12.    
  13. batch_size = 64  
  14.    
  15. train_file = open(train_data)  
  16. def get_next_batch():  
  17.     X = []  
  18.     Q = []  
  19.     A = []  
  20.     for i in range(batch_size):  
  21.         for line in train_file:  
  22.             line = ast.literal_eval(line.strip())  
  23.             X.append(line[0])  
  24.             Q.append(line[1])  
  25.             A.append(line[2][0])  
  26.             break  
  27.    
  28.     if len(X) == batch_size:  
  29.         return X, Q, A  
  30.     else:  
  31.         train_file.seek(0)  
  32.         return get_next_batch()  
  33.    
  34. def get_test_batch():  
  35.     with open(valid_data) as f:  
  36.         X = []  
  37.         Q = []  
  38.         A = []  
  39.         for line in f:  
  40.             line = ast.literal_eval(line.strip())  
  41.             X.append(line[0])  
  42.             Q.append(line[1])  
  43.             A.append(line[2][0])  
  44.         return X, Q, A  
  45.    
  46.    
  47. X = tf.placeholder(tf.int32, [batch_size, content_length])   # 洋文材料  
  48. Q = tf.placeholder(tf.int32, [batch_size, question_length])  # 问题  
  49. A = tf.placeholder(tf.int32, [batch_size])                   # 答案  
  50.    
  51. # drop out  
  52. keep_prob = tf.placeholder(tf.float32)  
  53.    
  54. def glimpse(weights, bias, encodings, inputs):  
  55.     weights = tf.nn.dropout(weights, keep_prob)  
  56.     inputs = tf.nn.dropout(inputs, keep_prob)  
  57.     attention = tf.transpose(tf.matmul(weights, tf.transpose(inputs)) + bias)  
  58.     attention = tf.batch_matmul(encodings, tf.expand_dims(attention, -1))  
  59.     attention = tf.nn.softmax(tf.squeeze(attention, -1))  
  60.     return attention, tf.reduce_sum(tf.expand_dims(attention, -1) * encodings, 1)  
  61.    
  62. def neural_attention(embedding_dim=384, encoding_dim=128):  
  63.     embeddings = tf.Variable(tf.random_normal([vocab_size, embedding_dim], stddev=0.22), dtype=tf.float32)  
  64.     tf.contrib.layers.apply_regularization(tf.contrib.layers.l2_regularizer(1e-4), [embeddings])  
  65.    
  66.     with tf.variable_scope('encode'):  
  67.         with tf.variable_scope('X'):  
  68.             X_lens = tf.reduce_sum(tf.sign(tf.abs(X)), 1)  
  69.             embedded_X = tf.nn.embedding_lookup(embeddings, X)  
  70.             encoded_X = tf.nn.dropout(embedded_X, keep_prob)  
  71.             gru_cell = tf.nn.rnn_cell.GRUCell(encoding_dim)  
  72.             outputs, output_states = tf.nn.bidirectional_dynamic_rnn(gru_cell, gru_cell, encoded_X, sequence_length=X_lens, dtype=tf.float32, swap_memory=True)  
  73.             encoded_X = tf.concat(2, outputs)  
  74.         with tf.variable_scope('Q'):  
  75.             Q_lens = tf.reduce_sum(tf.sign(tf.abs(Q)), 1)  
  76.             embedded_Q = tf.nn.embedding_lookup(embeddings, Q)  
  77.             encoded_Q = tf.nn.dropout(embedded_Q, keep_prob)  
  78.             gru_cell = tf.nn.rnn_cell.GRUCell(encoding_dim)  
  79.             outputs, output_states = tf.nn.bidirectional_dynamic_rnn(gru_cell, gru_cell, encoded_Q, sequence_length=Q_lens, dtype=tf.float32, swap_memory=True)  
  80.             encoded_Q = tf.concat(2, outputs)  
  81.    
  82.     W_q = tf.Variable(tf.random_normal([2*encoding_dim, 4*encoding_dim], stddev=0.22), dtype=tf.float32)  
  83.     b_q = tf.Variable(tf.random_normal([2*encoding_dim, 1], stddev=0.22), dtype=tf.float32)  
  84.     W_d = tf.Variable(tf.random_normal([2*encoding_dim, 6*encoding_dim], stddev=0.22), dtype=tf.float32)  
  85.     b_d = tf.Variable(tf.random_normal([2*encoding_dim, 1], stddev=0.22), dtype=tf.float32)  
  86.     g_q = tf.Variable(tf.random_normal([10*encoding_dim, 2*encoding_dim], stddev=0.22), dtype=tf.float32)  
  87.     g_d = tf.Variable(tf.random_normal([10*encoding_dim, 2*encoding_dim], stddev=0.22), dtype=tf.float32)  
  88.    
  89.     with tf.variable_scope('attend') as scope:  
  90.         infer_gru = tf.nn.rnn_cell.GRUCell(4*encoding_dim)  
  91.         infer_state = infer_gru.zero_state(batch_size, tf.float32)  
  92.         for iter_step in range(8):  
  93.             if iter_step > 0:  
  94.                 scope.reuse_variables()  
  95.    
  96.             _, q_glimpse = glimpse(W_q, b_q, encoded_Q, infer_state)  
  97.             d_attention, d_glimpse = glimpse(W_d, b_d, encoded_X, tf.concat_v2([infer_state, q_glimpse], 1))  
  98.    
  99.             gate_concat = tf.concat_v2([infer_state, q_glimpse, d_glimpse, q_glimpse * d_glimpse], 1)  
  100.    
  101.             r_d = tf.sigmoid(tf.matmul(gate_concat, g_d))  
  102.             r_d = tf.nn.dropout(r_d, keep_prob)  
  103.             r_q = tf.sigmoid(tf.matmul(gate_concat, g_q))  
  104.             r_q = tf.nn.dropout(r_q, keep_prob)  
  105.    
  106.             combined_gated_glimpse = tf.concat_v2([r_q * q_glimpse, r_d * d_glimpse], 1)  
  107.             _, infer_state = infer_gru(combined_gated_glimpse, infer_state)  
  108.    
  109.     return tf.to_float(tf.sign(tf.abs(X))) * d_attention  
  110.    
  111. def train_neural_attention():  
  112.     X_attentions = neural_attention()  
  113.     loss = -tf.reduce_mean(tf.log(tf.reduce_sum(tf.to_float(tf.equal(tf.expand_dims(A, -1), X)) * X_attentions, 1) + tf.constant(0.00001)))  
  114.    
  115.     optimizer = tf.train.AdamOptimizer(learning_rate=0.001)  
  116.     grads_and_vars = optimizer.compute_gradients(loss)  
  117.     capped_grads_and_vars = [(tf.clip_by_norm(g, 5), v) for g,v in grads_and_vars]  
  118.     train_op = optimizer.apply_gradients(capped_grads_and_vars)  
  119.    
  120.     saver = tf.train.Saver()  
  121.     with tf.Session() as sess:  
  122.         sess.run(tf.global_variables_initializer())  
  123.    
  124.         # writer = tf.summary.FileWriter()  
  125.         # 恢复前一次训练  
  126.         ckpt = tf.train.get_checkpoint_state('.')  
  127.         if ckpt != None:  
  128.             print(ckpt.model_checkpoint_path)  
  129.             saver.restore(sess, ckpt.model_checkpoint_path)  
  130.         else:  
  131.             print("没找到模型")  
  132.    
  133.         for step in range(20000):  
  134.             train_x, train_q, train_a = get_next_batch()  
  135.             loss_, _ = sess.run([loss, train_op], feed_dict={X:train_x, Q:train_q, A:train_a, keep_prob:0.7})  
  136.             print(loss_)  
  137.    
  138.             # 保存模型并计算准确率  
  139.             if step % 1000 == 0:  
  140.                 path = saver.save(sess, 'machine_reading.model', global_step=step)  
  141.                 print(path)  
  142.    
  143.                 test_x, test_q, test_a = get_test_batch()  
  144.                 test_x, test_q, test_a = np.array(test_x[:batch_size]), np.array(test_q[:batch_size]), np.array(test_a[:batch_size])  
  145.                 attentions = sess.run(X_attentions, feed_dict={X:test_x, Q:test_q, keep_prob:1.})  
  146.                 correct_count = 0  
  147.                 for x in range(test_x.shape[0]):  
  148.                     probs = defaultdict(int)  
  149.                     for idx, word in enumerate(test_x[x,:]):  
  150.                         probs[word] += attentions[x, idx]  
  151.                     guess = max(probs, key=probs.get)  
  152.                     if guess == test_a[x]:  
  153.                         correct_count += 1  
  154.                 print(correct_count / test_x.shape[0])  
  155.    
  156. train_neural_attention()  

我只想说,这个东西比我水平高!

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值