一、前言

1、Skip-Thought-Vector论文 https://github.com/ryankiros/skip-thoughts

2、本文假设读者已了解Skip-Gram-Vector和RNN相关基础

3、quick_thought 论文:Lajanugen Logeswaran, Honglak Lee, An efficient framework for learning sentence representations. In ICLR, 2018.

二、实战

1、对数据进行分句(去掉过短的句子)、删除频率高的句子、分词

  1. def fenju(data):
  2. sentence=[]
  3. for i in range(len(data)):
  4. try:
  5. m = re.findall('。',data[i][0])
  6. # print(m)
  7. if data[i][1] is not None and len(m)>0:
  8. if len(m)>1:
  9. content=data[i][0].split('。')
  10. # print(content)
  11. for c in range(len(content)):
  12. if len(content[c])>10:
  13. sentence.append(content[c]+'。')
  14. elif len(data[i][0])>10:
  15. sentence.append(data[i][0])
  16. else:
  17. continue
  18. except:
  19. continue
  20. return sentence
  21.  
  22. def _process_sentence_list(sentence_list, threshold=0.01):
  23. sentence_count = Counter(sentence_list)
  24. total_count = len(sentence_list)
  25. # 计算句子频率
  26. sentence_freqs = {w: c / total_count for w, c in sentence_count.items()}
  27. # 剔除出现频率太高的句子
  28. sentence=[]
  29. for w in range(len(sentence_list)):
  30. if sentence_freqs[sentence_list[w]] < threshold:
  31. sentence.append(sentence_list[w])
  32. else:
  33. continue
  34. return sentence
  35.  
  36. def fenci(alltext, writefile, filename):
  37. if not os.path.exists(writefile):
  38. os.makedirs(writefile)
  39. sentence = [' '.join(jieba.lcut(''.join(text.split()))) for text in alltext]
  40. print(sentence)
  41. with open(os.path.join(writefile, filename), "w") as fw:
  42. fw.write("\n".join(sentence))

2、构建vocab、TFRecord文件(详细看github代码)

3、模型输入定义(3种模式train/eval/encode)

  1. def build_inputs(self):
  2.  
  3. if self.mode == "encode":
  4. encode_ids = tf.placeholder(tf.int64, (None, None), name="encode_ids")
  5. encode_mask = tf.placeholder(tf.int8, (None, None), name="encode_mask")
  6. else:
  7. # Prefetch serialized tf.Example protos.
  8. input_queue = input_ops.prefetch_input_data(
  9. self.reader,
  10. FLAGS.input_file_pattern,
  11. shuffle=FLAGS.shuffle_input_data,
  12. capacity=FLAGS.input_queue_capacity,
  13. num_reader_threads=FLAGS.num_input_reader_threads)
  14. print("input_queue",input_queue)
  15. # Deserialize a batch.
  16. serialized = input_queue.dequeue_many(FLAGS.batch_size)
  17. encode = input_ops.parse_example_batch(serialized)
  18. encode_ids = encode.ids
  19. encode_mask = encode.mask
  20. self.encode_ids = encode_ids
  21. self.encode_mask = encode_mask

由于我们每个batch中句子都进行了padding,为了防止padding对训练的影响,这里需要传递掩码给到RNN网络--每个句子各自的原始长度(encode_mask)。

