word2vec的原理及实现(附github代码)_word2vec github-程序员宅基地

技术标签: gensim  python  机器学习  word embedding  自然语言处理  词向量  word2vec  

目录

一、word2vec原理

二、word2vec代码实现

(1)获取文本语料

(2)载入数据,训练并保存模型

①  # 输出日志信息

②  # 将语料保存在sentence中

③  # 生成词向量空间模型

④  # 保存模型

(3)加载模型,实现功能

(4)增量训练


最近要用到文本词向量,借此机会重温一下word2vec。本文会讲解word2vec的原理和代码实现。

本文提供的github代码链接:https://github.com/yip522364642/word2vec-gensim

在NLP中,要让计算机读懂文本语言,首先要对文本进行编码。常见的编码如独热编码(one-hot encoding),词袋模型(BOW,bag of words),词向量模型(word embedding)。而word2vec就是词向量模型中的一种,它是google在2013年发布的工具。

 

一、word2vec原理

word2vec工具主要包含两个模型:连续词袋模型(CBOW,continuous bag of words)和跳字模型(skip-gram)。如下图所示,左边蓝色部分代表CBOW模型,右边绿色部分代表Skip-gram模型。它们两者的区别是,CBOW是根据上下文去预测目标词来训练得到词向量,如图是根据W(t-2),W(t-1),W(t+1),W(t+2)这四个词来预测W(t);而Skip-gram是根据目标词去预测周围词来训练得到词向量,如图是根据W(t)去预测W(t-2),W(t-1),W(t+1),W(t+2)。根据经验,CBOW用于小型语料库比较适合,而Skip-gram在大型的语料上表现得比较好。

那具体是如何实现的呢?下文以CBOW模型为例,介绍各个步骤实现细节(具体公式先省略,有空再补上)

以上图为例,

① 输入层(Input layer):目标单词上下文的单词(这里显示三个),每个单词用ont-hot编码表示,为[1 * V]大小的矩阵,V表示词汇大小;

② 所有的ont-hot矩阵乘以输入权重矩阵W,W是[V * N]大小的共享矩阵,N是指输出的词的向量维数;

③ 将相乘得到的向量 ([1 * V] 的ont-hot矩阵乘上[V * N]的共享矩阵W) 相加,然后求平均作为隐层向量h, 大小为[1 * N];

④ 将隐层向量h乘以输出权重矩阵W',W'是[N * V]大小的共享矩阵;

⑤ 相乘得到向量y,大小为[1 * V],然后利用softmax激活函数处理向量y,得到V-dim概率分布;

⑥ 由于输入的是ont-hot编码,即每个维度都代表着一个单词,那么V-dim概率分布中,概率最大的index所指代的那个单词为预测出的中间词。

⑦ 将结果与真实标签的ont-hot做比较,误差越小越好,这里的误差函数,即loss function一般选交叉熵代价函数。

以上为CBOW生成词向量的全过程。如果我们只是想提取每个单词的向量,那么只需要得到向量y就可以了,但训练过程中要去做预测并计算误差,去求得输入权重矩阵W和输出权重矩阵W'。

 

二、word2vec代码实现

下文,我将介绍采用python的gensim包实现word2vec,并介绍相关函数功能。

(1)获取文本语料

本文采用网上的文本语料,语料大小将近100M,下载地址为http://mattmahoney.net/dc/text8.zip

下载之后,可以查看语料内容(看语料主要是为了清楚数据的格式是怎样的,方便后面模型的读取)

'''
1 获取文本语料并查看
'''
with open('text8', 'r', encoding='utf-8') as file:
    for line in file.readlines():
        print(line)

我们发现语料已经按空格分好词,并且去除了所有的标点符号,也没有换行符,如下所示为输出截图

 

(2)载入数据,训练并保存模型

