第22周:调用Gensim库训练Word2Vec模型
目录
前言
一、Word2vec基本知识
1.1 Word2Vec是什么
1.2 Word2Vec两种主要模型架构
1.2.1 CBOW模型
1.2.2 Skip-gram模型
1.3 实例说明
1.4 调用方法
二、准备工作
2.1 安装Gensim库
2.2 对原始语料分词
2.2 添加自定义停用词
三、训练Word2Vec模型
四、模型应用
4.1 计算词汇相似度
4.2 找出不匹配的词汇
4.3 计算词汇的词频
总结
前言
🍨 本文为[🔗365天深度学习训练营]中的学习记录博客
🍖 原作者:[K同学啊]
说在前面
本周任务:了解并学习Word2Vec相关知识、创建一个.txt文件存放自定义词汇,防止其被切分
我的环境:Python3.8、Pycharm2020、torch1.12.1+cu113
数据来源:[K同学啊]
一、Word2vec基本知识
1.1 Word2Vec是什么
自然语言处理(NLP)是一种涉及到处理语言文本的计算机技术。在 NLP中,最小的处理单位是词语,词语是语言文本的基本组成部分。词语组成句子,句子再组成段落、篇章、文档,因此处理 NLP 问题的第一步是要对词语进行处理。
在进行 NLP 问题处理时,一个常见的任务是判断一个词的词性,即动词还是名词等等。这可以通过机器学习来实现。具体地,我们可以构建一个映射函数 f(x)->y,其中 x是词语,y是它们的词性。为了使用机器学习模型,需要将词语转换成数值形式。然而,在 NLP 中,词语是人类的抽象总结,是符号形式的(比如中文、英文、拉丁文等等),不是数值形式的,因此需要将它们嵌入到一个数学空间中,这个过程就是词嵌入(word embedding)。
词嵌入是将词语映射到一个向量空间中的过程,使得相似的词在向量空间中距离较近,而不相似的词距离较远。Word2Vec 则是其中的一种词嵌入方法,是一种用于生成词向量的浅层神经网络模型,由Tomas Mikolov及其团队于2013年提出Word2Vec通过学习大量文本数据,将每个单词表示为一个连续的向量,这些向量可以捕捉单词之间的语义和句法关系。Word2Vec有两种主要架构:连续词袋模型(Continuous Bag of Words,CBOW)和Skip-Gram模型。
1.2 Word2Vec两种主要模型架构
1.2.1 CBOW模型
CBOW(Continuous Bag of Words)模型是通过上下文来预测当前值,相当于一句话中扣掉一个词,让你猜这个词是什么。
具体来说,CBOW模型首先将输入词语转换为词向量,然后将这些词向量相加得到一个向量表示,这个向量表示就是当前上下文的表示。最后,CBOW模型使用这个向量来表示预测目标词语的概率分布。CBOW模型的核心思想是根据上下文预测当前词语,因此它通常适用于训练数据中目标词语出现频率较高的情况。
1.2.2 Skip-gram模型
Skip-gram模型用当前词来预测上下文,相当于给你一个词,让你猜前面和后面可能出现什么词。
具体来说,Skip-gram模型首先将目标词语转换为它的词向量,然后使用这个词向量来预测它周围的词语,Skip-gram模型的核心思想是利用目标词语来预测上下文,因此它通常是用于训练数据中目标词语出现频率较低的情况。
Skip-gram 模型和 CBOW 模型的训练过程都是基于反向传播算法和随机梯度下降算法实现的。在训练过程中,两个模型都会通过不断地更新词向量来最小化损失函数使得目标词语和它周围的词语在向量空间中距离更近。最终,训练完成后,每个词语都被嵌入到了一个低维向量空间中,这些向量可以用于各种 NLP 任务,如语言模型词性标注、文本分类等等。
1.3 实例说明
实例:假设我们有一下句子作为训练语料:
The quick brown fox jumps over the lazy dog
- 对于Skip-gram模型,假设选择窗口大小为2(即在目标单词前后各取2个单词作为上下文),以单词‘jumps’为例,我们的训练样本为---输入:jumps,输出(quick、brown、over、the)。这种情况下,训练样本用于调整词向量,使得给定单词‘jumps’时,上下文单词的概率最大化
- 对于CBOW模型,训练样本为--输入:quick、brown、over、the,输出:jumps。在这个情况下,CBOW模型会根据上下文来预测目标单词jumps
1.4 调用方法
gensim.models.word2vec()函数原型
gensim.models.word2vec.Word2Vec(sentences=None, corpus_file=None, size=100, alpha=0.025, window=5, min_count=5,max_vocab_size=None, sample=0.001, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, ns_exponent=0.75, cbow_mean=1, hashfxn=<built-in function hash>, iter=5, null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000, compute_loss=False, callbacks=(), max_final_vocab=None)
参数介绍:
- sentences (iterable of iterables, optional): 供训练的句子,可以使用简单的列表。
- corpus_file (str, optional): LineSentence格式的语料库文件路径。
- size (int, optional): word向量的维度。
- window (int, optional): 一个句子中当前单词和被预测单词的最大距离。
- min_count (int, optional): 忽略词频小于此值的单词。
- workers (int, optional): 训练模型时使用的线程数。
- sg ({0, 1}, optional): 模型的训练算法: 1: skip-gram; 0: CBOW.
- hs ({0, 1}, optional): 1: 采用hierarchical softmax训练模型; 0: 使用负采样。
- negative (int, optional): 0: 使用负采样,设置多个负采样(通常在5-20之间)。
- ns_exponent (float, optional): 负采样分布指数。1.0样本值与频率成正比,0.0样本所有单词均等,负值更多地带样低频词。
- cbow_mean ({0, 1}, optional): 0: 使用上下文单词向量的总和; 1: 使用均值,适用于使用CBOW。
- alpha (float, optional): 初始学习率。
- min_alpha (float, optional): 随着训练的进行,学习率线性下降到min_alpha。
- seed (int, optional): 随机数发生器种子。
- max_vocab_size (int, optional): 词汇构建期间RAM的限制,如果有更多的独特单词,则修剪不常见的单词。每1000万个类型的字需要大约1GB的RAM。
- max_final_vocab (int, optional): 自动选择匹配的min_count将词汇限制为目标词汇大小。
- sample (float, optional): 高频词随机下采样的配置阈值,范围是(0,1e-5)。
- hashfxn (function, optional): 哈希函数用于随机初始化权重,以提高训练的可重复性。
- iter (int, optional): 迭代次数。
- trim_rule (function, optional): 词汇修剪规则,指定某些词语是否应保留在词汇表中,修剪掉或使用默认值处理。
- sorted_vocab ({0, 1}, optional): 如果为1,则在分配单词索引前按降序对词汇表进行排序。
- batch_words (int, optional): 每一个batch传递给线程单词的数量。
- compute_loss (bool, optional): 如果为True,则计算并存储可使用get_latest_training_loss()检索的损失值。
二、准备工作
2.1 安装Gensim库
pip install gensim
2.2 对原始语料分词
选择《人民的名义》的小说原文作为语料,先采用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', encoding='utf-8') as f:
result_cut = []
lines = f.readlines()
for line in lines:
result_cut.append(list(jieba.cut(line)))
f.close()
输出如下:
2.2 添加自定义停用词
拿到了分词后的文件,在一般的NLP处理中,会需要去停用词。由于word2vec的算法依赖于上下文,而上下文有可能就是停词。因此对于word2vec,我们可以不用去停词,仅仅去掉一些标点符号,做一个简单的数据清洗。
现在我们可以直接读分词后的文件到内存。这里使用了word2vec提供的LineSentence类来读文件,然后套用word2vec的模型。在实际应用中,可以调参提高词的embedding的效果。
在自然语言处理(NLP)中,停用词(stop words)是指在文本中频繁出现但对于传达实际意义贡献不大的词。这些词通常是冠词、介词、连词等,例如“的”、“和”、“是”、“在”等。停用词在文本中几乎无处不在,但它们并不携带太多实际的语义信息。
代码如下:
#添加自定义停用词
stopwords_list = [",", "。", "\n", "\u3000", " ", ":", "!", "?", "…"] #\u3000 是一个 Unicode 编码的字符,它代表一个全角的空白字符,通常在中文文本中用作空格。
def remove_stopwords(ls): # 去除停用词
return [word for word in ls if word not in stopwords_list]
result_stop = [remove_stopwords(x) for x in result_cut if remove_stopwords(x)]
print(result_stop[100:103])
输出结果如下:
[['侯亮平', '也', '很', '幽默', ',', '一把', '抓住', '了', '赵德汉', '的', '手', ':', '哎', ',', '赵', '处长', ',', '我', '既', '来', '了', '还', '真', '舍不得', '和', '你', '马上', '就', '分手', '哩', '!', '咱们', '去', '下', '一个点', '吧', '!', '说', '罢', ',', '从', '赵家', '桌上', '杂物', '筐', '里', '准确', '地', '拿出', '一张', '白色', '门卡', ',', '插到', '了', '赵德汉', '的', '上衣', '口袋', '里'], ['赵德汉', '慌', '了', ',', '忙', '把门', '卡往', '外', '掏', ':', '这', '这', '什么', '呀', '这', '是', '?'], ['你', '帝京', '苑', '豪宅', '的', '门', '卡', '啊', '!', '请', '继续', '配合', '我们', '执行公务', '吧', '!']]
三、训练Word2Vec模型
代码如下:
#二、训练Word2Vec模型
from gensim.models import Word2Vec
model = Word2Vec(result_stop, #用于训练的语料数据
vector_size=100, #是指特征向量的维度,默认为100
window=5, #一个句子中当前单词和被预测单词的最大距离
min_count=1) #可以对字典做截断,词频少于min_count次数的单词会被丢弃掉,默认值为5
四、模型应用
4.1 计算词汇相似度
model.wv.similarity 函数是 Gensim 库中 Word2Vec 模型的一个方法,用于计算两个词向量的余弦相似度。余弦相似度是一种衡量两个向量在方向上相似程度的度量,它的值范围在 -1 到 1 之间,1 表示完全相同的方向,-1 表示完全相反的方向,0 表示两者正交,即没有相似性。
计算余弦相似度的步骤如下:
- 获取词向量:首先,需要获取两个词的词向量。这些向量是在 Word2Vec 模型训练过程中学习到的。
- 计算点积:计算两个向量的点积(内积)。点积可以通过将两个向量的对应元素相乘然后求和得到。
- 计算向量长度:计算每个向量的长度(范数)。向量的长度是通过将向量中的每个元素平方后求和,然后取平方根得到的。
- 计算余弦相似度:余弦相似度是通过将两个向量的点积除以它们长度的乘积得到的
代码如下:
#3.1 计算词汇相似度(利用similarity计算两个词汇之间的余弦相似度)
print(model.wv.similarity('沙瑞金', '季昌明'))
print(model.wv.similarity('沙瑞金', '田国富'))
for e in model.wv.most_similar(positive=['沙瑞金'], topn=5):
print(e[0], e[1])
打印输出如下:
0.999525
0.99917823李达康 0.9997789263725281
学生 0.9997006058692932
肖钢玉 0.9996224641799927
陈海 0.9996022582054138
又 0.9995934963226318
4.2 找出不匹配的词汇
model.wv.doesnt_match 是 Gensim 库中 Word2Vec 模型的一个方法,用于找出一个列表中与其他词最不相似的词。这个方法基于 Word2Vec 模型学习到的词向量,通过计算词向量之间的余弦相似度来确定最不相似的词。
计算余弦相似度的步骤如下:
- 获取词向量:首先,需要获取列表中所有词的词向量。这些向量是在 Word2Vec 模型训练过程中学习到的。
- 计算相似度:对于列表中的每个词,计算它与其他词的余弦相似度。这需要对列表中的每个词计算与其他词的点积,然后除以它们长度的乘积。
- 选择最不相似的词:对于列表中的每个词,找出它与其他词中最小的相似度值。这个最小值就是该词与其他词中最不相似的度量。
- 返回结果:最后,返回列表中与其他词最不相似的词
代码如下:
#3.2 找出不匹配的词汇
odd_word = model.wv.doesnt_match(["苹果", "香蕉", "橙子", "书"])
print(f"在这组词汇中不匹配的词汇:{odd_word}")
输出如下:
在这组词汇中不匹配的词汇:书
4.3 计算词汇的词频
get_vecattr函数是Word2Vec模型中的一个方法,用于获取词向量的附加属性。它通常接收两个参数:单词和一个属性名称。
- 第一个参数:单词,即你想要查询的词汇。
- 第二个参数:属性名称,可以是以下几种:'count':该单词在训练时出现的次数。'mean':返回这个词向量的平均值。'norm':返回这个词向量的欧几里得范数(L2范数)。'total_count':这个单词及其所有上下文词对的总数。'total_bytes':存储向量所需的字节数。'total_words':训练集中的总词数。‘state_size':在线训练期间的状态大小
输出如下:
沙瑞金:353
总结
学习并了解了Word2Vec,知道了具体的操作流程