word2vec,glove 向量模型训练实践

各种词向量的特点:
One-hot:维度灾难 and 语义鸿沟
矩阵分解(LSA):利用全局语料特征,但SVD求解计算复杂度大
基于NNLM/RNNLM的词向量:词向量为副产物,存在效率不高等问题
word2vec、fastText:优化效率高,但是基于局部语料
glove:基于全局语料,结合了LSA和word2vec的优点
elmo、GPT、bert:动态特征

word2vec

word2vec
CBOW:根据上下文预测目标词的神经网络 ,输入是上下文,两个输入层(上下文考虑2个单词),经过中间层到达输出层,输入层到中间层的变换由相同的全连接层完成,中间层道输出层变换由另一个全连接层完成
在这里插入图片描述
softmax层+cross entropy error层得到损失

cbow(从上下文的多个单词预测中间的单词)
skip-gram(模型效果更好,从中间的单词预测周围多个单词上下文,在低频词和类推问题性能方面更好的表现,学习速度慢于CBOW)

glove

glove 融合了基于推理和基于技术的方法,将整个语料库的统计数据的信息纳入损失函数,进行mini batch学习。。

基于计数和基于推理:
1.向词汇表添加新词并更新的单词的分布式表示,基于计数的方法需要从头开始计算,基于推理的方法允许参数的增量学习。
2.基于计数的方法得到的单词的分布式表his主要是编码单词的相似性,而word2vec除了单词相似性,还能理解复杂单词之间的模式,

golve与word2vec模型区别

参考:https://www.biaodianfu.com/glove.html
GloVe与word2vec,两个模型都可以根据词汇的“共现co-occurrence”信息,将词汇编码成一个向量(所谓共现,即语料中词汇一块出现的频率)。

两者最直观的区别在于,word2vec是“predictive”的模型,而GloVe是“count-based”的模型。

  • Predictive的模型,如Word2vec,根据context预测中间的词汇,要么根据中间的词汇预测context,分别对应了word2vec的两种训练方式cbow和skip-gram。对于word2vec,采用三层神经网络就能训练,最后一层的输出要用一个Huffuman树进行词的预测。
  • Count-based模型,如GloVe,本质上是对共现矩阵进行降维。首先,构建一个词汇的共现矩阵,每一行是一个word,每一列是context。共现矩阵就是计算每个word在每个context出现的频率。由于context是多种词汇的组合,其维度非常大,我们希望像network embedding一样,在context的维度上降维,学习word的低维表示。这一过程可以视为共现矩阵的重构问题,即reconstruction loss。

相比Word2Vec,GloVe更容易并行化,所以对于较大的训练数据,GloVe更快。

实践

环境