'''
2 载入数据,训练并保存模型
'''
from gensim.models import word2vec
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)  # 输出日志信息
sentences = word2vec.Text8Corpus('text8')  # 将语料保存在sentence中
model = word2vec.Word2Vec(sentences, sg=1, size=100,  window=5,  min_count=5,  negative=3, sample=0.001, hs=1, workers=4)  # 生成词向量空间模型
model.save('text8_word2vec.model')  # 保存模型

接下来逐个讲解每个代码的意思(非常重要!!!)

①  # 输出日志信息

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

这一行表示程序会输出日志信息,形式(format)为日期(asctime):信息级别(levelname):日志信息(message),信息级别为正常信息(logging.INFO)。当然,logging.basicConfig函数里面可以添加各个参数,这里只添加了format参数,你也可以根据需要增加参数,建议只加自己想知道的东西,具体参考如下:

logging.basicConfig函数各参数:
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a'
format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
 %(levelno)s: 打印日志级别的数值
 %(levelname)s: 打印日志级别名称
 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
 %(filename)s: 打印当前执行程序名
 %(funcName)s: 打印日志的当前函数
 %(lineno)d: 打印日志的当前行号
 %(asctime)s: 打印日志的时间
 %(thread)d: 打印线程ID
 %(threadName)s: 打印线程名称
 %(process)d: 打印进程ID
 %(message)s: 打印日志信息
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略

logging打印信息函数:

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

输出结果截图:

 

②  # 将语料保存在sentence中

sentences = word2vec.Text8Corpus('text8')

这里采用的‘text8‘语料是已经按空格分好词,并且去除了所有的标点符号,也没有换行符,所以不需要任何的预处理。

对于大规模数据集,sentences可以采用word2vec.BrownCorpus(),word2vec.Text8Corpus()或word2vec.LineSentence()来读取;对于小规模数据集,sentences可以是一个List的形式,如sentences=[["I", "love", "China", "very", "much"], ["China", "is", "a", "strong", "country"]]。

 

③  # 生成词向量空间模型

model = word2vec.Word2Vec(sentences, sg=1, size=100,  window=5,  min_count=5,  negative=3, sample=0.001, hs=1, workers=4)

此行通过设置各个参数,来配置word2vec模型,具体参数的介绍如下:

'''
1.sentences:可以是一个List,对于大语料集,建议使用BrownCorpus,Text8Corpus或·ineSentence构建。
2.sg: 用于设置训练算法,默认为0,对应CBOW算法;sg=1则采用skip-gram算法。
3.size:是指输出的词的向量维数,默认为100。大的size需要更多的训练数据,但是效果会更好. 推荐值为几十到几百。
4.window:为训练的窗口大小,8表示每个词考虑前8个词与后8个词(实际代码中还有一个随机选窗口的过程,窗口大小<=5),默认值为5。
5.alpha: 是学习速率
6.seed:用于随机数发生器。与初始化词向量有关。
7.min_count: 可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5。
8.max_vocab_size: 设置词向量构建期间的RAM限制。如果所有独立单词个数超过这个,则就消除掉其中最不频繁的一个。每一千万个单词需要大约1GB的RAM。设置成None则没有限制。
9.sample: 表示 采样的阈值,如果一个词在训练样本中出现的频率越大,那么就越会被采样。默认为1e-3,范围是(0,1e-5)
10.workers:参数控制训练的并行数。
11.hs: 是否使用HS方法,0表示不使用,1表示使用 。默认为0
12.negative: 如果>0,则会采用negativesamp·ing,用于设置多少个noise words
13.cbow_mean: 如果为0,则采用上下文词向量的和,如果为1(default)则采用均值。只有使用CBOW的时候才起作用。
14.hashfxn: hash函数来初始化权重。默认使用python的hash函数
15.iter: 迭代次数,默认为5。
16.trim_rule: 用于设置词汇表的整理规则,指定那些单词要留下,哪些要被删除。可以设置为None(min_count会被使用)或者一个接受()并返回RU·E_DISCARD,uti·s.RU·E_KEEP或者uti·s.RU·E_DEFAU·T的函数。
17.sorted_vocab: 如果为1(defau·t),则在分配word index 的时候会先对单词基于频率降序排序。
18.batch_words:每一批的传递给线程的单词的数量,默认为10000
'''