4、对输入句子进行embedding

  1. def build_word_embeddings(self):
  2. rand_init = self.uniform_initializer
  3. self.word_embeddings = []
  4. self.encode_emb = []
  5. self.init = None
  6. for v in self.config.vocab_configs:
  7. if v.mode == 'fixed':
  8. if self.mode == "train":
  9. word_emb = tf.get_variable(
  10. name=v.name,
  11. shape=[v.size, v.dim],
  12. trainable=False)
  13. embedding_placeholder = tf.placeholder(
  14. tf.float32, [v.size, v.dim])
  15. embedding_init = word_emb.assign(embedding_placeholder)
  16.  
  17. rand = np.random.rand(1, v.dim)
  18. word_vecs = np.load(v.embs_file)
  19. load_vocab_size = word_vecs.shape[0]
  20. assert(load_vocab_size == v.size - 1)
  21. word_init = np.concatenate((rand, word_vecs), axis=0)
  22. self.init = (embedding_init, embedding_placeholder, word_init)
  23.  
  24. else:
  25. word_emb = tf.get_variable(
  26. name=v.name,
  27. shape=[v.size, v.dim])
  28.  
  29. encode_emb = tf.nn.embedding_lookup(word_emb, self.encode_ids)
  30. self.word_emb = word_emb
  31. self.encode_emb.extend([encode_emb, encode_emb])#####
  32.  
  33. if v.mode == 'trained':
  34. for inout in ["", "_out"]:
  35. word_emb = tf.get_variable(
  36. name=v.name + inout,
  37. shape=[v.size, v.dim],
  38. initializer=rand_init)
  39. if self.mode == 'train':
  40. self.word_embeddings.append(word_emb)
  41.  
  42. encode_emb = tf.nn.embedding_lookup(word_emb, self.encode_ids)
  43. self.encode_emb.append(encode_emb)
  44.  
  45. if v.mode == 'expand':
  46. for inout in ["", "_out"]:
  47. encode_emb = tf.placeholder(tf.float32, (
  48. None, None, v.dim), v.name + inout)
  49. self.encode_emb.append(encode_emb)
  50. word_emb_dict = read_vocab_embs(v.vocab_file + inout + ".txt",
  51. v.embs_file + inout + ".npy")
  52. self.word_embeddings.append(word_emb_dict)
  53.  
  54. if v.mode != 'expand' and self.mode == 'encode':
  55. word_emb_dict = read_vocab(v.vocab_file)
  56. self.word_embeddings.extend([word_emb_dict, word_emb_dict])

将句子中的每一个字都转化为vocab size长度的向量。v.mode的3种模式fixed(使用预训练的embedding)/train(训练)/expand(扩展)。 最终输出的形式[encode_emb,encode_emb],用来获取上下句联系。

5、构建encoder

encoder对句子进行encode,得到最终的hidden state,这里可用单层的LSTM网络\双向LSTM\双向GRU。

  1. def _initialize_cell(self, num_units, cell_type="GRU"):
  2. if cell_type == "GRU":
  3. return tf.contrib.rnn.GRUCell(num_units=num_units)
  4. elif cell_type == "LSTM":
  5. return tf.contrib.rnn.LSTMCell(num_units=num_units)
  6. else:
  7. raise ValueError("Invalid cell type")
  8.  
  9. def rnn(self, word_embs, mask, scope, encoder_dim, cell_type="GRU"):
  10. length = tf.to_int32(tf.reduce_sum(mask, 1), name="length")
  11. if self.config.bidir:
  12. if encoder_dim % 2:
  13. raise ValueError(
  14. "encoder_dim must be even when using a bidirectional encoder.")
  15. num_units = encoder_dim // 2
  16. cell_fw = self._initialize_cell(num_units, cell_type=cell_type)
  17. cell_bw = self._initialize_cell(num_units, cell_type=cell_type)
  18. outputs, states = tf.nn.bidirectional_dynamic_rnn(
  19. cell_fw=cell_fw,
  20. cell_bw=cell_bw,
  21. inputs=word_embs,
  22. sequence_length=length,
  23. dtype=tf.float32,
  24. scope=scope)
  25. if cell_type == "LSTM":
  26. states = [states[0][1], states[1][1]]
  27. state = tf.concat(states, 1)
  28. else:
  29. cell = self._initialize_cell(encoder_dim, cell_type=cell_type)
  30. outputs, state = tf.nn.dynamic_rnn(
  31. cell=cell,
  32. inputs=word_embs,
  33. sequence_length=length,
  34. dtype=tf.float32,
  35. scope=scope)
  36. if cell_type == "LSTM":
  37. state = state[1]
  38. return state
  39.  
  40. def build_encoder(self):
  41. """Builds the sentence encoder.
  42.  
  43. Inputs:
  44. self.encode_emb
  45. self.encode_mask
  46.  
  47. Outputs:
  48. self.thought_vectors
  49.  
  50. Raises:
  51. ValueError: if config.bidirectional_encoder is True and config.encoder_dim
  52. is odd.
  53. """
  54. names = ["", "_out"]
  55. self.thought_vectors = []
  56. for i in range(2):
  57. with tf.variable_scope("encoder" + names[i]) as scope:
  58. if self.config.encoder == "gru":
  59. sent_rep = self.rnn(self.encode_emb[i], self.encode_mask, scope, self.config.encoder_dim, cell_type="GRU")
  60. elif self.config.encoder == "lstm":
  61. sent_rep = self.rnn(self.encode_emb[i], self.encode_mask, scope, self.config.encoder_dim, cell_type="LSTM")
  62. elif self.config.encoder == 'bow':
  63. sent_rep = self.bow(self.encode_emb[i], self.encode_mask)
  64. else:
  65. raise ValueError("Invalid encoder")
  66.  
  67. thought_vectors = tf.identity(sent_rep, name="thought_vectors")
  68. self.thought_vectors.append(thought_vectors)

