(二)理解word2vec:实践篇

在《(一)理解word2vec:原理篇》中,我已经介绍了word2vec的相关应用和原理。在这篇博客中,我主要介绍word2vec的实践。

本篇博客的基础实践代码仍然参考刘新建老师的博客,在他文章的基础上,我又扩展了一些功能。

我用的实现word2vec的包是gensim官方github)。gensim是一款开源的第三方Python工具包,用于从原始的非结构化的文本中,无监督地学习到文本隐层的主题向量表达。它支持包括TF-IDF,LSA,LDA,和word2vec在内的多种主题模型算法,支持流式训练,并提供了诸如相似度计算,信息检索等一些常用任务的API接口。

目录

一、gensim word2vec API概述

二、对原始语料分词

三、利用gensim实现word2vec

四、关于实践word2vec的一些问题

4.1 word2vec是word embedding 最好的工具吗?

4.2 word2vec 训练结果的差异主要来自什么因素?

4.2.1 语料影响最大

4.2.2 算法参数的影响

4.3 word2vec 影响速度的因素有哪些?

4.3.1 语言模型:cbow 比skip-gram 更快

4.3.2 迭代次数

4.3.3 线程数

4.3.4 其他参数

4.4 怎样评估word2vec训练的好坏?

4.4.1 词聚类

4.4.2 词cos 相关性

4.4.3 Analogy对比

4.4.4 使用tnse,pca等降维可视化展示

参考文献


一、gensim word2vec API概述

在gensim中,word2vec 相关的API都在包gensim.models.word2vec中。和算法有关的参数都在类gensim.models.word2vec.Word2Vec中。相关主页:word2veckeyedvectors

算法需要注意的参数有:

1) sentences: 我们要分析的语料,可以是一个列表,或者从文件中遍历读出。后面我们会有从文件读出的例子。

2) size: 词向量的维度,默认值是100。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度

3) window:即词向量上下文最大距离,这个参数在我们的算法原理篇中标记为cc,window越大,则和某一词较远的词也会产生上下文关系。默认值为5。在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。对于一般的语料这个值推荐在[5,10]之间。

4) sg: 即我们的word2vec两个模型的选择了。如果是0, 则是CBOW模型,是1则是Skip-Gram模型,默认是0即CBOW模型。

5) hs: 即我们的word2vec两个解法的选择了,如果是0, 则是Negative Sampling,是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax。默认是0即Negative Sampling。

6) negative:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间。这个参数在我们的算法原理篇中标记为neg。

7) cbow_mean: 仅用于CBOW在做投影的时候,为0,则算法中的xwxw为上下文的词向量之和,为1则为上下文的词向量的平均值。在我们的原理篇中,是按照词向量的平均值来描述的。在原理篇中,我们用平均值来表示x_w,默认值也是1,不推荐修改默认值。

8) min_count:需要计算词向量的最小词频。这个值可以去掉一些很生僻的低频词,默认是5。如果是小语料,可以调低这个值。

9) iter: 随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大这个值。

10) alpha: 在随机梯度下降法中迭代的初始步长。算法原理篇中标记为\eta,默认是0.025。

11) min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步长值。随机梯度下降中每轮的迭代步长可以由iter,alpha, min_alpha一起得出。这部分由于不是word2vec算法的核心内容,因此在原理篇我们没有提到。对于大语料,需要对alpha, min_alpha,iter一起调参,来选择合适的三个值。

以上就是gensim word2vec的主要的参数,下面我们用一个实际的例子来学习word2vec。

二、对原始语料分词

 刘新建老师选择《人民的名义》的小说原文作为语料,语料原文在这里。在这里,我也用这个语料。由于这个原始语料就是小说,因此,我们应该先分词。采用jieba。

代码如下:

import jieba
import jieba.analyse

