赞
踩
最近做项目想把bert的词向量提出来用,好好研究了一下词向量的嵌入。传统词向量嵌入主要就是word2vec和keras.layers.Embedding层了,除此之外还打算讲一下bert的词向量应用:
不管是用word2vec、embedding层还是bert,每个词都会被先编码为一个数字,你的数据集/batch会先被转化为一个[batch_size,seq_length]的矩阵,然后再使用词向量嵌入把他做成一个[batch_size,seq_length,z_dim]的三维矩阵,其中seq_length是句长,z_dim就是词向量长度。对于变长的句子,一般是采取padding处理,就是用[UNK]标识符把句子不够长的部分补齐。最后投进神经网络的就是这个[batch_size,seq_length,z_dim]的三维矩阵。
Keras.layers.Embedding(input_dim,output_dim):
Input_dim是字典长度(总词量),output_dim就是嵌入维度。
Embedding层在编码的时候就和就是一个矩阵,矩阵就是一种变换吗,矩阵的值通过结果的反向传播来更新。所以他本身对于每个词的编码是结合了语句和整个数据集的上下文学习经验的。
word2vec本身是训练一个矩阵,这个矩阵和Embedding层的神经网络基本上是一样的,所以我们在用word2vec的时候是先训练word2vec模型,然后把word2vec的矩阵按行提出来放进Embedding层里,当然一般是要把这层冻结掉的,因为word2vec是在进入模型之前就训练好的:
#word2vec的训练: # 设置词语向量维度 num_featrues = char_size # 保证被考虑词语的最低频度 min_word_count = min_count # 设置并行化训练使用CPU计算核心数量 num_workers =4 # 设置词语上下文窗口大小 context = 5 w2v_model = word2vec.Word2Vec(word2vecCut, workers=num_workers, size=num_featrues, min_count=min_word_count, window=context) w2v_model.init_sims(replace=True) #利用训练后的word2vec自定义Embedding的训练矩阵,每行代表一个词(结合独热码和矩阵乘法理解) embedding_matrix = np.zeros((len(chars)+4, char_size)) for word, i in char2id.items(): try: embedding_vector = w2v_model[str(word)] embedding_matrix[i] = embedding_vector except KeyError: continue
然后神经网络embedding层加载权重矩阵并冻结:
embedding = Embedding(len(chars)+4, char_size,weights=[embedding_matrix], trainable=False)
那么word2vec和embedding层哪个好呢?
我个人是倾向word2vec的,因为word2vec的训练是无监督的,特别是对于文本摘要任务,词向量本身应该表示词义,和他的结果应该是没关系的,embedding层作为有监督训练出来的词的权重必然会受到结果的影响,但是在文本摘要任务中词义是不应该受到结果影响的。
bert的提取词向量(tensorflow):
token=tokenization.CharTokenizer(bert_vocab_file) split_tokens = token.tokenize('锄禾日当午') print(split_tokens) word_ids = token.convert_tokens_to_ids(split_tokens) print(word_ids,len(word_ids)) test_ids=[100,101,102,103] ret_words=token.convert_ids_to_tokens(test_ids) print(ret_words) word_mask = [1] * len(word_ids) word_segment_ids = [0] * len(word_ids) # graph input_ids = tf.placeholder(tf.int32, shape=[None, None], name='input_ids') input_mask = tf.placeholder(tf.int32, shape=[None, None], name='input_masks') segment_ids = tf.placeholder(tf.int32, shape=[None, None], name='segment_ids') model=modeling.BertModel( config=bert_config, is_training=False, input_ids=input_ids, input_mask=input_mask, token_type_ids=segment_ids, use_one_hot_embeddings=False, ) # 加载bert模型 tvars=tf.trainable_variables() (assignment, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tvars, init_checkpoint) tf.train.init_from_checkpoint(init_checkpoint, assignment) # 获取最后一层和倒数第二层。 encoder_last_layer = model.get_sequence_output() encoder_last2_layer = model.all_encoder_layers[-2] queryList=['锄禾日当午','汗滴禾下土'] vecList=[] with tf.Session() as sess: sess.run(tf.global_variables_initializer()) token = tokenization.CharTokenizer(vocab_file=bert_vocab_file) for query in queryList: split_tokens = token.tokenize(query) word_ids=token.convert_tokens_to_ids(split_tokens) word_mask=[1] * len(word_ids) word_segment_ids=[0] * len(word_ids) fd = {input_ids: [word_ids], input_mask: [word_mask], segment_ids: [word_segment_ids]} last = sess.run(encoder_last_layer, feed_dict=fd) print(last)
其中token是调用的谷歌开源的bert代码里的tokenization,对句子进行分词和编码,代码里出现的[100,101,102,103]是[CLS][SEP][UNK][MASK]四个标识符(具体顺序我记不太清了,可以看bert模型目录下面的vocab.txt)。token.convert_ids_to_tokens需要自己翻一下tokenization.py改一下源码,很简单的,bert的词与编码(不是词向量)的对应是用dict实现的。
当然你要投不等长的数据集进去你要先mask,把短句子补齐到同一长度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。