1  简介

本文我们主要介绍词嵌入中一种非常经典的算法,Word2Vec,早期Word2Vec主要被用在文本类的问题中,但是现在做比赛的朋友应该都发现了,几乎一半的传统数据竞赛都会用到Word2Vec,所以这边我们必须得好好看看Word2Vec究竟在学习什么,这样今后也可以举一反三更好地使用这些技术。

本文我们先简单介绍词嵌入模型,然后详细介绍Word2Vec,包括Word2Vec在做什么,为什么用Word2Vec(它与老的BOW模型比有什么创新) ,Word2Vec常见的两种框架以及选择,最后我们会给出基于Pytorch版本的Word2Vec的两种实现。

本文我们不会罗列太多的数学,主要讲框架以及实现,大家可以思考将其如何的用到自己的问题中,在词嵌入模型中,我们也会列举些许相关的应用。

2  什么是词嵌入(Word Embedding)

词嵌入(Word Embedding)是一类词的表示方法,它可以通过很多机器学习模型将原先不同的词转化为不同的实数向量,目前的Word Embedding的技术非常多,例如Google的Word2Vec,Stanford的Glove, Facebook的Fastext等等。

Word Embedding有的时候也被称作为分布式语义模型或向量空间模型等,所以从名字和其转换的方式我们就可以明白, Word Embedding技术可以将相同类型的词归到一起,例如苹果,芒果香蕉等,在投影之后的向量空间距离就会更近,而书本,房子这些则会与苹果这些词的距离相对较远。

3  什么时候使用词嵌入模型

目前为止,Word Embedding可以用到特征生成,文件聚类,文本分类和自然语言处理等任务,例如:

  • 计算相似的词:Word Embedding可以被用来寻找与某个词相近的词。

  • 构建一群相关的词:对不同的词进行聚类,将相关的词聚集到一起;

  • 用于文本分类的特征:在文本分类问题中,因为词没法直接用于机器学习模型的训练,所以我们将词先投影到向量空间,这样之后便可以基于这些向量进行机器学习模型的训练;

  • 用于文件的聚类

上面列举的是文本相关任务,当然目前词嵌入模型已经被扩展到方方面面。典型的,例如:

  • 在微博上面,每个人都用一个词来表示,对每个人构建Embedding,然后计算人之间的相关性,得到关系最为相近的人;

  • 在推荐问题里面,依据每个用户的购买的商品记录,对每个商品进行Embedding,就可以计算商品之间的相关性,并进行推荐;

  • 在此次天池的航海问题中,对相同经纬度上不同的船进行Embedding,就可以得到每个船只的向量,就可以得到经常在某些区域工作的船只;

可以说,词嵌入为寻找物体之间相关性带来了巨大的帮助。现在基本每个数据竞赛都会见到Embedding技术。本文我们主要关注用的最多的Word2Vec模型。

4  什么是Word2Vec模型?

Word2vec是一种得到词表示的方法,它可以较好地捕捉句法和语义词汇的关系。如果仅从网络结构看的话,它就是一个两层的浅层网络。

即一个输入层+一个隐藏层+一个输出层。

相较于潜在语义分析模型,Word2vec是一种更好以及更加高效的方案。

5  Word2Vec在做什么?

Word2vec在向量空间中对词进行表示, 或者说词以向量的形式表示,在词向量空间中:相似含义的单词一起出现,而不同的单词则位于很远的地方。这也被称为语义关系

神经网络不理解文本,而只理解数字。词嵌入提供了一种将文本转换为数字向量的方法

Word2vec就是在重建词的语言上下文。那什么是语言上下文?在一般的生活情景中,当我们通过说话或写作来交流,其他人会试图找出句子的目的。例如,“印度的温度是多少”,这里的上下文是用户想知道“印度的温度”即上下文。

简而言之,句子的主要目标是语境。围绕口头或书面语言的单词或句子(披露)有助于确定上下文的意义。Word2vec通过上下文学习单词的矢量表示。

6  为什么用Word2Vec?

6.1  在词嵌入之前

关于为什么用Word2Vec好,这就要看在Word2Vec之前大家都在用什么方法,这些方法有什么不足,然后我们就能明白用Word2Vec的好处了。

6.2  潜在语义分析方法

