词向量嵌入的深入研究

最近做项目想把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

Keras.layers.Embedding(input_dim,output_dim):
Input_dim是字典长度(总词量),output_dim就是嵌入维度。

Embedding层在编码的时候就和就是一个矩阵,矩阵就是一种变换吗,矩阵的值通过结果的反向传播来更新。所以他本身对于每个词的编码是结合了语句和整个数据集的上下文学习经验的。

word2vec

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

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,把短句子补齐到同一长度。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值