笔者最近在学习elmo中文的词向量训练及使用,由于网上相关资料比较缺乏,也比较零碎,没有完整的从中文词向量的训练到使用的介绍,学起来困难较多。经过漫长的尝试,笔者终于将整套流程走通,相信应该是目前最完整的流程。现将相关学习过程记录如下,希望后来者可以少走些弯路。(免责声明:笔者也处于初学阶段,不能保证本文的过程及结果正确,若发现错误,敬请指正)
关于elmo的解读可参看网上众多博客,也可参考本人上篇博客:
https://blog.csdn.net/weixin_44081621/article/details/86649821
elmo中文词向量训练及使用可分为三个阶段:
一、中文elmo模型预训练。
二、下游任务的词向量计算。
三、elmo词向量嵌入到下游任务。
下面将按这三个阶段展开:
一、中文elmo模型预训练
本文elmo词向量的训练主要参考:
https://github.com/searobbersduck/ELMo_Chin
先用data_preprocessing.py处理原始语料库(4篇小说),再用train_elmo.py训练模型。
但该代码有些问题,训练过程中陷入了死循环,笔者一直找不到问题出在哪,后来直接用elmo的training源码(代码地址:https://github.com/allenai/bilm-tf/tree/master/bilm)代替作者修改后的代码发现可以运行。(没有研究作者为什么要进行修改,有兴趣的可以甄别一下)
训练完之后得到一个options.json文件,再用training模块中的dump_weights函数将权重导入文件lm_weights.hdf5。
预训练好elmo模型之后,需要将它用在下游的任务当中,上文的代码中没有这部分内容,以下主要是笔者的尝试。
二、下游任务的词向量计算
计算下游任务文本的词向量需要先准备好上文提到的两个文件options.json和lm_weights.hdf5,得到这两个文件之后,可参照bilm中usage_token.py来计算词向量。
# -*- coding: utf-8 -*-
import tensorflow as tf
import os
from bilm import TokenBatcher, BidirectionalLanguageModel, weight_layers, \
dump_token_embeddings
raw_context = [
'我 和 我的 朋友们 都 很 喜欢 苹果手机 .',
'阿凡达 这部 电影 简直 太 精彩 了 .',
'这个 新产品 一点 都 不好 用 .',
'我 讨厌 这些 广告 .'
]
'''ValueError: Invalid shape initializing char_embed, got [60000, 4], expected (60001, 4)
将options里的"n_characters": 改为60001
'''
tokenized_context = [sentence.split() for sentence in raw_context]
all_tokens = set(['', ''] )
for context_sentence in tokenized_context:
for token in context_sentence:
all_tokens.add(token)
vocab_file = r'D:\python_work\paper_code\elmo\elmo_use\elmo_chin_use_new_whole\try\vocab_small.txt'
with open(vocab_file, 'w', encoding='UTF-8') as fout:
fout.write('\n'.join(all_tokens))
options_file = os.path.join(r'D:\python_work\paper_code\elmo\elmo_use\elmo_chin_use_new_whole\data', 'options.json')
weight_file = os.path.join(r'D:\python_work\paper_code\elmo\elmo_use\elmo_chin_use_new_whole\data', 'lm_weights.hdf5')
# Dump the token embeddings to a file. Run this once for your dataset.
token_embedding_file = r'D:\python_work\paper_code\elmo\elmo_use\elmo_chin_use_new_whole\try\elmo_token_embeddings.hdf5'
dump_token_embeddings(
vocab_file, options_file, weight_file, token_embedding_file
)
tf.reset_default_graph()
# Create a TokenBatcher to map text to token ids.
batcher = TokenBatcher(vocab_file)
# Input placeholders to the biLM.
context_token_ids = tf.placeholder('int32', shape=(None, None))
# Build the biLM graph.
bilm = BidirectionalLanguageModel(
options_file,
weight_file,
use_character_inputs=False,
embedding_weight_file=token_embedding_file
)
# Get ops to compute the LM embeddings.
context_embeddings_op = bilm(context_token_ids)
elmo_context_input = weight_layers('input', context_embeddings_op, l2_coef=0.0)
elmo_context_output = weight_layers(
'output', context_embeddings_op, l2_coef=0.0
)
def elmo():
with tf.Session() as sess:
# It is necessary to initialize variables once before running inference.
sess.run(tf.global_variables_initializer())
# Create batches of data.
context_ids = batcher.batch_sentences(tokenized_context)
# question_ids = batcher.batch_sentences(tokenized_question)
elmo_context_input_= sess.run(
[elmo_context_input['weighted_op']],
feed_dict={context_token_ids: context_ids
}
)
return elmo_context_input_
三、将词向量嵌入到下游模型当中
这一部分主要参考博客:
https://blog.csdn.net/feng98ren/article/details/79374369
但是本人使用的例子和处理方法都很蠢,主要是尝试怎样使用elmo的词向量,各位可在自己的能力基础上尽情发挥。
# -*- coding: utf-8 -*-
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.embeddings import Embedding
from try_usage_token import elmo
from numpy import zeros
docs = [ '我 和 我的 朋友们 都 很 喜欢 苹果手机 .',
'阿凡达 这部 电影 简直 太 精彩 了 .',
'这个 新产品 一点 都 不好 用 .',
'我 讨厌 这些 广告 .'
]
labels = [1,1,0,0]
# integer encode the documents
encoded_docs = [[0, 1, 2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24, 25, 26],
[ 27, 28, 29, 30, 31, 32, 33, 34, 35]]
print('t1')
print(encoded_docs)
max_length = 9
print('t2')
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
print('t3')
# load the whole embedding into memory
embedding_matrix = zeros((36, 16))
for i in range(4):
for j in range(9):
embedding_matrix[9*i+j]= elmo()[0][i][j]
print(embedding_matrix)
print('t4')
# define the model
model = Sequential()
e=Embedding(36, 16, weights=[embedding_matrix], input_length=max_length, trainable=False)
print('t5')
model.add(e)
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
# summarize the model
print('t6')
print(model.summary())
# fit the model
print('t7')
model.fit(padded_docs, labels, epochs=100, verbose=0)
# evaluate the model
print('t8')
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('t9')
print('Accuracy: %f' % (accuracy*100))
本文参考了众多博客,在此一并表示感谢。