潜在语义分析方法是在词向量之前用的最多的方法,它使用BOW(Bog of Words)的概念,每个词都被以编码的向量所表示,每个词都是一种稀疏的表示,其中向量的维度就是词汇表的大小。如果某个词出现了,那么我们就会对它进行计数。

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
data_corpus = ['guru99 is the best size for online tutorials. I love to visit guru99 .']
vocabulary = vectorizer.fit(data_corpus)
X          = vectorizer.transform(data_corpus)
print(X.toarray())
[[1 1 2 1 1 1 1 1 1 1 1]]
print(vocabulary.get_feature_names())

['best', 'for', 'guru99', 'is', 'love', 'online', 'size', 'the', 'to', 'tutorials', 'visit']

在潜在语义分析中,每一行(特征列)表示的是某个词,每个列表示的是词出现在在某个文本中的次数。

后来很多学者发现Countervector方法会忽律词在不同文本词库中的出现情况, 按理说如果某些词在不同的文本中都经常出现,那么应该降低此类词汇的重要性会更好。所以就出现了TFIDF方法。

  • TFIDF中,字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降.

但是其实TFIDF也存在很多明显的问题,它的不足如下(参见wiki):

对区别文档最有意义的词语应该是那些在文档中出现频率高,而在整个文档集合的其他文档中出现频率少的词语,所以如果特征空间坐标系取tf词频作为测度,就可以体现同类文本的特点。另外考虑到单词区别不同类别的能力,tf-idf法认为一个单词出现的文本频数越小,它区别不同类别文本的能力就越大。因此引入了逆文本频度idf的概念,以tf和idf的乘积作为特征空间坐标系的取值测度,并用它完成对权值tf的调整,调整权值的目的在于突出重要单词,抑制次要单词。但是在本质上idf是一种试图抑制噪声的加权,并且单纯地认为文本频率小的单词就越重要,文本频率大的单词就越无用,显然这并不是完全正确的。idf的简单结构并不能有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能,所以tf-idf法的精度并不是很高

6.3  BOW方法的问题

不管是Countervector还是TFIDF,我们发现它们都是从全局词汇的分布来对文本进行表示,所以缺点也明显,

  • 它忽略了单个文本句子中词的顺序, 例如 'this is bad' 在BOW中的表示和 'bad is this'是一样的;

  • 它忽略了词的上下文,假设我们写一个句子,"He loved books. Education is best found in books".我们会在处理这两句话的时候是不会考虑前一个句子或者后一个句子是什么意思,但是他们之间是存在某些关系的

为了克服上述的两个缺陷,Word2Vec被开发出来并用来解决上述的两个问题。

7  Word2Vec如何工作?

Word2Vec通过学习与其相邻的上下文来进行预测,举例来说,我们要得到句子"He Loves Football"中Loves的词向量,这边我们假设:

loves =  Vin. P(Vout / Vin) is calculated
where,
Vin is the input word.
P is the probability of likelihood.
Vout is the output word.

那么词"loves"在语料中移动每个单词。词与词之间的语法和语义便可以得到编码,这非常有助于帮助我们寻找相近与相似的词汇。

8  Word2Vec框架

Word2Vec解决的问题就是上面说的,此处我们介绍Word2Vec的两种框架,

  1. Continuous Bag of words (CBOW)

  2. Skip gram

我们都知道学习词的表示是无监督的,但是如果没有targets/labels,那么我们将很难去训练该模型,Skip-gram和CBOW将无监督的表示到有监督的形式,这样便可以用于模型训练了。其中,

  • CBOW,当前的词使用其周围的上下文(某个window size)的词进行预测,例如,如果$w_{i-1}$,$w_{i-2}$,$w_{i+1}$,$w_{i+2}$是给定的词或者是上下文,那么我们的模型需要预测出是$w_i$。

  • Skip-Gram则与CBOW相反,CBOW意味着它从单词中预测给定的序列或上下文。如果$w_i$是给定的,那么我用它去预测它的上下文$w_{i-1}$,$w_{i-2}$,$w_{i+1}$,$w_{i+2}$.

二者的区别大家可以参考下图:

8.1  CBOW

下面这个就是CBOW的图示,

我们假设V是词库的大小,N是隐藏层的大小,我们将输入定义为$\{x_{i-1},x_{i-1}, x_{i+1}, x_{i+2}\}$,那么我们就得到一个权重矩阵, 它的大小是$V * N$的.即,我们通过周围的词汇来对我们当前的词汇进行预测。

