gensim包使用

gensim包使用

1 gensim介绍

gensim是一款强大的自然语言处理工具,里面包括N多常见模型:

  • 基本的语料处理工具
  • LSI
  • LDA
  • HDP
  • DTM
  • DIM
  • TF-IDF
  • word2vec、paragraph2vec

2 Word2Vector使用

训练思路:

  1. 将语料库预处理:一行一个文档或句子,将文档或句子分词(以空格分割,英文可以不用分词,英文单词之间已经由空格分割,中文预料需要使用分词工具进行分词。
  2. 将原始的训练语料转化成一个sentence的迭代器,每一次迭代返回的sentence是一个word(utf8格式)的列表。可以使用Gensim中word2vec.py中的LineSentence()方法实现;
  3. 将上面处理的结果输入Gensim内建的word2vec对象进行训练即可:,即sentence参数

1 训练模型

最简单的训练方式(还有第二种训练方式,这里不再讲解,课参考链接1):

sentence直接传参:

from gensim.models import Word2Vec
#控制并行训练的cpu数量
import multiprocessing
sentences = [['first', 'sentence'],
             ['second', 'sentence','is']]
# 模型训练
model = Word2Vec(sentences, size=100, window=10, min_count=1,workers=multiprocessing.cpu_count(), sg=1, iter=10, negative=20)

LineSentence来构建语料

from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
import multiprocessing

sentences = LineSentence('data/test.txt')
for sentence in sentences:
    print(sentence)
    
model=Word2Vec(sentences,size=100, alpha=0.025, window=5, min_count=1,workers=multiprocessing.cpu_count())
    # workers=4,default = 1 worker = no parallelization 只有在机器已安装 Cython 情况下才会起到作用。如没有 Cython,则只能单核运行。

test.txt文件格式为:

风卷 江湖 雨暗村,四山 声作 海涛 翻。
溪柴 火软 蛮毡 暖,我与 狸奴不 出门。
僵卧 孤村 不自哀,尚思 为国 戍轮台。
夜阑 卧听风 吹雨,铁马 冰河 入梦来。

备注:使用LineSentence,则是加载文件,文件格式是一行一个句子,一行为一个迭代对象,每行的文字必须用空格隔开。

Text8Corpus 来构建语料


  • sentences:可以是一个list(list中套list),对于大语料集,建议使用BrownCorpus,Text8Corpus或lineSentence构建.
  • size:是指特征向量的维度,默认为100,神经网络 NN 层单元数,它也对应了训练算法的自由程度。
  • alpha: 是初始的学习速率,在训练过程中会线性地递减到min_alpha。
  • window:窗口大小,表示当前词与预测词在一个句子中的最大距离是多少。
  • min_count:频数阈值,大于等于1的保留
  • workers:用于控制训练的并行数。
  • sg: 用于设置训练算法,默认为0,对应CBOW算法;sg=1则采用skip-gram算法。
  • negative: 如果>0,则会采用negativesampling,用于设置多少个noise words(一般是5-20)

备注:

一些参数的选择与对比:

1.skip-gram (训练速度慢,对罕见字有效),CBOW(训练速度快)。一般选择Skip-gram模型;

2.训练方法:Hierarchical Softmax(对罕见字有利),Negative Sampling(对常见字和低维向量有利);

3.欠采样频繁词可以提高结果的准确性和速度(1e-3~1e-5)

4.Window大小:Skip-gram通常选择10左右,CBOW通常选择5左右。

外部语料集

如果是对于大量的输入语料集或者需要整合磁盘上多个文件夹下的数据,我们可以以迭代器的方式而不是一次性将全部内容读取到内存中来节省 RAM 空间:

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

    def __iter__(self):
        for fname in os.listdir(self.dirname):
            for line in open(os.path.join(self.dirname, fname)):
                yield line.split()

sentences = MySentences('/some/directory') # a memory-friendly iterator
model = gensim.models.Word2Vec(sentences)

备注:这里没有验证,还需要验证

大数据量的训练方法

由于语料太大,不能一次性加载到内存训练,gensim提供了PathLineSentences(input_dir)这个类,会去指定目录依次读取语料数据文件,采用iterator方式加载训练数据到内存。

model = Word2Vec(PathLineSentences(input_dir),
                     size=256, window=10, min_count=5,
                     workers=multiprocessing.cpu_count(), iter=10)

备注:PathLineSentence(input_dir)它会指定input_dir这个目录,依次读取语料文件,采用Iterator方式加载数据到内存,前提是,各个语料文件要做好预处理即进行分词(注意加入外部词典)、去掉停用词

2 模型使用

# 两个词的相似性距离
model.similarity('first','is')    
# 类比的防护四
model.most_similar(positive=['first', 'second'], negative=['sentence'], topn=1)  
# 找出不匹配的词语
model.doesnt_match("input is lunch he sentence cat".split())      
#词向量加减
model.most_similar(positive=['woman', 'king'], negative=['man'])
#输出[('queen', 0.50882536), ...]

model.wv.similarity('woman', 'man')
0.7129250672362295



model.most_similar(['man'])
[('woman', 0.7129250168800354),
 ('girl', 0.6310214996337891),
 ('creature', 0.6019233465194702),
 ('god', 0.5626420974731445),
 ('boy', 0.5613292455673218),
 ('person', 0.5532713532447815),
 ('beast', 0.5510985851287842),
 ('evil', 0.5497387647628784),
 ('stranger', 0.5446441173553467),
 ('soul', 0.5437164306640625)]

查看词向量内容

#输出词向量
print(model['computer'])#输出词向量

查看词向量表

model.wv.vocab.keys()

model.wv.index2word

3 保存和加载

模型保存

保存模型

使用model.save()方法,以该方式保存的模型可以在读取后进行再训练(追加训练),因为保存了训练的全部信息

# 保存模型
model.save("word2vec.model")

备注: 如果需要继续训练,需要完整的Word2Vec对象状态,由save()存储,而不仅仅是KeyedVectors

加载模型

使用load方式加载模型,可以进行再训练

from gensim.models import Word2Vec

model = Word2Vec.load("word2vec.model")
model.train([["hello", "world"]], total_examples=1, epochs=1)

训练后的词向量可以使用model.wv保存在一个KeyedVectors实例中,如下:

vector = model.wv['computer'] # numpy vector of a word

如果已经完成模型的训练(即不再进行模型的更新,仅仅是查询),则可切换到KeyedVectors实例:

word_vectors = model.wv
del model

词向量文件的加载和保存

词向量保存

使用mdoel.wv.saveKededVectors实例的形式保存词向量文件,以该方式保存的模型丢失了完整的模型状态,无法再训练,保存的对象更小更快。

model.wv.save("model.wv")

使用wv.save_word2vec_format保存词向量文件

model.wv.save_word2vec_format("model.bin", binary=True)
词向量加载

使用KeyedVectors.load加载词向量文件,保存在KeyedVectors实例中(适用于不需要完整的模型状态,不再进行训练)

from gensim.models import KeyedVectors
wv = KeyedVectors.load("model.wv", mmap='r')
vector = wv['computer'] # numpy vector of a word

word2vec C format加载词向量,保存在KeyedVectors实例中
使用KeyedVector.load_word2vec_format()可以加载两种格式的词向量文件:C 文本格式C bin格式(二进制)

from gensim.models import KeyedVectors
wv_from_text = KeyedVectors.load_word2vec_format("model_kv_c", binary=False) # C text format
wv_from_bin = KeyedVectors.load_word2vec_format("model_kv.bin", binary=True) # C bin format

备注: 由于权重文件,二叉树和词汇频率的缺失,无法从C格式加载的向量继续训练。

4 增量训练

# 增量训练
model = gensim.models.Word2Vec.load(temp_path)
more_sentences = [['Advanced', 'users', 'can', 'load', 'a', 'model', 'and', 'continue', 'training', 'it', 'with', 'more', 'sentences']]
model.build_vocab(more_sentences, update=True)
model.train(more_sentences, total_examples=model.corpus_count, epochs=model.iter)

备注:不能对C生成的模型进行再训练

案例1 搜狐新闻

https://blog.csdn.net/lilong117194/article/details/82849054

搜狐新闻语料

1 中文语料库准备

本文采用的是搜狗实验室的搜狗新闻语料库,数据链接 http://www.sogou.com/labs/resource/cs.php

下载下来的文件名为: news_sohusite_xml.full.tar.gz

2 数据预处理

2.1 数据解压缩并取出内容

(1)解压缩

tar -zvxf news_sohusite_xml.full.tar.gz

(2)取出内容

由于这里的搜索的材料中给每个对中存储的是文本内容

所以取出内容,执行如下命令

cat news_tensite_xml.dat | iconv -f gbk -t utf-8 -c | grep "<content>"  > corpus.txt

2.2 使用结巴分词

送给word2vec的文件是要分词的,分词可以采用jieba分词实现,

"""
由原始文本进行分词后保存到新的文件
"""
import jieba
import numpy as np

filePath='corpus_1.txt'
fileSegWordDonePath ='corpusSegDone_1.txt'

# 读取文件内容到列表
fileTrainRead = []
with open(filePath,'r') as fileTrainRaw:
    for line in fileTrainRaw:  # 按行读取文件
        fileTrainRead.append(line)
    

# jieba分词后保存在列表中
fileTrainSeg=[]
for i in range(len(fileTrainRead)):
    fileTrainSeg.append([' '.join(list(jieba.cut(fileTrainRead[i][9:-11],cut_all=False)))])
    if i % 100 == 0:
        print(i)
        

# 保存分词结果到文件中
with open(fileSegWordDonePath,'w',encoding='utf-8') as fW:
    for i in range(len(fileTrainSeg)):
        fW.write(fileTrainSeg[i][0])
        fW.write('
')

备注: 需要注意的是,对于读入文件的每一行,使用结巴分词的时候并不是从0到结尾的全部都进行分词,而是对[9:-11]分词 (如行22中所示: fileTrainRead[i][9:-11] ),这样可以去掉每行(一篇新闻稿)起始的 和结尾的

3 训练

训练会用到一个文件,生成两个文件

"""
gensim word2vec获取词向量
"""
import warnings
import logging
import os.path
import sys

import multiprocessing

import gensim
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence

# 忽略警告
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')

if __name__ == '__main__':

    # 设置日志
	program = os.path.basename(sys.argv[0]) # 读取当前文件的文件名
    logger = logging.getLogger(program)
    logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s',level=logging.INFO)
    logger.info("running %s" % ' '.join(sys.argv))


    # inp为输入语料, outp1为输出模型, outp2为vector格式的模型
    inp = 'corpusSegDone_1.txt'
    out_model = 'corpusSegDone_1.model'
    out_vector = 'corpusSegDone_1.vector'
 
    # 训练skip-gram模型
    model = Word2Vec(LineSentence(inp), size=50, window=5, min_count=5,
                     workers=multiprocessing.cpu_count())
 
    # 保存模型
    model.save(out_model)
    # 保存词向量
    model.wv.save_word2vec_format(out_vector, binary=False)

案例2 维基百科

https://blog.csdn.net/lilong117194/article/details/82849054

百度百科+维基百科

案例3

https://blog.csdn.net/sinat_26917383/article/details/69803018

微信语料训练

原文地址:https://www.cnblogs.com/jimlau/p/13263312.html