可见分别对[encode_emb,encode_emb]进行了encode,得到[thought_vectors,thought_vectors]

6、构建损失函数

  1. def build_loss(self):
  2. """Builds the loss Tensor.
  3.  
  4. Outputs:
  5. self.total_loss
  6. """
  7. all_sen_embs = self.thought_vectors
  8.  
  9. if FLAGS.dropout:
  10. mask_shp = [1, self.config.encoder_dim]
  11. bin_mask = tf.random_uniform(mask_shp) > FLAGS.dropout_rate
  12. bin_mask = tf.where(bin_mask, tf.ones(mask_shp), tf.zeros(mask_shp))
  13. src = all_sen_embs[0] * bin_mask
  14. dst = all_sen_embs[1] * bin_mask
  15. scores = tf.matmul(src, dst, transpose_b=True)
  16. else:
  17. scores = tf.matmul(all_sen_embs[0], all_sen_embs[1], transpose_b=True)###study pre current post
  18.  
  19. # Ignore source sentence
  20. scores = tf.matrix_set_diag(scores, np.zeros(FLAGS.batch_size))
  21. # Targets
  22. targets_np = np.zeros((FLAGS.batch_size, FLAGS.batch_size))
  23. ctxt_sent_pos = list(range(-FLAGS.context_size, FLAGS.context_size + 1))
  24. ctxt_sent_pos.remove(0)
  25. for ctxt_pos in ctxt_sent_pos:
  26. targets_np += np.eye(FLAGS.batch_size, k=ctxt_pos)
  27. targets_np_sum = np.sum(targets_np, axis=1, keepdims=True)
  28. targets_np = targets_np/targets_np_sum
  29. targets = tf.constant(targets_np, dtype=tf.float32)
  30.  
  31. # Forward and backward scores
  32. f_scores = scores[:-1]
  33. b_scores = scores[1:]
  34.  
  35. losses = tf.nn.softmax_cross_entropy_with_logits(
  36. labels=targets, logits=scores)
  37.  
  38. loss = tf.reduce_mean(losses)
  39.  
  40. tf.summary.scalar("losses/ent_loss", loss)
  41. self.total_loss = loss
  42.  
  43. if self.mode == "eval":
  44. f_max = tf.to_int64(tf.argmax(f_scores, axis=1))
  45. b_max = tf.to_int64(tf.argmax(b_scores, axis=1))
  46.  
  47. targets = range(FLAGS.batch_size - 1)
  48. targets = tf.constant(list(targets), dtype=tf.int64)
  49. fwd_targets = targets + 1
  50.  
  51. names_to_values, names_to_updates = tf.contrib.slim.metrics.aggregate_metric_map({
  52. "Acc/Fwd Acc": tf.contrib.slim.metrics.streaming_accuracy(f_max, fwd_targets),
  53. "Acc/Bwd Acc": tf.contrib.slim.metrics.streaming_accuracy(b_max, targets)
  54. })
  55.  
  56. for name, value in names_to_values.items():
  57. tf.summary.scalar(name, value)
  58.  
  59. self.eval_op = names_to_updates.values()

损失函数图解如下:

用 tf.nn.softmax_cross_entropy_with_logits(labels=targets, logits=scores)进行交叉熵,从targets可以看出quick_thought思想是根据上下文来推出目标句的相似性,个人认为并没有学习到目标句的特征,我用quick_thought训练出来的句子向量进行多类别分类,效果不是很好(quick_thought 评估里的例子有电影情感分类)。

具体论文复现的代码https://github.com/lajanugen/S2V(英文)

修改https://github.com/jinjiajia/Quick_Thought(中文)