8.2  Skip-Gram

下面这个就是Skip-Gram的图示,

Skip-Gram模型和CBOW是相对的,我们通过当前的词汇去预测周围的词汇。

8.3  如何选择CBOW还是Skip-Gram

  • CBOW训练的时候要比Skip-Gram要快很多;

  • CBOW相较于Skip-Gram对于常见的词可以提供一个更好的表示;

  • Skip-Gram从需要少量的训练数据集中也可以表示稀有的单词或者短语;

8.4  词向量理解

Word2Vec是希望把词映射到词向量空间中,那么这中间就需要一个这样一个映射,这里怎么合理的理解?我们在训练时,先将原词映射到V维的空间,V是词库中不同词的个数。比如现在输入一个 x 的 one-hot encoder: [1,0,0,…,0],对应一个简单的词,则在输入层到隐含层的权重更新时,只有对应 1 这个位置的权重被激活,这些权重的个数,跟隐含层节点数是一致的,从而这些权重组成一个向量 vx 来表示x,而因为每个词语的 one-hot encoder 里面 1 的位置是不同的,所以,这个向量 vx 就可以用来唯一表示 x

9  代码展示

import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optimtorch.manual_seed(1)

构建映射,将词映射到整数上

CONTEXT_SIZE = 2  # 2 words to the left, 2 to the right
text = """We are about to study the idea of a computational process.
Computational processes are abstract beings that inhabit computers.
As they evolve, processes manipulate other abstract things called data.
The evolution of a process is directed by a pattern of rules
called a program. People create programs to direct processes. In effect,
we conjure the spirits of the computer with our spells.""".split()split_ind = (int)(len(text) * 0.8)
vocab = set(text)
vocab_size = len(vocab)
print('vocab_size:', vocab_size)w2i = {w: i for i, w in enumerate(vocab)}
i2w = {i: w for i, w in enumerate(vocab)}

构建CBOW以及SkipGram所需的数据形式

# context window size is two
def create_cbow_dataset(text):data = []for i in range(2, len(text) - 2):context = [text[i - 2], text[i - 1],text[i + 1], text[i + 2]]target = text[i]data.append((context, target))return datadef create_skipgram_dataset(text):import randomdata = []for i in range(2, len(text) - 2):data.append((text[i], text[i-2], 1))data.append((text[i], text[i-1], 1))data.append((text[i], text[i+1], 1))data.append((text[i], text[i+2], 1))# negative samplingfor _ in range(4):if random.random() < 0.5 or i >= len(text) - 3:rand_id = random.randint(0, i-1)else:rand_id = random.randint(i+3, len(text)-1)data.append((text[i], text[rand_id], 0))return datacbow_train = create_cbow_dataset(text)
skipgram_train = create_skipgram_dataset(text)
print('cbow sample', cbow_train[0])
print('skipgram sample', skipgram_train[0])

构建模型框架

class CBOW(nn.Module):def __init__(self, vocab_size, embd_size, context_size, hidden_size):super(CBOW, self).__init__()self.embeddings = nn.Embedding(vocab_size, embd_size)self.linear1 = nn.Linear(2*context_size*embd_size, hidden_size)self.linear2 = nn.Linear(hidden_size, vocab_size)def forward(self, inputs):embedded = self.embeddings(inputs).view((1, -1))hid = F.relu(self.linear1(embedded))out = self.linear2(hid)log_probs = F.log_softmax(out)return log_probsclass SkipGram(nn.Module):def __init__(self, vocab_size, embd_size):super(SkipGram, self).__init__()self.embeddings = nn.Embedding(vocab_size, embd_size)def forward(self, focus, context):embed_focus = self.embeddings(focus).view((1, -1))embed_ctx = self.embeddings(context).view((1, -1))score = torch.mm(embed_focus, torch.t(embed_ctx))log_probs = F.logsigmoid(score)return log_probs

进行模型训练