jieba.suggest_freq('沙瑞金', True) # 加入一些词,使得jieba分词准确率更高
jieba.suggest_freq('田国富', True)
jieba.suggest_freq('高育良', True)
jieba.suggest_freq('侯亮平', True)
jieba.suggest_freq('钟小艾', True)
jieba.suggest_freq('陈岩石', True)
jieba.suggest_freq('欧阳菁', True)
jieba.suggest_freq('易学习', True)
jieba.suggest_freq('王大路', True)
jieba.suggest_freq('蔡成功', True)
jieba.suggest_freq('孙连城', True)
jieba.suggest_freq('季昌明', True)
jieba.suggest_freq('丁义珍', True)
jieba.suggest_freq('郑西坡', True)
jieba.suggest_freq('赵东来', True)
jieba.suggest_freq('高小琴', True)
jieba.suggest_freq('赵瑞龙', True)
jieba.suggest_freq('林华华', True)
jieba.suggest_freq('陆亦可', True)
jieba.suggest_freq('刘新建', True)
jieba.suggest_freq('刘庆祝', True)
jieba.suggest_freq('赵德汉', True)


with open('in_the_name_of_people.txt', 'rb') as f:
    
    document = f.read()     
    document_cut = jieba.cut(document)
    result = ' '.join(document_cut)
    result = result.encode('utf-8')
    
    with open('in_the_name_of_people_segment.txt', 'wb') as f2:
        f2.write(result)
f.close()
f2.close()

三、利用gensim实现word2vec

拿到了分词后的文件,在一般的NLP处理中,会需要去停用词。由于word2vec的算法依赖于上下文,而上下文有可能就是停词。因此对于word2vec,我们可以不用去停词。

现在我们可以直接读分词后的文件到内存。这里使用了word2vec提供的LineSentence类来读文件,然后套用word2vec的模型。在实际应用中,可以调参提高词的embedding的效果。

① 训练模型

# import modules & set up logging
import logging
from gensim.models import word2vec

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.LineSentence('in_the_name_of_people_segment.txt') 

model = word2vec.Word2Vec(sentences, hs=1, min_count=10, window=3, size=100)

② 选出最相似的5个词

# 选出最相似的5个词,方法一
for e in model.wv.similar_by_word('沙瑞金', topn =5):
    print (e[0], e[1])
'''
高育良 0.9234411716461182
田国富 0.8858301043510437
亮 0.8368291854858398
李达康 0.822664737701416
指示 0.8102874755859375
'''
    
print ('*'*50)      
 
# 选出最相似的5个词,方法二
for e in model.wv.most_similar(positive=['沙瑞金'], topn=5):
   print(e[0], e[1])
'''
高育良 0.9234411716461182
田国富 0.8858301043510437
亮 0.8368291854858398
李达康 0.822664737701416
指示 0.8102874755859375
'''   

2个方法的结果一样,可以看到能找到几个相关的词,但是也有噪音

③ 选出词汇相对于另一组词汇的对应词

# 选出词汇相对于另一组词汇的对应词
model.wv.most_similar(positive=['李达康', '欧阳菁'], negative=['侯亮平'])
'''
[('一个', 0.8564327359199524),
 ('为', 0.8563842177391052),
 ('老婆', 0.8343011140823364),
 ('中国', 0.8328956961631775),
 ('问题', 0.8306251764297485),
 ('班子', 0.8267861604690552),
 ('发展', 0.8258910179138184),
 ('干部', 0.8231020569801331),
 ('思路', 0.8212059140205383),
 ('重要', 0.8195070028305054)]
'''

第3个是老婆,看来还是能get到欧阳菁是李达康的老婆。但是却找不到侯亮平的老婆?

④ 计算两个词的相似度

# 计算两个词的相似度
print(model.wv.similarity('沙瑞金', '季昌明'))
print(model.wv.similarity('沙瑞金', '田国富'))
'''
0.69518
0.88583
'''

沙瑞金和田国富都是书记,而季昌明是检察长,因此沙瑞金和田国富更相关。

