拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Gensim Word2Vec 模型实战指南:从预训练模型到自定义训练、评估与可视化

人工智能NLP机器学习深度学习【免费下载链接】gensimTopic Modelling for Humans项目地址https://gitcode.com/gh_mirrors/ge/gensim点击查看免费下载本篇技术指南以 Gensim 官方示例 run_word2vec.py 及其渲染文档 run_word2vec.rst 为骨架系统讲解 Gensim 中Word2Vec模型的完整使用链路先用预训练模型体验向量代数与相似度查询再从零训练自己的词向量掌握模型保存/加载、核心训练参数、内存占用估算、标准评测集评估、在线续训、训练损失计算与 t-SNE 可视化。读完本文你将能独立完成一个可复用的 Word2Vec 训练、评估与部署流程。从 Bag-of-words 到 Word2Vec为什么需要词向量在进入具体代码之前先回顾一下 Word2Vec 要解决的问题。经典的bag-of-words词袋模型把每篇文档转换成一个定长整数向量每个元素统计某个词在文档中出现的次数。例如给定两句话John likes to watch movies. Mary likes movies too.John also likes to watch football games. Mary hates football.按词表[John, likes, to, watch, movies, Mary, too, also, football, games, hates]的顺序会得到如下向量[1, 2, 1, 1, 2, 1, 1, 0, 0, 0, 0][1, 1, 1, 1, 0, 1, 0, 1, 2, 1, 1]这种模型简单有效但有两个明显缺陷丢失词序信息John likes Mary和Mary likes John会得到完全相同的向量。n-gram 词袋模型虽然能捕获局部词序却会带来数据稀疏和高维度问题。不学习词义向量之间的距离并不反映词义差异例如strong与powerful的向量距离可能和strong与Paris一样远。Word2Vec正是针对第二个问题提出的它用一个浅层神经网络把词嵌入到低维向量空间使得语义相近的词在向量空间中距离相近如strong与powerful靠近语义无关的词距离较远如strong与Paris。认识 Gensim 的 Word2Vec 模型Gensim 的核心实现位于 gensim/models/word2vec.py 中的Word2Vec类继承自utils.SaveLoad天然支持保存/加载它同时实现了两种经典训练算法由sg参数切换Skip-gramSG把滑动窗口扫过文本产生的 (word1, word2) 词对喂给一个单隐层神经网络合成任务是给定一个输入词预测其附近词的概率分布。词的 one-hot 编码经投影层进入隐层投影层的权重最终就被解释为词嵌入——若隐层有 300 个神经元就能得到 300 维的词向量。Continuous Bag-of-WordsCBOW结构与 Skip-gram 类似区别在于合成训练任务是用多个上下文词向量的平均来预测中心词投影权重同样被解释为词嵌入。从 word2vec.py 的__init__签名 可以看到完整的默认参数Word2Vec( sentencesNone, corpus_fileNone, vector_size100, alpha0.025, window5, min_count5, max_vocab_sizeNone, sample1e-3, seed1, workers3, min_alpha0.0001, sg0, hs0, negative5, ns_exponent0.75, cbow_mean1, hashfxnhash, epochs5, null_word0, trim_ruleNone, sorted_vocab1, batch_wordsMAX_WORDS_IN_BATCH, compute_lossFalse, callbacks(), commentNone, max_final_vocabNone, shrink_windowsTrue, )训练完成后模型主体是model.wvKeyedVectors实例实现见 gensim/models/keyedvectors.py它承载词与向量之间的映射以及全部查询 API。实战演示加载预训练模型玩转向量代数Gensim 提供了gensim.downloader工具实现见 gensim/downloader.py可以直接拉取在 Google News 数据集约 30 亿词、约 300 万个词与短语上预训练的模型。自行训练这种规模的模型需要数小时而下载并加载只需要几分钟。注意该模型约2GB需要良好的网络条件网络不佳时可跳过本节直接阅读训练自己的模型。import logging logging.basicConfig(format%(asctime)s : %(levelname)s : %(message)s, levellogging.INFO) import gensim.downloader as api wv api.load(word2vec-google-news-300)查看词表与获取词向量词表保存在index_to_key中Gensim 4.x 起替代了旧版的index2word遍历前 10 个词for index, word in enumerate(wv.index_to_key): if index 10: break print(fword #{index}/{len(wv.index_to_key)} is {word})输出节选word #0/3000000 is /s word #1/3000000 is in word #2/3000000 is for word #3/3000000 is that word #4/3000000 is is word #5/3000000 is on word #6/3000000 is ## word #7/3000000 is The word #8/3000000 is with word #9/3000000 is said获取已知词的向量非常直接__getitem__实现在 keyedvectors.pyvec_king wv[king]但 Word2Vec无法为词表中不存在的词推断向量访问时会抛出KeyError。这是 Word2Vec 的固有局限——如果你需要处理 OOV词表外词可以考虑 Gensim 的 FastText 模型见 gensim/models/fasttext.pytry: vec_cameroon wv[cameroon] except KeyError: print(The word cameroon does not appear in this model)输出The word cameroon does not appear in this model相似度计算、类比推理与找异类Word2Vec 开箱即用支持多种词相似度任务。similarity(w1, w2)返回两个词的余弦相似度可以看到相似度随语义距离拉大而平滑下降pairs [ (car, minivan), # a minivan is a kind of car (car, bicycle), # still a wheeled vehicle (car, airplane), # ok, no wheels, but still a vehicle (car, cereal), # ... and so on (car, communism), ] for w1, w2 in pairs: print(%r\t%r\t%.2f % (w1, w2, wv.similarity(w1, w2)))输出car minivan 0.69 car bicycle 0.54 car airplane 0.42 car cereal 0.14 car communism 0.06most_similar(positive[...], topnn)支持向量加法式类比例如与 car 和 minivan 最接近的 5 个词print(wv.most_similar(positive[car, minivan], topn5))输出[(SUV, 0.8532192707061768), (vehicle, 0.8175783753395081), (pickup_truck, 0.7763688564300537), (Jeep, 0.7567334175109863), (Ford_Explorer, 0.7565720081329346)]doesnt_match(words)找出列表中不属于同一类的词实现在 keyedvectors.pyprint(wv.doesnt_match([fire, water, land, sea, air, car]))输出car这些 API 背后正是著名的向量线性关系例如vec(king) - vec(man) vec(woman) ≈ vec(queen)、vec(Montreal Canadiens) - vec(Montreal) vec(Toronto) ≈ vec(Toronto Maple Leafs)。这也是 Word2Vec 被广泛用于自动文本打标、推荐系统和机器翻译的原因。训练自己的模型内存友好的语料迭代器要训练自己的模型首先需要准备语料。本教程使用Lee Evaluation Corpus它随 Gensim 测试数据一起分发即 gensim/test/test_data/lee_background.cor。该语料很小、可整体装入内存但为了演示如何处理更大的语料教程实现了一个逐行读取的内存友好迭代器from gensim.test.utils import datapath from gensim import utils class MyCorpus: An iterator that yields sentences (lists of str). def __iter__(self): corpus_path datapath(lee_background.cor) for line in open(corpus_path): # assume theres one document per line, tokens separated by whitespace yield utils.simple_preprocess(line)utils.simple_preprocess来自 gensim/utils.py默认会把文本转为小写、按空白切分并过滤非字母字符。如果需要自定义预处理解码特殊编码、去除数字、抽取命名实体等都可以写进这个迭代器——Word2Vec 对此完全无感知它只要求输入逐个产出句子utf8 词组成的列表。训练模型只需一行import gensim.models sentences MyCorpus() model gensim.models.Word2Vec(sentencessentences)从 word2vec.py 的__init__可以看出传入sentences后构造函数会自动依次执行build_vocab()统计词频、裁剪词表和train()真正训练无需手动调用。训练完成后使用方式与前面的预训练模型完全一致核心入口同样是model.wvwv 即 word vectorsvec_king model.wv[king] for index, word in enumerate(model.wv.index_to_key): if index 10: break print(fword #{index}/{len(model.wv.index_to_key)} is {word})注意教程示例中第二个遍历误用了wv而非model.wv在自己训练的场景下应统一通过model.wv访问词表即上面写法。模型的存储与加载非平凡规模的模型训练耗时较长训练完成后应保存到磁盘避免重复训练。Gensim 提供了标准化的save/load接口实现在 word2vec.pyimport tempfile with tempfile.NamedTemporaryFile(prefixgensim-model-, deleteFalse) as tmp: temporary_filepath tmp.name model.save(temporary_filepath) # # The model is now safely stored in the filepath. # You can copy it to other machines, share it with others, etc. # # To load a saved model: # new_model gensim.models.Word2Vec.load(temporary_filepath)save内部基于 pickle 序列化并支持将模型内部的大 NumPy 矩阵通过 mmap 直接从磁盘文件映射进虚拟内存从而实现多进程间的内存共享显著降低加载大模型时的内存压力word2vec.py 的模块级文档对此有专门说明。此外Gensim 还可以加载原始 C 版 word2vec 工具产出的词向量文件文本与二进制格式均可且 gzip/bz2 压缩文件无需解压即可直接读取model gensim.models.KeyedVectors.load_word2vec_format(/tmp/vectors.txt, binaryFalse) # using gzipped/bz2 input works too, no need to unzip model gensim.models.KeyedVectors.load_word2vec_format(/tmp/vectors.bin.gz, binaryTrue)核心训练参数详解Word2Vec接受多个影响训练速度与质量的参数本节逐个说明并给出仓库源码中的默认值与实现依据。min_count词表裁剪阈值min_count用于裁剪内部词典。十亿级语料中只出现一两次的词多半是拼写错误或噪声既没有足够数据做有意义的训练也值得直接忽略# default value of min_count5 model gensim.models.Word2Vec(sentences, min_count10)在源码中prepare_vocab()阶段会根据min_count或max_final_vocab反推的effective_min_count丢弃低频词word2vec.py。默认值min_count5见 word2vec.py 的__init__。vector_size词向量维度vector_size是 Gensim 将词映射到的 N 维空间的维度旧版参数名为size。更大的维度需要更多训练数据但通常能带来更精确的模型合理的取值区间是几十到几百# The default value of vector_size is 100. model gensim.models.Word2Vec(sentences, vector_size200)vector_size同时决定隐层宽度源码中self.layer1_size vector_sizeword2vec.py这正是隐层有 N 个神经元就得到 N 维嵌入的直接对应。workers并行训练线程数workers控制训练并行度用于加速训练# default value of workers3 (tutorial says 1...) model gensim.models.Word2Vec(sentences, workers4)这里有一个文档演进中的细节教程注释指出默认值存在3 与 1的出入以当前仓库源码为准——workers3word2vec.py。需要强调workers只有在安装了 Cython 时才真正生效。没有 Cython 时受 Python GIL全局解释器锁限制只能用单核训练速度会急剧下降。Gensim 的核心训练循环如train_epoch_sg/train_epoch_cbow见 word2vec.py由 Cython 编译的word2vec_inner.pyx实现gensim/models/word2vec_inner.pyx多线程加速依赖这部分原生代码。更多值得关注的参数除上述三个大参数外__init__签名word2vec.py还暴露了以下常用配置参数默认值含义sg0训练算法1 为 Skip-gram否则为 CBOWhs01 时使用层次 Softmax0 时使用负采样negative5负采样噪声词数量0 表示关闭负采样通常取 5–20window5句子中当前词与预测词的最大距离alpha0.025初始学习率min_alpha0.0001训练过程中学习率线性衰减到的下限sample1e-3高频词随机下采样阈值有效范围约 (0, 1e-5]epochs5遍历语料的迭代轮数旧版名为iterseed1随机数种子如需完全可复现还需workers1max_final_vocabNone自动挑选匹配的min_count以限制词表大小shrink_windowsTrue对每个目标词从[1, window]均匀采样有效窗口贴近原版 word2vec 的近似权重compute_lossFalse是否在训练时计算并记录损失内存占用估算Word2Vec 的参数核心是若干 NumPy 矩阵单精度 float4 字节/元素。每个矩阵的规模为词表大小由min_count控制× 向量维度vector_size。训练期间会同时持有三份这样的矩阵源码中也提到正在努力将其降至两份甚至一份因此内存占用可按如下公式估算若输入含 100,000 个唯一词、vector_size200则模型约需100,000 × 200 × 4 × 3 bytes ≈ 229MB。词表树本身还要占少量额外内存10 万词约几 MB。除非词的字符串异常之长内存占用主要由上述三份矩阵主导。源码中的estimate_memory()word2vec.py 调用提供了精确的内存预估接口训练时日志也会打印相应报告。评估类比推理与词对相似度Word2Vec 训练是无监督任务没有统一的客观评价标准评估应围绕最终应用展开。Gensim 提供了两种内置评测方式类比推理评测Google 测试集Google 发布了约 20,000 条句法与语义测试样例遵循A 对 B 如同 C 对 D的任务形式数据文件随 Gensim 分发于 gensim/test/test_data/questions-words.txt。例如句法类比比较级bad:worse; good:?数据集包含 9 类句法比较如复数名词、反义词等语义类比首都Paris:France; Tokyo:?、家庭成员brother:sister; dad:?等 5 类。Gensim 支持以完全相同格式评测model.wv.evaluate_word_analogies(datapath(questions-words.txt))该方法实现在 keyedvectors.py返回一个元组(accuracy, [section 结果...])每个 section 含section名、correct与incorrect列表。在小语料模型上运行输出会呈现各分类的答对/答错明细且Total accuracy一栏汇总全部结果例如在教程所用小模型上各 section 的correct均为空、全部计入incorrect最终准确率为 0.0——这是语料过小的正常表现。它还接受可选参数restrict_vocab默认 300000用于限定只考虑词表中前 N 个高频词的测试样例从而在受限词表上快速评估。词对相似度评测WS-353 风格Gensim 在 2016 年 12 月版本中加入了更贴近语义相似度任务的评测方式默认使用学术数据集 WS-353也可以基于其格式构建贴合自身业务的数据集。该数据集包含词对 人工相似度打分衡量两个词的关联性/共现性例如coast与shore因常出现在相同语境而非常相似而clothes与closet虽相关但不可互换相似度较低。model.wv.evaluate_word_pairs(datapath(wordsim353.tsv))评测数据文件位于 gensim/test/test_data/wordsim353.tsv。输出示例((0.1014236962315867, 0.44065378924434523), SpearmanrResult(correlation0.07441989763914543, pvalue0.5719973648460552), 83.0028328611898)务必注意在 Google 或 WS-353 测试集上表现好不代表在你的应用场景中就一定好用反之亦然。最稳妥的做法是直接在你预期的任务上评测例如把词向量接入一个分类器流水线做端到端验证。在线训练与恢复训练进阶用户可以先加载已有模型再用更多句子和新词表词继续训练。更完整的示例见 online_w2v_tutorial.ipynbmodel gensim.models.Word2Vec.load(temporary_filepath) more_sentences [ [Advanced, users, can, load, a, model, and, continue, training, it, with, more, sentences], ] model.build_vocab(more_sentences, updateTrue) model.train(more_sentences, total_examplesmodel.corpus_count, epochsmodel.epochs) # cleaning up temporary file import os os.remove(temporary_filepath)关键点解析build_vocab(updateTrue)把新句子的词增量并入现有词表word2vec.pytrain(total_examplesmodel.corpus_count, epochsmodel.epochs)在旧词表 新词表上继续训练total_examples决定学习率衰减的进度可按需调整total_words以模拟不同的学习率衰减曲线无法用KeyedVectors.load_word2vec_format()加载的 C 工具模型恢复训练这类模型只含词向量缺少训练所必需的词表树vocab tree信息因此只能用于查询/相似度计算。计算并读取训练损失参数compute_lossTrue可在训练时累计损失。损失值保存在模型属性running_training_loss中通过get_latest_training_loss()读取实现见 word2vec.py# instantiating and training the Word2Vec model model_with_loss gensim.models.Word2Vec( sentences, min_count1, compute_lossTrue, hs0, sg1, seed42, ) # getting the training loss value training_loss model_with_loss.get_latest_training_loss() print(training_loss)输出示例1369454.25需要说明的是损失值对模型质量没有直接的绝对意义更多是用于监控训练过程是否收敛。基准测试compute_loss 对训练时间的影响为了量化计算训练损失这一开关对训练耗时的影响教程给出了一套可复现的基准测试流程。测试数据包括Lee Background 语料即 Gensim 测试数据中的 lee_background.cor约 25kBText8 语料通过api.load(text8)获取并截取前 1MB、10MB、50MB、100MB 来考察语料规模的影响。import io import os import gensim.models.word2vec import gensim.downloader as api import smart_open def head(path, size): with smart_open.open(path) as fin: return io.StringIO(fin.read(size)) def generate_input_data(): lee_path datapath(lee_background.cor) ls gensim.models.word2vec.LineSentence(lee_path) ls.name 25kB yield ls text8_path api.load(text8).fn labels (1MB, 10MB, 50MB, 100MB) sizes (1024 ** 2, 10 * 1024 ** 2, 50 * 1024 ** 2, 100 * 1024 ** 2) for l, s in zip(labels, sizes): ls gensim.models.word2vec.LineSentence(head(text8_path, s)) ls.name l yield ls input_data list(generate_input_data())LineSentence是 word2vec.py 内置的逐行句子迭代器其他可复用的语料迭代器还包括BrownCorpusword2vec.py和Text8Corpusword2vec.py。随后对sg ∈ {0, 1}、hs ∈ {0, 1}、compute_loss ∈ {True, False}的每种组合重复训练 3 次统计平均耗时与标准差# Temporarily reduce logging verbosity logging.root.level logging.ERROR import time import numpy as np import pandas as pd train_time_values [] seed_val 42 sg_values [0, 1] hs_values [0, 1] fast True if fast: input_data_subset input_data[:3] else: input_data_subset input_data for data in input_data_subset: for sg_val in sg_values: for hs_val in hs_values: for loss_flag in [True, False]: time_taken_list [] for i in range(3): start_time time.time() w2v_model gensim.models.Word2Vec( data, compute_lossloss_flag, sgsg_val, hshs_val, seedseed_val, ) time_taken_list.append(time.time() - start_time) time_taken_list np.array(time_taken_list) time_mean np.mean(time_taken_list) time_std np.std(time_taken_list) model_result { train_data: data.name, compute_loss: loss_flag, sg: sg_val, hs: hs_val, train_time_mean: time_mean, train_time_std: time_std, } print(Word2vec model #%i: %s % (len(train_time_values), model_result)) train_time_values.append(model_result) train_times_table pd.DataFrame(train_time_values) train_times_table train_times_table.sort_values( by[train_data, sg, hs, compute_loss], ascending[False, False, True, False], ) print(train_times_table)在教程运行环境fastTrue取前三个数据集下得到的结果汇总节选单位为秒compute_loss hs sg train_data train_time_mean train_time_std 4 True 0 1 25kB 0.472116 0.015137 5 False 0 1 25kB 0.469522 0.003345 6 True 1 1 25kB 0.950259 0.005153 7 False 1 1 25kB 0.942416 0.009776 0 True 0 0 25kB 0.252174 0.020227 1 False 0 0 25kB 0.258985 0.026276 2 True 1 0 25kB 0.419408 0.002198 3 False 1 0 25kB 0.430876 0.001000 12 True 0 1 1MB 1.506507 0.036966 13 False 0 1 1MB 1.537814 0.010207 14 True 1 1 1MB 3.302257 0.045232 15 False 1 1 1MB 3.492871 0.193276 8 True 0 0 1MB 0.644114 0.009346 9 False 0 0 1MB 0.656217 0.027036 10 True 1 0 1MB 1.315072 0.094572 11 False 1 0 1MB 1.205833 0.005159 20 True 0 1 10MB 20.357308 0.412410 21 False 0 1 10MB 21.380845 1.690947 22 True 1 1 10MB 44.487718 1.131427 23 False 1 1 10MB 44.517535 1.447279 16 True 0 0 10MB 7.446084 0.789432 17 False 0 0 10MB 7.060013 0.213669 18 True 1 0 10MB 14.277136 0.744163 19 False 1 0 10MB 13.758649 0.373940从结果可以看出两个规律基于该教程运行环境的数据仅供趋势参考训练耗时随语料规模近似线性增长hs1层次 Softmax比hs0负采样明显更慢sg1Skip-gram比sg0CBOW更慢而compute_loss开关对训练耗时的影响在统计误差范围内并不显著。可视化词嵌入t-SNE 降维训练好的词嵌入可以通过 t-SNE 降维到二维进行可视化直观观察数据中的语义与句法趋势语义cat、dog、cow等词倾向于彼此靠近句法run/running、cut/cutting等词形变化会聚在一起向量关系vKing - vMan vQueen - vWoman这类线性关系在图上也能被观察到。注意教程可视化所用的模型是在小语料上训练的因此部分关系可能并不清晰。本文顶部插图的完整生成代码与脚本一致可参考 run_word2vec.py 的可视化部分复现。核心代码如下使用IncrementalPCA初降维、t-SNE 终降维并兼容 Plotly 与 Matplotlib 两种绘图路径from sklearn.decomposition import IncrementalPCA # inital reduction from sklearn.manifold import TSNE # final reduction import numpy as np # array handling def reduce_dimensions(model): num_dimensions 2 # final num dimensions (2D, 3D, etc) # extract the words their vectors, as numpy arrays vectors np.asarray(model.wv.vectors) labels np.asarray(model.wv.index_to_key) # fixed-width numpy strings # reduce using t-SNE tsne TSNE(n_componentsnum_dimensions, random_state0) vectors tsne.fit_transform(vectors) x_vals [v[0] for v in vectors] y_vals [v[1] for v in vectors] return x_vals, y_vals, labels x_vals, y_vals, labels reduce_dimensions(model) def plot_with_plotly(x_vals, y_vals, labels, plot_in_notebookTrue): from plotly.offline import init_notebook_mode, iplot, plot import plotly.graph_objs as go trace go.Scatter(xx_vals, yy_vals, modetext, textlabels) data [trace] if plot_in_notebook: init_notebook_mode(connectedTrue) iplot(data, filenameword-embedding-plot) else: plot(data, filenameword-embedding-plot.html) def plot_with_matplotlib(x_vals, y_vals, labels): import matplotlib.pyplot as plt import random random.seed(0) plt.figure(figsize(12, 12)) plt.scatter(x_vals, y_vals) # # Label randomly subsampled 25 data points # indices list(range(len(labels))) selected_indices random.sample(indices, 25) for i in selected_indices: plt.annotate(labels[i], (x_vals[i], y_vals[i])) try: get_ipython() except Exception: plot_function plot_with_matplotlib else: plot_function plot_with_plotly plot_function(x_vals, y_vals, labels)在 Jupyter 环境中会自动选用 Plotly 交互式绘图在普通脚本环境中则回退到 Matplotlib 静态图随机标注 25 个点。小结本文完整覆盖了 Gensim Word2Vec 从概念到落地的全流程从词袋模型的局限出发理解词向量动机通过预训练模型体验相似度与类比推理再从零训练、保存/加载模型深入min_count、vector_size、workers等核心参数及其源码默认值掌握内存估算、双评测体系、在线续训、训练损失读取与 t-SNE 可视化。核心实现可进一步研读 gensim/models/word2vec.py 与 gensim/models/keyedvectors.py完整可运行脚本见 run_word2vec.py 及其 Notebook 版本 run_word2vec.ipynb文中用到的语料与评测数据均可从 gensim/test/test_data 目录获取。赞分享人工智能NLP机器学习深度学习【免费下载链接】gensimTopic Modelling for Humans项目地址https://gitcode.com/gh_mirrors/ge/gensim点击查看免费下载相关推荐FairSeq入门指南从预训练模型评估到自定义模型训练FairSeq入门指南从预训练模型评估到自定义模型训练 预训练模型评估实战 FairSeq提供了多种预训练模型我们可以直接下载并使用这些模型进行文本生成任务人工智能深度学习预训练NLP语音fairseq 快速上手从预训练模型评估到新模型训练的完整实战指南fairseq 快速上手从预训练模型评估到新模型训练的完整实战指南 导读 本文是 fairseqFacebook AI Research 开源的 Pytho人工智能深度学习预训练NLP语音LitGPT 预训练实战指南从零训练、自定义数据续训到 TinyLlama 级模型LitGPT 预训练实战指南从零训练、自定义数据续训到 TinyLlama 级模型 导读 本指南围绕 LitGPT 的 litgpt pretrain 命令展大模型预训练微调模型推理服务上一篇终极HTTP解析器指南从字节流到结构化消息的高效转换下一篇pako实战案例如何在WebSocket中实现高效数据传输创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门