embd_size = 100
learning_rate = 0.001
n_epoch = 30def train_cbow():hidden_size = 64losses = []loss_fn = nn.NLLLoss()model = CBOW(vocab_size, embd_size, CONTEXT_SIZE, hidden_size)print(model)optimizer = optim.SGD(model.parameters(), lr=learning_rate)for epoch in range(n_epoch):total_loss = .0for context, target in cbow_train:ctx_idxs = [w2i[w] for w in context]ctx_var = Variable(torch.LongTensor(ctx_idxs))model.zero_grad()log_probs = model(ctx_var)loss = loss_fn(log_probs, Variable(torch.LongTensor([w2i[target]])))loss.backward()optimizer.step()total_loss += loss.datalosses.append(total_loss)return model, lossesdef train_skipgram():losses = []loss_fn = nn.MSELoss()model = SkipGram(vocab_size, embd_size)print(model)optimizer = optim.SGD(model.parameters(), lr=learning_rate)for epoch in range(n_epoch):total_loss = .0for in_w, out_w, target in skipgram_train:in_w_var = Variable(torch.LongTensor([w2i[in_w]]))out_w_var = Variable(torch.LongTensor([w2i[out_w]]))model.zero_grad()log_probs = model(in_w_var, out_w_var)loss = loss_fn(log_probs[0], Variable(torch.Tensor([target])))loss.backward()optimizer.step()total_loss += loss.datalosses.append(total_loss)return model, lossescbow_model, cbow_losses = train_cbow()
sg_model, sg_losses = train_skipgram()

模型测试

def test_cbow(test_data, model):print('====Test CBOW===')correct_ct = 0for ctx, target in test_data:ctx_idxs = [w2i[w] for w in ctx]ctx_var = Variable(torch.LongTensor(ctx_idxs))model.zero_grad()log_probs = model(ctx_var)_, predicted = torch.max(log_probs.data, 1)
#         print(predicted,int(predicted[0]))predicted_word = i2w[int(predicted[0])]print('predicted:', predicted_word)print('label    :', target)if predicted_word == target:correct_ct += 1print('Accuracy: {:.1f}% ({:d}/{:d})'.format(correct_ct/len(test_data)*100, correct_ct, len(test_data)))def test_skipgram(test_data, model):print('====Test SkipGram===')correct_ct = 0for in_w, out_w, target in test_data:in_w_var = Variable(torch.LongTensor([w2i[in_w]]))out_w_var = Variable(torch.LongTensor([w2i[out_w]]))model.zero_grad()log_probs = model(in_w_var, out_w_var)_, predicted = torch.max(log_probs.data, 1)predicted = predicted[0]if predicted == target:correct_ct += 1print('Accuracy: {:.1f}% ({:d}/{:d})'.format(correct_ct/len(test_data)*100, correct_ct, len(test_data)))test_cbow(cbow_train, cbow_model)
print('------')
test_skipgram(skipgram_train, sg_model)

10  参考文献

  1. tf-idf:https://zh.wikipedia.org/wiki/Tf-idf

  2. word2vec-pytorch:https://github.com/jojonki/word2vec-pytorch

  3. [NLP] 秒懂词向量Word2vec的本质:https://zhuanlan.zhihu.com/p/26306795

  4. Word Embedding Tutorial: word2vec using Gensim [EXAMPLE]:https://www.guru99.com/word-embedding-word2vec.html

  5. Implementing word2vec in PyTorch (skip-gram model):https://towardsdatascience.com/implementing-word2vec-in-pytorch-skip-gram-model-e6bae040d2fb

  6. https://gist.github.com/mbednarski/da08eb297304f7a66a3840e857e060a0

  7. Tutorial: Build your own Skip-gram Embeddings and use them in a Neural Network:https://blog.cambridgespark.com/tutorial-build-your-own-embedding-and-use-it-in-a-neural-network-e9cde4a81296

AI学习路线和优质资源,在后台回复"AI"获取