需要的python包:
pkuseg ,多领域中文分词包pkuseg.test(readFile, outputFile, model_name = “default”, user_dict = “default”, postag = False, nthread = 10)
ltp分词,[’ '.join(ltp.seg(line)[0]) for line in lines]
gensim,用gensim训练词向量,一个很好用的Python NLP的包,不光可以用于使用word2vec,还有很多其他的API可以用。它封装了google的C语言版的word2vec
LTP 4.0.x,下载包:http://39.96.43.154/ltp/v2/small.tgz,使用方法详情见官网http://ltp.ai/docs/quickstart.html

gensim训练词向量

word2vec是目前比较通用的训练词向量的工具,使用Gensim模块,可以使词向量的训练变的简单

1.引入的包和常数设置

import os
import gensim
from gensim.models import word2vec,Word2Vec
from gensim.models.callbacks import CallbackAny2Vec
import matplotlib.pyplot as plt
import numpy as np
import time
from numpy import linalg
data_path='data/预训练数据.txt'
zi_model_path = "data/字向量模型.model"
vocab_file_path= 'data/all_vocab.txt'
vec_zi_path = "data/字向量.vector"
 
cum_loss_list = [0]# 累计 loss
loss_list=[] #单loss

2.token类

# 自定义token
class Token(object):
    def __init__(self, vocab_file_path, max_len=512):
        self.vocab_file_path = vocab_file_path
        self.max_len = max_len
        self.word2id, self.id2word = self._load_vovab_file()  # 得到词典
        # 进行参数验证
        if self.max_len > 512:  # 表示超过了bert限定长度
            raise Exception(print('设置序列最大长度超过bert限制长度,建议设置max_len<=510'))

    # 加载词表生成word2id和id2word列表
    def _load_vovab_file(self):
        with open(self.vocab_file_path, 'r', encoding='utf-8') as fp:
            vocab_list = [i.replace('\n', '') for i in fp.readlines()]
            word2id = {}
            id2word = {}
            for index, i in enumerate(vocab_list):
                word2id[i] = index
                id2word[index] = i
        return word2id, id2word

    # 定义数据编码encode并生成pytorch所需的数据格式
    def encode_str(self, txt_list: list):
        # 针对所有的输入数据进行编码
        return_txt_id_list = []
        for txt in txt_list:
            inner_str = txt
            inner_str_list = list(inner_str)
            # 开始构建各种索引
            inner_seq_list = []
            inner_seq_list.append('[CLS]')#句子开始标记
            for char in inner_str_list:
                char_index = self.word2id.get(char, False)
                if char_index == False:  # 表示该字符串不认识
                    inner_seq_list.append('[UNK]')
                else:
                    inner_seq_list.append(char)
            inner_seq_list.append('[SEP]')  # 跟上结尾token
            inner_seq_list.append('[PAD]')  # 跟上PAD 
            return_txt_id_list.append(inner_seq_list)
		return return_txt_id_list 

3.train_zi2vec和main函数


def train_zi2vec(data_path, vec_zi_path):
    token =Token(vocab_file_path)
    with open(data_path, 'r',encoding='utf-8') as f:
        data =f.read().splitlines()
    strs_list = token.encode_str(data)#[[1,345...
    while True:
        if os.path.exists(zi_model_path)==False:
            model = Word2Vec(sentences=strs_list,sg=0,size=100,window=10,min_count=0, workers=4,iter=100,compute_loss=True,callbacks=[callback()])
            print('模型训练完毕')
        else:
            model = gensim.models.Word2Vec.load(zi_model_path)
            model.running_training_loss=0
            model.train(sentences=strs_list, epochs=20,totaL_examples = model.corpus_count, compute_Loss=True,callbacks=[callback()])
            model.wv.save_word2vec_format(vec_zi_path,binary=False)
            model.save(zi_model_path)
            if min(loss_list[-20:-10])-min(loss_list[-10:])<100:
                break
    print('loss_List',len(loss_list))
    draw_loss(loss_list)
	#保存训练好的字向量模型字典
	words_list = list(model.wv.vacab.keys)
	word2idx_dic = {word:index for index,word in enumerate(words_list)}
	w = open('字向量字典.vector','w',encoding='utf-8')
	json.dump(word2idx_dic ,w,ensure_ascii=False)
	#下游任务需要用的embedding和字典将从这个文件加载获取
	model.wv.save_word2vec_format('字向量.vector',binary=False)
    print('模型保存成功')
if '_name__'=='__ main__':
    train_zi2vec(data_path, vec_zi_path)

4.callback函数参考

class callback(CallbackAny2Vec):
	'''Callback to print loss after each epoch.'''

	def __init__(self):
		self.epoch = 0

	def on_epoch_end(self, model):
		cumlative_loss = model.get_latest_training_loss()
		cum_loss_list.append(cumlative_loss )
		print('cumlative_loss after epoch {}: {}'.format(self.epoch, cumlative_loss ))
		loss_list.append(cum_loss_list[-1]-cum_loss_list[-2] if self.epoch != 1 else cum_loss_list[-1])
		print('Loss after epoch {}: {}'.format(self.epoch, loss_list[-1]))
		self.epoch += 1

5.画图函数

def draw_loss(y):
	plt.rcParams['font.sans-serif']=['SimHei']
	x = np.arange(0,len(y))
	plt.xlabel('iters')
	plt.ylabel('loss')
	plt.title('gensim_字向量训练loss曲线')
	plt.plot(x, y,color='red')
	plt.savefig('loss曲线.png',dpi=120)
	plt.show()	

skip_gram,CBOW算法了解可参考语言模型介绍
callback()是一个回调,使用get_latest_training_loss()获得word2vec模型的累计的训练损失。

注意:
1.loss收敛不再训练,收敛依据为,使用while不断循环训练,直到上个10轮迭代loss与这个10轮迭代loss相差不超过N,N可以debug时自由定义
2.如果loss太大,超过2**27,model.get_latest_training_loss()获取的值将不再增加,可以保存模型model.save(’ .model)再重新加载(load,train())来避免。
3.如果数据量大,可以用time包打印下时间评估

python-glove 训练词向量简单实践

GloVe(Global Vectors for Word Representation)是一种“用于获取词的向量表示的无监督学习算法。” 简而言之,GloVe允许我们获取文本语料库,并将该语料库中的每个单词直观地转换为高维空间中的位置。 这意味着相似的词将被放在一起。
官网:https://nlp.stanford.edu/projects/glove/
参考:https://blog.csdn.net/keeppractice/article/details/108473693

#准备数据集
from __future__ import print_function
import argparse
import pprint
import gensim
from glove import Glove
from glove import Corpus
import pkuseg
#分词
pkuseg.test(r'data\不要等到毕业以后.txt', r'G:data\不要等到毕业以后分词.txt', model_name = "default", user_dict = "default", postag = False, nthread = 5)
#1.准备数据集
with open(r'data\不要等到毕业以后分词.txt','r',encoding='utf-8') as f:
    sentense = [line.replace('\n','').split(' ')  for line in f.readlines() if line.strip()!='']
#sentense = [['你','是','谁'],['我','是','中国人']]
corpus_model = Corpus()
corpus_model.fit(sentense, window=10)#10
#corpus_model.save('corpus.model')
print('Dict size: %s' % len(corpus_model.dictionary))
#Dict size: 2485
print('Collocations: %s' % corpus_model.matrix.nnz)
#Collocations: 71160

# 2.训练
glove = Glove(no_components=100, learning_rate=0.05)#no_components 维度,可以与word2vec一起使用。
glove.fit(corpus_model.matrix, epochs=10, no_threads=1, verbose=True)
glove.add_dictionary(corpus_model.dictionary)

#3.glove模型保存与加载
corpus_model.save('corpus.model')
corpus_model = Corpus.load('corpus.model')

# 指定词条词向量 
glove.word_vectors[glove.dictionary['你']]
# 相似词
glove.most_similart('专业', number = 10)

# 全部词向量矩阵
glove.word_vectors

#语料协同矩阵 corpus coocurrence matrix
corpus_model.matrix.todense().tolist()

 

在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值