当前位置:   article > 正文

Bert生成句向量(tensorflow)_max_seq_len

max_seq_len

BERT句向量

Bert包括两个版本,12层的transformers与24层的transformers,官方提供了12层的中文模型,下文也将基于12层的transformers来讲解

每一层的transformers的输出值,理论来说都可以作为句向量,但是到底该取哪一层呢,根据hanxiao大神的实验数据,最佳结果是取倒数第二层,最后一层太过于接近目标,前面几层可能语义还未充分的学习到。

接下来从代码的角度来进行详解。

先看下args.py,介绍几个重要参数。这里主要说一下layer_indexes参数,layer_indexes表示的是使用第几层的输出作为句向量,-2代表的是倒数第二层。max_seq_len表示的是序列的最大长度,因为输入的长度是不固定的,所以我们需要设置一个最大长度才能确保输出的维度是一样的,如果最大长度是20,当输入的序列长度小于20的时候,就会补0,如果大于20则会截取前面的部分 ,通常该值会取语料的长度的平均值+2,加2的原因是因为需要拼接两个占位符[CLS](表示序列的开始)与[SEP](表示序列的结束)。在这里,为了提高句子间的区分度,把list里最长的句子的值作为max_seq_len。

  1. # -*- coding: utf-8 -*-
  2. # @Time : 2021/1/21 14:55
  3. # @Author : hcy
  4. # @File : args.py
  5. #配置文件
  6. import os
  7. root_path = os.path.dirname(__file__)
  8. model_dir = os.path.join(root_path, 'model/bert/chinese_L-12_H-768_A-12/')
  9. bert_config = os.path.join(model_dir, 'bert_config.json')
  10. bert_ckpt = os.path.join(model_dir, 'bert_model.ckpt')
  11. bert_vocab_file = os.path.join(model_dir, 'vocab.txt')
  12. output_dir = os.path.join(root_path, 'output/')
  13. data_dir = os.path.join(root_path, 'data/')
  14. num_train_epochs = 10
  15. batch_size = 128
  16. learning_rate = 0.00005
  17. # gpu使用率
  18. gpu_memory_fraction = 0.8
  19. # 默认取倒数第二层的输出值作为句向量
  20. layer_indexes = [-2]
  21. # # 序列的最大程度,取列表中最长句子的长度作为max_seq_len
  22. # max_seq_len = 128

 定义三个占位符,分别表示的是对应文本的index,mask与segment,其中index表示的是在词典中的index,mask表示的是该位置是否有内容,举个例子,例如序列的最大长度是20,有效的字符只有10个字,加上[CLS]与[SEP]两个占位符,那有8个字符是空的,该8个位置设置为0其他位置设置为1,segment_ids表示的是是否是第一个句子,是第一个句子则设置为1,因为该项目只有一个句子,所以均为1。

  1. input_ids = tf.placeholder(tf.int32, shape=[None, None], name='input_ids')
  2. input_mask = tf.placeholder(tf.int32, shape=[None, None], name='input_masks')
  3. segment_ids = tf.placeholder(tf.int32, shape=[None, None], name='segment_ids')

根据上面定义的三个占位符,定义好输入的张量,实例化一个model对象,该对象就是预训练好的bert模型,然后从check_point文件中初始化权重 

  1. input_tensors = [input_ids, input_mask, segment_ids]
  2. # 初始化BERT
  3. model = modeling.BertModel(
  4. config=bert_config,
  5. is_training=False,
  6. input_ids=input_ids,
  7. input_mask=input_mask,
  8. token_type_ids=segment_ids,
  9. use_one_hot_embeddings=False
  10. )
  11. # 加载BERT模型
  12. tf_vars = tf.trainable_variables()
  13. (assignment, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tf_vars, args.bert_ckpt)
  14. tf.train.init_from_checkpoint(args.bert_ckpt, assignment)
  15. # 获取最后一层和倒数第二层
  16. encoder_last_layer = model.get_sequence_output()
  17. encoder_last2_layer = model.all_encoder_layers[-2]
  18. # 读取数据
  19. token = tokenization.FullTokenizer(vocab_file=args.bert_vocab_file)

接下来将args.index_layeres参数中的层数取出来,last2[:, 0, :]代表的就是句向量。

  1. # 获取最后一层和倒数第二层
  2. encoder_last_layer = model.get_sequence_output()
  3. encoder_last2_layer = model.all_encoder_layers[args.layer_indexes[0]]
  4. with tf.Session() as sess:
  5. sess.run(tf.global_variables_initializer())
  6. last2 = sess.run(encoder_last2_layer, feed_dict=feed_data)
  7. # last2 shape:(max_len, 1, 768)
  8. text_embeddings = last2[:, 0, :]

 完整代码