机器学习竞赛必备基础知识_Word2Vec相关推荐

  1. python基础一入门必备知识-Python数据分析入门必备基础知识

    今天,老师要带大家解数据分析的定义.核心思路.应用领域以及开发流程,向大家全方位展示数据分析入门必备基础知识,全都是干货哦!虽然看完本文,不能让大家立马变身为一名数据分析师,但是能让大家对数据分析有一 ...

  2. 机器学习算法的基础知识

    机器学习算法的基础知识 1.评估指标 2.偏差与方差(过拟合与欠拟合) 3.正则化(解决过拟合) 4.梯度下降算法(算法优化方式) 5.数据不平衡 1.评估指标 预测值 0 1 实际 0 TN FP ...

  3. 笔刷怎么做_零基础怎么学板绘?板绘小白必备基础知识

    零基础怎么学板绘?板绘小白必备基础知识!零基础学板绘需要准备什么东西?零基础学板绘需要学习哪些软件?板绘是做电影时要用到的人物场景原画的最重要的绘画方式,也是美术爱好者日常学习和创作的首选方式之一.那 ...

  4. java高手之路上的必备基础知识

    其实Java也就这么回事,重要的还是坚持,不能三天打鱼两天晒网.每一个分支下都是一门专业的技术,重要的是证明学精,熟练运用各项软件语言. 下面和大家分享java高手之路上的必备基础知识: 1.面向对象 ...

  5. 【网络通信】【电信运营商实战工程师】思科设备篇-网络工程师必备基础知识

    电信运营商实战工程师系列文章. 思科设备篇-网络工程师必备基础知识. 文章目录 1. 电信运营商网络设备机房 2. 认识并管理运营商网络设备 3. GNS3 安装与配置 4. IPv4地址及子网划分 ...

  6. 电商软件性能测试,实战 | 电商业务的性能测试(一): 必备基础知识

    原标题:实战 | 电商业务的性能测试(一): 必备基础知识 1. 测试步骤及模型分析 1.1 测试步骤总览 需求分析与测试设计(性能需求目标+业务模型拆解) 测试数据准备和构造(基于模型的数据准备) ...

  7. 电子工程师必备基础知识

    电子工程师必备基础知识(一) 运算放大器通过简单的外围元件,在模拟电路和数字电路中得到非常广泛的应用.运算放大器有好些个型号,在详细的性能参数上有几个差别,但原理和应用方法一样. 运算放大器通常有两个 ...

  8. 学习光盘刻录必备基础知识

    学习光盘刻录必备基础知识 2011年04月11日 [b] 学习光盘刻录必备基础知识[/b] 日期:2009-10-10 11:04 1.什么是CD-R? CD-R就是光盘刻录片(CD Recordab ...

  9. c语言需要哪些英语基础,学习C语言的必备基础知识(国外英语资料).doc

    学习C语言的必备基础知识(国外英语资料) 满卧裹瑟莉筑部获搪肪棱惺杀摄械圭旬敷豹休登悬邱雀报台盼拈毒鹰进怀却恩登雄旁二宇谊婆叔陌嘎扇体歌嫉蹿久题篡憨琵夹涌芦鸣褐颂诅讳拴狸果液梦绸亥氯确杯牌憨耗终贼况榔 ...

最新文章

  1. 结对开发石家庄地铁系统
  2. yii2-datepicker/datetimepicker插件使用
  3. C和指针之字符串之strncpy、strncat、strncmp
  4. eslint quo_Quo Vadis JUnit
  5. 【原型设计】第三节:Axure RP9 母版的使用说明以及操作教程
  6. 关于收集,标准化和集中化处理Golang日志的一些建议
  7. 【排列组合】只上代码不解释
  8. 人生定位 读后感(1)
  9. C语言---编译器、编辑器
  10. Wireshark: Getting Started
  11. 用户体验设计师、UI 设计师和交互设计师有什么区别?
  12. 解决安装webrtcvad出现错误的方法
  13. 赛迪网:VMware访谈实录
  14. android转服务器吗,王者荣耀角色迁移iOS区可以转安卓区吗 王者荣耀角色迁移iOS区转安卓区详情...
  15. 基于JPVideoPlayerKit的小视频播放
  16. 合肥市直计算机知识pdf,事业单位计算机专业知识整理(全)-20210419115129.pdf-原创力文档...
  17. 分享课程设计 仿电商 纯静态页面 果冻零食商城
  18. Python基础之算数运算符
  19. 如何学习计算机实现攻防
  20. 最大回撤线性算法实现

热门文章

  1. java I/O总结(收藏)
  2. UE中的几个极有用功能
  3. 【青少年编程】【蓝桥杯】绘制莲花图形
  4. 数据结构与算法:06 线性表
  5. 【机器学习】基于蚁群算法的多元非线性函数极值寻优
  6. 【MATLAB】符号数学计算(六):符号函数的操作
  7. cvsdfgdfdf
  8. 《新程序员002》图书正式上市! 从“新数据库时代”到“软件定义汽车”
  9. 用Python轻松搞定Excel中的20个常用操作
  10. 深耕智能制造和超高清视频领域,思谋科技获数千万美元融资