提高 DOC2VEC Gensim 效率

Improving DOC2VEC Gensim efficiency

我正在尝试在标记文档上训练 Gensim Doc2Vec 模型。我有大约 4000000 份文件。以下是我的代码:

import pandas as pd
import multiprocessing
from nltk.corpus import stopwords
from nltk.tokenize import RegexpTokenizer
from nltk.stem import WordNetLemmatizer
import logging
from tqdm import tqdm
from gensim.models import Doc2Vec
from gensim.models.doc2vec import TaggedDocument
import os
import re



def text_process(text):
    logging.basicConfig(format="%(levelname)s - %(asctime)s: %(message)s", datefmt='%H:%M:%S', level=logging.INFO)
    stop_words_lst = ['mm', 'machine', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'first', 'second', 'third', 'plurality', 'one', 'more', 'least', 'at', 'example', 'memory', 'exemplary', 'fourth', 'fifth', 'sixth','a', 'A', 'an', 'the', 'system', 'method', 'apparatus', 'computer', 'program', 'product', 'instruction', 'code', 'configure', 'operable', 'couple', 'comprise', 'comprising', 'includes', 'cm', 'processor', 'hardware']
    stop_words = set(stopwords.words('english'))

    temp_corpus =[]
    text = re.sub(r'\d+', '', text)
    for w in stop_words_lst:
        stop_words.add(w)
    tokenizer = RegexpTokenizer(r'\w+')
    word_tokens = tokenizer.tokenize(text)
    lemmatizer= WordNetLemmatizer()
    for w in word_tokens:
        w = lemmatizer.lemmatize(w)
        if w not in stop_words:
            temp_corpus.append(str(w))
    return temp_corpus

chunk_patent = pd.DataFrame()
chunksize = 10 ** 5
cores = multiprocessing.cpu_count()
directory = os.getcwd()
for root,dirs,files in os.walk(directory):
    for file in files:
       if file.startswith("patent_cpc -"):
           print(file)
           #f=open(file, 'r')
           #f.close()
           for chunk_patent_temp in pd.read_csv(file, chunksize=chunksize):
                #chunk_patent.sort_values(by=['cpc'], inplace=True)
                #chunk_patent_temp = chunk_patent_temp[chunk_patent_temp['cpc'] == "G06K7"]
                if chunk_patent.empty:
                    chunk_patent = chunk_patent_temp
                else:
                    chunk_patent = chunk_patent.append(chunk_patent_temp)
train_tagged = chunk_patent.apply(lambda r: TaggedDocument(words=text_process(r['text']), tags=[r.cpc]), axis=1)
print(train_tagged.values)

if os.path.exists("cpcpredict_doc2vec.model"):
    doc2vec_model = Doc2Vec.load("cpcpredict_doc2vec.model")
    doc2vec_model.build_vocab((x for x in tqdm(train_tagged.values)), update=True)
    doc2vec_model.train(train_tagged, total_examples=doc2vec_model.corpus_count, epochs=50)
    doc2vec_model.save("cpcpredict_doc2vec.model")
else:
    doc2vec_model = Doc2Vec(dm=0, vector_size=300, min_count=100, workers=cores-1)
    doc2vec_model.build_vocab((x for x in tqdm(train_tagged.values)))
    doc2vec_model.train(train_tagged, total_examples=doc2vec_model.corpus_count, epochs=50)
    doc2vec_model.save("cpcpredict_doc2vec.model")

我试过修改 Doc2vec 参数,但没有成功。

在相同的数据上,我训练了 Word2vec 模型,与 doc2vec 模型相比,它更加准确。此外,"most_similar" word2vec 模型的结果与 doc2vec 模型有很大不同。

以下是搜索最相似结果的代码:

from gensim.models import Word2Vec
from nltk.corpus import stopwords
from nltk.tokenize import RegexpTokenizer
from nltk.stem import WordNetLemmatizer
import logging
from gensim.models import Doc2Vec
import re

def text_process(text):
    logging.basicConfig(format="%(levelname)s - %(asctime)s: %(message)s", datefmt='%H:%M:%S', level=logging.INFO)
    stop_words_lst = ['mm', 'machine', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'first', 'second', 'third', 'example', 'memory', 'exemplary', 'fourth', 'fifth', 'sixth','a', 'A', 'an', 'the', 'system', 'method', 'apparatus', 'computer', 'program', 'product', 'instruction', 'code', 'configure', 'operable', 'couple', 'comprise', 'comprising', 'includes', 'cm', 'processor', 'hardware']
    stop_words = set(stopwords.words('english'))
    #for index, row in df.iterrows():
    temp_corpus =[]
    text = re.sub(r'\d+', '', text)
    for w in stop_words_lst:
        stop_words.add(w)
    tokenizer = RegexpTokenizer(r'\w+')
    word_tokens = tokenizer.tokenize(text)
    lemmatizer= WordNetLemmatizer()
    for w in word_tokens:
        w = lemmatizer.lemmatize(w)
        if w not in stop_words:
            temp_corpus.append(str(w))
    return temp_corpus

model = Word2Vec.load("cpc.model")
print(model.most_similar(positive=['barcode'], topn=30))

model1 = Doc2Vec.load("cpcpredict_doc2vec.model")

pred_tags = model1.most_similar('barcode',topn=10)
print(pred_tags)

此外,上述输出引用如下:

[('indicium', 0.36468246579170227), ('symbology', 0.31725651025772095), ('G06K17', 0.29797130823135376), ('dataform', 0.29535001516342163), ('rogue', 0.29372256994247437), ('certification', 0.29178398847579956), ('reading', 0.27675414085388184), ('indicia', 0.27346929907798767), ('Contra', 0.2700084149837494), ('redemption', 0.26682156324386597)]

[('searched', 0.4693435728549957), ('automated', 0.4469209909439087), ('production', 0.4364866018295288), ('hardcopy', 0.42193126678466797), ('UWB', 0.4197841286659241), ('technique', 0.4149003326892853), ('authorized', 0.4134449362754822), ('issued', 0.4129987359046936), ('installing', 0.4093806743621826), ('thin', 0.4016669690608978)]

您选择的 Doc2Vec 模式,dm=0(又名普通 "PV-DBOW"),根本不训练词向量。由于不同模型的共享代码路径,词向量仍将被随机初始化,但从未经过训练,因此毫无意义。

所以您的 most_similar() 的结果使用一个词作为查询,基本上是随机的。 (在模型本身上使用 most_similar(),而不是其 .wv 词向量或 .docvecs 文档向量,也应该生成弃用警告。)

如果您需要 Doc2Vec 模型来训练除文档向量之外的词向量,请使用 dm=1 模式 ("PV-DM") 或 dm=0, dbow_words=1 (将可选的交错 skip-gram 单词训练添加到普通 DBOW 训练中)。在这两种情况下,单词的训练都将非常类似于 Word2Vec 模型(分别为 'CBOW' 或 'skip-gram' 模式)——因此您的基于单词的 most_similar() 结果应该很有可比性。

分开:

  • 如果您有足够的数据来训练 300 维向量,并丢弃所有出现次数少于 100 次的单词,那么 50 个训练阶段 可能 超出需要。
  • 那些 most_similar() 结果看起来不像是任何词形还原的结果,正如您的 text_process() 方法所预期的那样,但也许这不是问题,或者完全是其他问题.但是请注意,如果有足够的数据,词形还原可能是一个多余的步骤——当在真实上下文中有大量不同示例的所有单词变体时,同一个单词的所有变体往往会彼此靠近有用地结束。