ELMO中文词向量训练及使用的完整流程

笔者最近在学习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))

本文参考了众多博客,在此一并表示感谢。

你可能感兴趣的:(词向量,elmo)