④  # 保存模型

model.save('text8_word2vec.model')  

将模型保存起来,以后再使用的时候就不用重新训练,直接加载训练好的模型使用就可以了。

下面会介绍加载模型后,直接使用word2vec来实现各个功能。

 

(3)加载模型,实现功能

'''
3 加载模型,实现各个功能
'''
# 加载模型
model = word2vec.Word2Vec.load('text8_word2vec.model')

# 计算两个词的相似度/相关程度
print("计算两个词的相似度/相关程度")
word1 = 'man'
word2 = 'woman'
result1 = model.similarity(word1, word2)
print(word1 + "和" + word2 + "的相似度为:", result1)
print("\n================================")

# 计算某个词的相关词列表
print("计算某个词的相关词列表")
word = 'bad'
result2 = model.most_similar(word, topn=10)  # 10个最相关的
print("和" + word + "最相关的词有:")
for item in result2:
    print(item[0], item[1])
print("\n================================")

# 寻找对应关系
print("寻找对应关系")
print(' "boy" is to "father" as "girl" is to ...? ')
result3 = model.most_similar(['girl', 'father'], ['boy'], topn=3)
for item in result3:
    print(item[0], item[1])
print("\n")

more_examples = ["she her he", "small smaller bad", "going went being"]
for example in more_examples:
    a, b, x = example.split()
    predicted = model.most_similar([x, b], [a])[0][0]
    print("'%s' is to '%s' as '%s' is to '%s'" % (a, b, x, predicted))
print("\n================================")

# 寻找不合群的词
print("寻找不合群的词")
result4 = model.doesnt_match("flower grass pig tree".split())
print("不合群的词:", result4)
print("\n================================")

# 查看词向量(只在model中保留中的词)
print("查看词向量(只在model中保留中的词)")
word = 'girl'
print(word, model[word])
# for word in model.wv.vocab.keys():  # 查看所有单词
#     print(word, model[word])

 

(4)增量训练

在使用词向量时,如果出现了在训练时未出现的词(未登陆词),可采用增量训练的方法,训练未登陆词以得到其词向量

'''
4 增量训练
'''
model = word2vec.Word2Vec.load('text8_word2vec.model')
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)
model.save('text8_word2vec.model')

 

完整代码如下,github为:https://github.com/yip522364642/word2vec-gensim

# -*- coding: utf-8 -*-
# @Time : 2019/11/13 14:55
# @FileName: word2vec-gensim.py
# @Software: PyCharm
# @Author : yip
# @Email : [email protected]
# @Blog : https://blog.csdn.net/qq_30189255
# @Github : https://github.com/yip522364642


import warnings

warnings.filterwarnings("ignore")

'''
1 获取文本语料并查看
'''
# with open('text8', 'r', encoding='utf-8') as file:
#     for line in file.readlines():
#         print(line)

'''
2 载入数据,训练并保存模型
'''
from gensim.models import word2vec
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)  # 输出日志信息
sentences = word2vec.Text8Corpus('text8')  # 将语料保存在sentence中
model = word2vec.Word2Vec(sentences, sg=1, size=100,  window=5,  min_count=5,  negative=3, sample=0.001, hs=1, workers=4)  # 生成词向量空间模型
model.save('text8_word2vec.model')  # 保存模型


'''
3 加载模型,实现各个功能
'''
# 加载模型
model = word2vec.Word2Vec.load('text8_word2vec.model')

# 计算两个词的相似度/相关程度
print("计算两个词的相似度/相关程度")
word1 = 'man'
word2 = 'woman'
result1 = model.similarity(word1, word2)
print(word1 + "和" + word2 + "的相似度为:", result1)
print("\n================================")

# 计算某个词的相关词列表
print("计算某个词的相关词列表")
word = 'bad'
result2 = model.most_similar(word, topn=10)  # 10个最相关的
print("和" + word + "最相关的词有:")
for item in result2:
    print(item[0], item[1])