⑤ 计算两个集合的相似度

# 计算两个集合的相似度
list1 = ['李达康', '欧阳菁']
list2 = ['侯亮平', '钟小艾']
print(model.wv.n_similarity(list1, list2))
'''
0.811746
'''

⑥ 选出集合中不同类的词语

# 选出集合中不同类的词语
list3 = ['沙瑞金', '李达康', '季昌明', '刘新建']
print(model.wv.doesnt_match(list3))
'''
刘新建
'''

刘新建明显跟他们3个不是一类的。

⑦ 查看词的向量值

# 查看词的向量值
print(model.wv.__getitem__(['沙瑞金']))  # 输出 一行100列的向量

⑧ 保存并读出训练好的模型

# 保存训练好的模型
model.save('model.bin')
# 读出训练好的模型
new_model =  word2vec.Word2Vec.load('model.bin')

这篇文章里有更多模型保存和读入的例子。

上面实现了一个很简单的例子,在实际应用中,我们可以对word2vec进行调参提高embedding的准确性。有时间,自己会整理一个调参的代码。这里有一个调参的参考。

四、关于实践word2vec的一些问题

4.1 word2vec是word embedding 最好的工具吗?

word2vec并非是效果最好的word embedding 工具。最容易看出的就是word2vec没有考虑语序,这里会有训练效果损失

由于 word2vec训练速度快 ,易用,google出品 等,使得word2vec使用的人多。

训练快是因为word2vec只有输入层和输出层,砍去了神经网络中,隐藏层的耗时计算(所以word2vec并不算是一个深度学习算法)。另外,阅读word2vec的google的源码,会发现里面有一些提速的trick。如 sigmod函数,采用一次计算,以后查表,减去了大量的重复计算。如词典hash存储, 层次softmax等。

易用是因为word2vec公布了word2vec的代码。在tensorflow,gensim,spark mllib包中都有集成,使用方便。

4.2 word2vec 训练结果的差异主要来自什么因素?

4.2.1 语料影响最大

语料的场景,比如微博的语料和新闻语料训练的结果差别很大。因为微博属于个人发帖,比较随意。而新闻比较官方正式,另外新闻句式相对复杂。经过训练对比:微博这种短文,训练的相似词更多是同级别的相关词。比如 深圳 相关的是 广州 。而用新闻语料,训练得到 深圳 相关的词 更多是与 深圳 有关联的词,比如 深圳大学。

4.2.2 算法参数的影响

算法参数对总体效果影响不大。相对来说,比较重要的参数有以下:

① 子采样(subsampling)

子采样越低,对高频词越不利,对低频词有利。可以这么理解,本来高频词被迭代50次,低频词迭代10次,如果采样频率降低一半,高频词失去了25次迭代,而低频词只失去了5次。一般设置成le-5。个人觉得,降采样有类似tf-idf的功能,降低高频词对上下文影响的权重。

② 语言模型

skip-gram 和cbow,之前有对比,切词效果偏重各不相同。

从效果来看,感觉cbow对词频低的词更有利。这是因为cbow是基于周围词来预测某个词,虽然这个词词频低,但是它是基于周围词训练的基础上,通过算法来得到这个词的向量。通过周围词的影响,周围词训练的充分,这个词就会收益。

③ 窗口大小

窗口大小影响词和前后多少个词的关系,和语料中语句长度有关,建议可以统计一下语料中,句子长度的分布,再来设置window大小。

④ min-count

最小词频训练阀值,这个根据训练语料大小设置,只有词频超过这个阀值的词才能被训练。

根据经验,如果切词效果不好,会切错一些词,比如 “在深圳”,毕竟切错的是少数情况,使得这种错词词频不高,可以通过设置相对大一点的 min-count 过滤掉切错的词。

⑤ 向量维度

