在中文大语料库上训练word2vector

目录:

  • 1、词向量的作用
  • 2、词向量的训练方法
  • 3、gensim实现大语料库的word2vec

1、词向量的作用

传统使用one-hot表示一个词,用multi-hot表示一个文档。这样做主要的问题是:
1)维度大,独热向量稀疏。
2)损失语义信息,每个词用一个维度进行编号,词之间的余弦相似度都为0

word embedding的优势:
1)分布式的表示(distributional representation),每一维不一定是0或1可以是任意实数,降低维度节省表示空间。
2)包含语义信息,在分布式表示的向量空间中,语义相近的词的向量会比较相近(例如香蕉、苹果属于水果,它们的向量会比较接近)

2、词向量的训练方法

训练的方法常用的有四种奇异值分解、Word2vector、AutoEncoder和glove,这里不介绍具体算法推到,只是简单的介绍一下它们的思想。

1)奇异值分解
基于SVD分解,对term-document矩阵(每个元素为tf-idf)进行奇异值分解,得到term的向量表示和document的向量表示。tfidf是根据全局信息计算的,所以分解方法主要考虑的是全局统计特征。
2)word2vector
有skip-gram和CBOW两种训练方式,word2vec是一种基于局部信息的训练方法,通过单词的上下文信息得到单词的向量表示,两种方法都是通过超参数设定上下文的范围,skip-gram是通过目标单词预测上下文,给定目标单词极大化上下文单词出现的概率,CBOW是通过上下文预测目标单词,给定上下文极大化目标单词出现的概率。都是取模型中部分的隐藏层参数作为单词的向量表示。
3)AutoEncoder
AutoEncoder是一种常用的降维工具,通过对称的全连接神经网络,用输入作为label进行训练达到尽量不损耗原表达的效果,取中间维度低的隐藏层作为压缩后的向量表示。将one-hot的词表示放进去autoencoder,取中间的隐藏层作为词向量。
4)glove
glove是一种结合整体和局部的方法,glove首先统计一个单词之间的共现矩阵,是否共现是通过局部信息即滑动窗口决定的,在滑动窗口内认为两个单词共现,然后统计单词所有的共现信息,这里就实现了同时考虑局部和整体的信息。然后glove设计函数使得单词的词向量的表示经过函数后满足共现矩阵之间的关系,得到单词的向量表示,具体的设计方法还是比较开脑洞的,可以看一下原论文。

现在一般使用的就是word2vec和glove,这里介绍用gensim实现word2vec

3、gensim实现大语料库的word2vec

3.1 requirements

pip install pyltp==0.1.9.1
# 哈工大做的分句、分词、词性标注的工具,也可以用jieba
pip install gensim
# 包含word2vec模型

如果使用pyltp要下载对应(与1.9版本对应的)的模型文件:
https://pan.baidu.com/share/link?shareid=1988562907&uk=2738088569#list/path=%2F

3.2 训练

读取原始数据,做一些简单的预处理

skip_list = [' ', '\n', '=*', '.......']
# 删除一些没意义的字符,由于版面限制的换行符
for skip_char in skip_list:
    sentences = sentences.replace(skip_char, "")
return sentences

对处理后的句子进行分句操作

from pyltp import SentenceSplitter
tmp_sentences = SentenceSplitter.split(sentences)
sentences_list = list(tmp_sentences)

对分好句的句子进行分词操作

from pyltp import Segmentor
segmentor = Segmentor()
segmentor.load(cws_model_path)
# cws_model_path是下载ltp模型后,cws.model的存放地址
seg_list = []
for i in range(len(sentences_list)):
    words = segmentor.segment(sentences_list[i])
    words_list = list(words)
    seg_list.append(words_list)

#保存到一个文件夹中,如果语料库太大,或者有多个文本文件,可以逐个处理,保存下来
with open(text_save_path + '.txt', 'a+') as save_f:
    json.dump(sep_list, save_f)
    save_f.write('\n')

然后进行训练,如果语料库太大,可能不能把整个语料库读入内存,应该使用on-the-fly的训练方式,首先是要写一个迭代器的类,能逐行读取句子:

class DirofCorpus(object):
    def __init__(self, dirname):
        self.dirname = dirname

    def __iter__(self):
        with open(self.dirname) as f:
            line = f.readline()
            while line:
                single_text = json.loads(line)
                line = f.readline()
                for i in range(len(single_text)):
                    yield single_text[i]

word2vec模型构建

model = Word2Vec(size=words_dim, min_count=min_count, workers=workers)

参数介绍:

  • word_dim:词向量的维度
  • min_count:最少出现次数,少于这个次数的词不纳入考虑
  • workers:使用多少个cpu进行训练
  • window:当前单词和预测单词的最远距离,默认是5

训练模型,第一步是用build_vocab的方法构建训练的词汇库,有两种构建方式,可以读入整个语料(可用迭代器读取),也可以读入一个字典,key是每个词汇,value是出现的频率

all_text = DirofCorpus(text_path)
model.build_vocab(all_text, update=False, keep_raw_vocab=False)

第二步是训练

all_text = DirofCorpus(text_path + text_path_list[i])
model.train(all_text, total_examples=model.corpus_count, epochs=model.epochs)

3.3 完整代码

这是一个可以从pdf中提取文本,进行分领域大语料文本训练的自制小工具
https://github.com/xiayto/word2vec

你可能感兴趣的:(机器学习实战,机器学习,nlp)