print("\n================================")

# 寻找对应关系
print("寻找对应关系")
print(' "boy" is to "father" as "girl" is to ...? ')
result3 = model.most_similar(['girl', 'father'], ['boy'], topn=3)
for item in result3:
    print(item[0], item[1])
print("\n")

more_examples = ["she her he", "small smaller bad", "going went being"]
for example in more_examples:
    a, b, x = example.split()
    predicted = model.most_similar([x, b], [a])[0][0]
    print("'%s' is to '%s' as '%s' is to '%s'" % (a, b, x, predicted))
print("\n================================")

# 寻找不合群的词
print("寻找不合群的词")
result4 = model.doesnt_match("flower grass pig tree".split())
print("不合群的词:", result4)
print("\n================================")

# 查看词向量(只在model中保留中的词)
print("查看词向量(只在model中保留中的词)")
word = 'girl'
print(word, model[word])
# for word in model.wv.vocab.keys():  # 查看所有单词
#     print(word, model[word])


'''
4 增量训练
'''
model = word2vec.Word2Vec.load('text8_word2vec.model')
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)
model.save('text8_word2vec.model')

 

以上介绍了word2vec原理代码实现。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_30189255/article/details/103049569

智能推荐

简单代码训练(if语句)_python条件分支if语句 当货物重量小于20公斤的时候收费大于5元-程序员宅基地

文章浏览阅读873次。1.(if 语句)读入一个整数,判断其是奇数还是偶数:package com.xiaobaiExercise;//导包import java.util.Scanner;//判断奇偶数public class OddNumber { public static void main(String[] args) { int a; System.out.println("请输入一个自然数:"); //输入数字 Scanner x = new Scanner(Syste._python条件分支if语句 当货物重量小于20公斤的时候收费大于5元

个人简介网页设计作业 静态HTML个人介绍网页作业 DW个人网站模板下载 WEB静态大学生简单网页 个人网页作品代码 个人网页制作 学生个人网页-程序员宅基地

文章浏览阅读53次。个人网页设计、‍♂️个人简历制作、简单静态HTML个人网页作品、个人介绍网站模板 、等网站的设计与制作。个人网页设计网站模板采用DIV CSS布局制作,网页作品有多个页面,如 :个人介绍(文字页面)、我的作品(图片列表)、个人技能(图文页面)、在线留言(表单页面)CSS样式方面网页整体采用左右布局结构,制作了网页背景图片,导航区域每个导航背景色不同,导航背景色与页面背景呼应。 一套A+的网页应该包含 (具体可根据个人要求而定)网站布局方面:计划采用目前主流的、能兼容各大

4.4.5 信道均衡(一)-程序员宅基地

文章浏览阅读2.1w次,点赞3次,收藏62次。4.4.5 信道均衡(一)一、为什么要信道均衡? 数字信号在实际信道上传输时,由于信道传输特性不理想以及信道噪声的影响,接收端接收到的信号不可避免地发生错误。为了恢复发送的数据信息,接收端需要估计出信道的特性,并对接收到的数据进行校正。 二、信道均衡的常用方法 一般来说有二种方法:差分检测和相干检测。 差分检测:比较相邻两个信号的相位和幅度的差值; ..._信道均衡

PHP中时间戳和时区_php gmt date-程序员宅基地

文章浏览阅读1.2k次。时间戳时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。时区由于世界各国家与地区经度不同,地方时也有所不同,因此会划分为不同的时区。正式的时区划分,每隔经度15°划分一个时区,共包括24个时区。我们目前使用的北京时间并不是北京(东经116.4°)的地方时间,而是东经120°(东八区)的地方时间。..._php gmt date

【微信小程序】实现验证码倒计时效果_微信小程序 发送验证码倒计时-程序员宅基地

文章浏览阅读334次。效果图wxml<input class='input-pwd' placeholder="新密码" placeholder-style='color: #000' password focus bindconfirm='getPwd'/><input class='input-tel' type='number' placeholder="手机号" placehol..._微信小程序 发送验证码倒计时