基于Quick_Thought Vectors的Sentence2Vec神经网络实现的更多相关文章

  1. 基于MTCNN多任务级联卷积神经网络进行的人脸识别 世纪晟人脸检测

    神经网络和深度学习目前为处理图像识别的许多问题提供了最佳解决方案,而基于MTCNN(多任务级联卷积神经网络)的人脸检测算法也解决了传统算法对环境要求高.人脸要求高.检测耗时高的弊端. 基于MTCNN多 ...

  2. 基于MNIST数据的卷积神经网络CNN

    基于tensorflow使用CNN识别MNIST 参数数量:第一个卷积层5x5x1x32=800个参数,第二个卷积层5x5x32x64=51200个参数,第三个全连接层7x7x64x1024=3211 ...

  3. 深度学习基础-基于Numpy的多层前馈神经网络(FFN)的构建和反向传播训练

    本文是深度学习入门: 基于Python的实现.神经网络与深度学习(NNDL)以及花书的读书笔记.本文将以多分类任务为例,介绍多层的前馈神经网络(Feed Forward Networks,FFN)加上 ...

  4. 优化基于FPGA的深度卷积神经网络的加速器设计

    英文论文链接:http://cadlab.cs.ucla.edu/~cong/slides/fpga2015_chen.pdf 翻译:卜居 转载请注明出处:http://blog.csdn.net/k ...

  5. 深度学习(五)基于tensorflow实现简单卷积神经网络Lenet5

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8954892.html 参考博客:https://blog.csdn.net/u01287127 ...

  6. 基于区域的全卷积神经网络(R-FCN)简介

    在 Faster R-CNN 中,检测器使用了多个全连接层进行预测.如果有 2000 个 ROI,那么成本非常高. feature_maps = process(image)ROIs = region ...

  7. 人脸检测数据源制作与基于caffe构架的ALEXNET神经网络训练

    本篇文章主要记录的是人脸检测数据源制作与ALEXNET网络训练实现检测到人脸(基于caffe). 1.数据获取 数据获取: ① benchmark是一个行业的基准(数据库.论文.源码.结果),例如WI ...

  8. 基于theano的深度卷积神经网络

    使用了两个卷积层.一个全连接层和一个softmax分类器. 在测试数据集上正确率可以达到99.22%. 代码参考了neural-networks-and-deep-learning #coding:u ...

  9. GRNN/PNN:基于GRNN、PNN两神经网络实现并比较鸢尾花种类识别正确率、各个模型运行时间对比—Jason niu

    load iris_data.mat P_train = []; T_train = []; P_test = []; T_test = []; for i = 1:3 temp_input = fe ...

随机推荐

  1. vue-cli3.0 搭建项目

    1.首先我们先在安装好node   node用于npm安装[自行百度] 2.全局安装vue 通过npm命令安装vue.js 在用vue.js在用于构建大型的应用时推荐使用npm安装,npm能很好的和w ...

  2. centos 如何执行.bin 文件??

    默认下载,或者上传到 linux 上的 .bin 文件都是白色的,不能被执行. 想要用 ./ 命令去执行,需要先给这个 bin 文件赋权限 chmod u+x 文件名(全名称) 执行完成这个命令,可以 ...

  3. Java Web学习总结(27)——JavaEE中Web服务器、Web容器、Application服务器区别及联系

    在JavaEE 开发Web中,我们经常会听到Web服务器(Web Server).Web容器(Web Container).应用服务器(Application Server),等容易混淆不好理解名词. ...

  4. 循环时自动打开url

    'systemutil.Run "C:\Program Files (x86)\HP\QuickTest Professional\samples\flight\app\flight4a.e ...

  5. 2015 Multi-University Training Contest 10 hdu 5412 CRB and Queries

    CRB and Queries Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Other ...

  6. MySQL 触发器 -1

    MySQL包含对触发器的支持.触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将调用该对象,即表的操作事件触发表上的触发器的执行. 创建触发器 在MySQL中,创建触发器语法如下 ...

  7. iOS 使用脚本自动化复制target

    有些项目成熟以后,就会有需求自动化配置生成一个全新的项目,不需要再让开发人员手动修改工程文件,将配置化工作直接移交给运维或者配置团队去做 其实按照普通的做法,无非就是在xcode里将目标target ...

  8. 笔试题&amp;面试题:给定n个数,要求比較次数1.5n同一时候找出最大值和最小值

    写出一个算法,对给定的n个数的序列,返回序列中的最大和最小的数. 设计出一个算法,仅仅须要运行1.5n次比較就能找到序列中最大和最小的数吗?是否能再少? 分析:要求比較次数为1.5n,使用一般的逐个遍 ...

  9. Linux体验之旅(一)——制作U启,安装rhel-server-6.3

    U启制作: 双击UltraISO: 点击文件→打开: 选择rhel-server6.3 点击启动→选择写入硬盘映像 最后选择格式化优盘→写入→完毕 注意:启动盘制作完毕后一定记得将rhel-serve ...

  10. centos6配置固定ip地址(选择桥接模式)

    1.配置ifcfg-eth0 vim /etc/sysconfig/network-scripts/ifcfg-eth0 首先把BOOTPROTO="dhcp"改成BOOTPROT ...