如果词量大,训练得到的词向量还要做语义层面的叠加,比如句子的向量表示用词的向量叠加,为了有区分度,语义空间应该要设置大一些,所以维度要偏大。一般情况下200维够用。

⑥ 其他参数

比如学习率,可以根据需要调。

4.3 word2vec 影响速度的因素有哪些?

4.3.1 语言模型:cbow 比skip-gram 更快

为什么 cbow更快,很重要的一个原因,cbow是基于周围词来预测这个单词本身 。而skip-gram是基于本身词去预测周围词。 那么,cbow只要 把窗口内的其他词相加一次作为输入来预测 一个单词。不管窗口多大,只需要一次运算。而skip-gram直接受窗口影响,窗口越大,需要预测的周围词越多。在训练中,通过调整窗口大小明显感觉到训练速度受到很大影响。

4.3.2 迭代次数

影响训练次数,语料不够的情况下,可以调大迭代次数。

4.3.3 线程数

单机版(google word2vec)可以通过设置多线程跑,集群版(spark mllib)可以设置多个partitions。但是从经验来看,在集群上设置partitions 过多,会影响训练的效果。

4.3.4 其他参数

采样频率 影响词的训练频率
min-count 最小词频 影响 训练词的数量
向量维度 维度决定了训练过程中计算的维度

4.4 怎样评估word2vec训练的好坏?

该篇论文介绍了word embedding 的评估方法。

4.4.1 词聚类

可以采用 kmeans 聚类,看聚类簇的分布

4.4.2 词cos 相关性

查找cos相近的词

4.4.3 Analogy对比

a:b 与 c:d的cos距离 (man-king woman-queen )

4.4.4 使用tnse,pca等降维可视化展示

在参考文献【3】中有用pca展示的代码。

 

参考文献

【1】15分钟入门Gensim

【2】python︱gensim训练word2vec及相关函数与功能理解

【3】How to Develop Word Embeddings in Python with Gensim

【4】关于word2vec,我有话要说

### Word2Vec 技术简介 Word2Vec是一种用于生成词语向量的技术,能够将自然语言中的单词转换成数值型向量表示。这种技术基于神经网络模型,在处理大规模语料库时表现出色[^1]。 ### 使用 Gensim 库构建 Word2Vec 模型 为了简化开发流程并提高效率,可以利用 Python 的 `gensim` 库快速搭建起一个功能完备的 Word2Vec 实现方案: #### 安装依赖包 首先需要安装必要的Python库: ```bash pip install gensim numpy ``` #### 准备训练数据 准备待训练的数据集,并将其转化为适合输入的形式。假设变量名为 `x` ,它应该是一个由多个句子组成的列表,而每个句子又是一系列分词后的字符串数组。 #### 初始化与配置参数 创建一个新的 Word2Vec 对象实例,并设置一些重要的超参选项,比如特征向量维度 (`vector_size`) 和最小词频阈值(`min_count`): ```python from gensim.models.word2vec import Word2Vec import numpy as np w2v = Word2Vec( vector_size=100, # 特征向量长度设为100维 min_count=3 # 过滤掉出现频率低于三次的词汇 ) ``` #### 构建词汇表 调用 `.build_vocab()` 方法读取整个语料库以建立词汇索引关系: ```python w2v.build_vocab(x) ``` #### 开始训练过程 通过`.train()`函数启动迭代更新权重的过程,期间指定总的样本数量以及循环轮次数目(epochs): ```python w2v.train( x, total_examples=w2v.corpus_count, epochs=20 # 设定训练周期数为20次 ) ``` 上述代码片段展示了如何使用Gensim库轻松地完成从零开始构建自己的Word2Vec模型的任务[^2]。 ### 关键概念解析 在深入理解Word2Vec的工作原理之前,有必要先熟悉几个核心术语和技术细节,例如神经网络架构的选择(CBOW vs Skip-Gram),优化算法(Hierarchical Softmax 或 Negative Sampling)等等[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值