Python爬虫编程思想(112):基于Splash的爬虫--模拟鼠标键盘动作_splash:send_keys-程序员宅基地

文章浏览阅读800次。Splash Lua脚本还提供了很多方法,用于模拟鼠标和键盘的动作,例如,mouse_click函数可以模拟鼠标单击的动作,send_keys可以模拟键盘按键的动作。_splash:send_keys

随便推点

unity 协程原理-程序员宅基地

文章浏览阅读1.7k次,点赞36次,收藏42次。Unity 开发常用到协程Coroutine,但是unity的协程和monobehaviour绑定,有时候并不想继承mono,但是又想使用协程,这时候就有点麻烦,

centos7 安装wps 依赖源libXss.so.1()(64bit)-程序员宅基地

文章浏览阅读489次。手动搜索发现https://pkgs.org/download/libXss.so.1()(64bit)可以下载。centos 在安装wps时会提示:依赖检测失败: libXss.so.1()(64bit)被需要。选择合适自己的系统,这里以centos7为例。进入后下拉到Download选择二进制文件。yum 或者apt安装依赖失败。_libxss.so.1

关于Ubuntu18.04虚拟机配置桥接模式_gnome box bridge-程序员宅基地

文章浏览阅读8k次,点赞9次,收藏43次。虚拟机设置为桥接模式+静态ip的话可以连接ARM开发板的。先说明一下,我一开始是在校园网环境下配置的,我们的路由器是设置为AP模式(也就是交换机模式)的,连入wifi后获取的是A类静态IP,在这种情况下配置桥接模式配了好多天打死都配不出来,最后屈服了,换成了手机开热点给电脑连,5分钟就配置完了。详细步骤如下:windows下cmd中输入ipconfig /all,输出如下:记住主机的IP..._gnome box bridge

贪吃蛇小游戏的实现【C语言魅力时刻】_c#贪吃蛇小游戏实现关卡难度的控制-程序员宅基地

文章浏览阅读564次,点赞9次,收藏8次。我们大致要实现的效果如下:你可以看到,这两张游戏界面中,我们首先修改了我们的控制台的名称,其次我们隐藏了我们的光标,然后我同时做到了在控制台上的任意位置打印输出我们的文字。前面的改名字和暂停我已经说过,接下来让我们来说说如何改变控制台坐标以及如何隐藏光标。_c#贪吃蛇小游戏实现关卡难度的控制

rsync和inotify实时备份实现_watch rsync-程序员宅基地

文章浏览阅读611次。rsync是一个远程备份工具,用于在本地和远程计算机之间同步和备份文件。它能够实现增量备份,节省了大量时间和带宽。rsync也支持加密传输和备份,这使得它非常适合用于远程备份,同时也可用于本地备份。增量备份:仅备份发生了变化的文件,节省带宽和存储空间。安全:支持加密传输和备份。支持备份到远程服务器。inotify是一个Linux内核特性,用于监控文件系统中的事件。它能够监控文件或目录的创建、删除、修改、移动等事件,通过这些事件触发的钩子,实现实时监控和响应。_watch rsync

车载以太网协议的架构_车载以太网架构-程序员宅基地

文章浏览阅读3.2k次,点赞4次,收藏41次。无论是软件定义汽车,还是分布式ECU抑或是自适应Autosar,都离不开智能汽车时代的基础技术车载以太网,对于硬件工程师来说,车载以太网物理层和交换机是其最关注的芯片,这也是利润率远超过高算力芯片的领域,也是基本上被欧美企业垄断的领域。上图是整个车载以太网的7层OSI模型与标准分布图,我们最常提到的是TSN或EAVB,而物理层标准鲜少有人提及。因为绝大多数工程师都不会和物理层打交道。很多人都在说域控制器、服务导向架构、分布式计算或软件定义汽车,殊不知关键的1G车载以太网物理层芯片在2020年才SOP_车载以太网架构

推荐文章

热门文章

相关标签