args.py

  1. # -*- coding: utf-8 -*-
  2. # @Time : 2021/1/21 14:55
  3. # @Author : hcy
  4. # @File : args.py
  5. #配置文件
  6. import os
  7. root_path = os.path.dirname(__file__)
  8. model_dir = os.path.join(root_path, 'model/bert/chinese_L-12_H-768_A-12/')
  9. bert_config = os.path.join(model_dir, 'bert_config.json')
  10. bert_ckpt = os.path.join(model_dir, 'bert_model.ckpt')
  11. bert_vocab_file = os.path.join(model_dir, 'vocab.txt')
  12. output_dir = os.path.join(root_path, 'output/')
  13. data_dir = os.path.join(root_path, 'data/')
  14. num_train_epochs = 10
  15. batch_size = 128
  16. learning_rate = 0.00005
  17. # gpu使用率
  18. gpu_memory_fraction = 0.8
  19. # 默认取倒数第二层的输出值作为句向量
  20. layer_indexes = [-2]
  21. # # 序列的最大程度,取列表中最长句子的长度作为max_seq_len
  22. # max_seq_len = 128

 

extract_features.py

  1. # -*- coding: utf-8 -*-
  2. # @Time : 2021/1/21 15:19
  3. # @Author : hcy
  4. # @File : sentences_features.py
  5. import modeling
  6. import tokenization
  7. import numpy as np
  8. from scipy.spatial.distance import cosine
  9. import tensorflow as tf
  10. import args
  11. bert_config = modeling.BertConfig.from_json_file(args.bert_config)
  12. # graph
  13. input_ids = tf.placeholder(tf.int32, shape=[None, None], name='input_ids')
  14. input_mask = tf.placeholder(tf.int32, shape=[None, None], name='input_masks')
  15. segment_ids = tf.placeholder(tf.int32, shape=[None, None], name='segment_ids')
  16. def get_data(sentences):
  17. """产生句子向量"""
  18. word_mask = [[1] * (args.max_seq_len + 2)]
  19. word_segment_ids = [[0] * (args.max_seq_len + 2)]
  20. return [sentences], word_mask, word_segment_ids
  21. def read_input(sentences):
  22. # sentences是一个list,每一个元素是一个str,代表输入文本
  23. # 现在需要转化成id_list
  24. word_id_list = []
  25. max_len = max([len(single) for single in sentences]) # 最大的句子长度
  26. args.max_seq_len = max_len
  27. for sentence in sentences:
  28. split_tokens = token.tokenize(sentence)
  29. # 在这里截取掉大于seq_len个句子的样本,保留其前seq_len个句子
  30. if len(split_tokens) > args.max_seq_len:
  31. split_tokens = split_tokens[:args.max_seq_len]
  32. else:
  33. while len(split_tokens) < args.max_seq_len:
  34. split_tokens.append('[PAD]')
  35. #句向量
  36. tokens = []
  37. tokens.append("[CLS]")
  38. for i_token in split_tokens:
  39. tokens.append(i_token)
  40. tokens.append("[SEP]")
  41. # 加个CLS头,加个SEP尾
  42. word_ids = token.convert_tokens_to_ids(tokens)
  43. word_id_list.append(word_ids)
  44. return word_id_list
  45. # 初始化BERT
  46. model = modeling.BertModel(
  47. config=bert_config,
  48. is_training=False,
  49. input_ids=input_ids,
  50. input_mask=input_mask,
  51. token_type_ids=segment_ids,
  52. use_one_hot_embeddings=False
  53. )
  54. # 加载BERT模型
  55. tf_vars = tf.trainable_variables()
  56. (assignment, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tf_vars, args.bert_ckpt)
  57. tf.train.init_from_checkpoint(args.bert_ckpt, assignment)
  58. # 获取最后一层和倒数第二层
  59. encoder_last_layer = model.get_sequence_output()
  60. encoder_last2_layer = model.all_encoder_layers[args.layer_indexes[0]]
  61. # 读取数据
  62. token = tokenization.FullTokenizer(vocab_file=args.bert_vocab_file)
  63. def extract_features(sentences):
  64. """ 生成句向量"""
  65. embedding_features = []
  66. input_data = read_input(sentences)
  67. for sample in input_data:
  68. #生成句向量
  69. word_id, mask, segment = get_data(sample)
  70. print(word_id)
  71. feed_data = {input_ids: np.asarray(word_id), input_mask: np.asarray(mask), segment_ids: np.asarray(segment)}
  72. with tf.Session() as sess:
  73. sess.run(tf.global_variables_initializer())
  74. last2 = sess.run(encoder_last2_layer, feed_dict=feed_data)
  75. # print(last2.shape)
  76. # last2 shape:(max_len, 1, 768)
  77. text_embeddings = last2[:, 0, :]
  78. embedding_features.append(text_embeddings)
  79. return embedding_features
  80. def similarity(sentences):
  81. """计算句向量的相似度"""
  82. distances = []
  83. similarity = []
  84. last_feature = None
  85. features = extract_features(sentences)
  86. for feature in features:
  87. if last_feature is None:
  88. last_feature = feature
  89. else:
  90. dis = cosine(feature, last_feature)
  91. last_feature = feature
  92. distances.append(dis)
  93. similarity.append(1-dis)
  94. return np.array(similarity)
  95. if __name__ == '__main__':
  96. sentences = ["今天天气不错,适合出行。",
  97. "今天是晴天,可以出去玩。"]
  98. # sentences = ["打开刘红的个人相情愿","分享名片"]
  99. sims = similarity(sentences)
  100. print(sims)

参考文章: 使用BERT生成句向量

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/413673
推荐阅读
相关标签
  

闽ICP备14008679号