1. 程式人生 > 實用技巧 >gensim包使用

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('\n')

備註: 需要注意的是,對於讀入檔案的每一行,使用結巴分詞的時候並不是從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

微信語料訓練