Embedding技术在推荐系统中的应用

什么是Word2Vec和Embeddings?

Word2Vec是从大量文本语料中以无监督的方式学习语义知识的一种模型,它被大量地用在自然语言处理(NLP)中。那么它是如何帮助做自然语言处理呢?Word2Vec其实就是通过学习文本来用词向量的方式表征词的语义信息,即通过一个嵌入空间使得语义上相似的单词在该空间内距离很近。Embedding其实就是一个映射,将单词从原先所属的空间映射到新的多维空间中,也就是把原先词所在空间嵌入到一个新的空间中去。

从直观角度上来理解一下,cat这个单词和kitten属于语义上很相近的词,而dog和kitten则不是那么相近,iphone这个单词和kitten的语义就差的更远了。通过对词汇表中单词进行这种数值表示方式的学习(也就是将单词转换为词向量),能够让基于这样的数值进行向量化的操作从而得到一些有趣的结论。比如说,如果对词向量kitten、cat以及dog执行这样的操作:kitten - cat + dog,那么最终得到的嵌入向量(embedded vector)将与puppy这个词向量十分相近。

1.模型

Word2Vec模型中,主要有Skip-Gram和CBOW两种模型,从直观上理解,Skip-Gram是给定input word来预测上下文。而CBOW是给定上下文,来预测input word。

 

Skip-Gram模型的基础形式非常简单。

Word2Vec模型实际上分为了两个部分,第一部分为建立模型,第二部分是通过模型获取嵌入词向量。Word2Vec的整个建模过程实际上与自编码器(auto-encoder)的思想很相似,即先基于训练数据构建一个神经网络,当这个模型训练好以后,并不会用这个训练好的模型处理新的任务,真正需要的是这个模型通过训练数据所学得的参数,例如隐层的权重矩阵——后面将会看到这些权重在Word2Vec中实际上就是试图去学习的“word vectors”。基于训练数据建模的过程,给它一个名字叫“Fake Task”,意味着建模并不是最终的目的。

上面提到的这种方法实际上会在无监督特征学习(unsupervised feature learning)中见到,最常见的就是自编码器(auto-encoder):通过在隐层将输入进行编码压缩,继而在输出层将数据解码恢复初始状态,训练完成后,会将输出层“砍掉”,仅保留隐层。

2.The Fake Task

训练模型的真正目的是获得模型基于训练数据学得的隐层权重。为了得到这些权重,首先要构建一个完整的神经网络作为的“Fake Task”,后面再返回来看通过“Fake Task”如何间接地得到这些词向量。

 

接下来来看看如何训练的神经网络。选定句子“The quick brown fox jumps over lazy dog”,设定的窗口大小为2(windowsize = 2),也就是说仅选输入词前后各两个词和输入词进行组合。下图中,蓝色代表input word,方框内代表位于窗口内的单词。

的模型将会从每对单词出现的次数中习得统计结果。例如,的神经网络可能会得到更多类似(“Soviet“,”Union“)这样的训练样本对,而对于(”Soviet“,”Sasquatch“)这样的组合却看到的很少。因此,当的模型完成训练后,给定一个单词”Soviet“作为输入,输出的结果中”Union“或者”Russia“要比”Sasquatch“被赋予更高的概率。

模型细节

如何来表示这些单词呢?

首先,都知道神经网络只能接受数值输入,不可能把一个单词字符串作为输入,因此得想个办法来表示这些单词。最常用的办法就是基于训练文档来构建自己的词汇表(vocabulary)再对单词进行one-hot编码。

假设从的训练文档中抽取出10000个唯一不重复的单词组成词汇表。对这10000个单词进行one-hot编码,得到的每个单词都是一个10000维的向量,向量每个维度的值只有0或者1,假如单词ants在词汇表中的出现位置为第3个,那么ants的向量就是一个第三维度取值为1,其他维都为0的10000维的向量()。

还是上面的例子,“The dog barked at the mailman”,那么基于这个句子,可以构建一个大小为5的词汇表(忽略大小写和标点符号):("the", "dog", "barked", "at", "mailman"),对这个词汇表的单词进行编号0-4。那么”dog“就可以被表示为一个5维向量[0, 1, 0, 0, 0]。

模型的输入如果为一个10000维的向量,那么输出也是一个10000维度(词汇表的大小)的向量,它包含了10000个概率,每一个概率代表着当前词是输入样本中output word的概率大小。

下图是神经网络的结构:

 

隐层没有使用任何激活函数,但是输出层使用了softmax。
基于成对的单词来对神经网络进行训练,训练样本是 ( input word, output word ) 这样的单词对,input word和output word都是one-hot编码的向量。最终模型的输出是一个概率分布。
说完单词的编码和训练样本的选取,来看下的隐层。如果现在想用300个特征来表示一个单词(即每个词可以被表示为300维的向量)。那么隐层的权重矩阵应该为10000行,300列(隐层有300个结点)。

Google在最新发布的基于Google news数据集训练的模型中使用的就是300个特征的词向量。词向量的维度是一个可以调节的超参数(在Python的gensim包中封装的Word2Vec接口默认的词向量大小为100, window_size为5)。

看下面的图片,左右两张图分别从不同角度代表了输入层-隐层的权重矩阵。左图中每一列代表一个10000维的词向量和隐层单个神经元连接的权重向量。从右边的图来看,每一行实际上代表了每个单词的词向量。

 

所以最终的目标就是学习这个隐层的权重矩阵。

现在回来接着通过模型的定义来训练的这个模型。

上面提到,input word和output word都会被进行one-hot编码。仔细想一下,的输入被one-hot编码以后大多数维度上都是0(实际上仅有一个位置为1),所以这个向量相当稀疏,那么会造成什么结果呢。如果将一个1 x 10000的向量和10000 x 300的矩阵相乘,它会消耗相当大的计算资源,为了高效计算,它仅仅会选择矩阵中对应的向量中维度值为1的索引行(这句话很绕),看图就明白。



来看一下上图中的矩阵运算,左边分别是1 x 5和5 x 3的矩阵,结果应该是1 x 3的矩阵,按照矩阵乘法的规则,结果的第一行第一列元素为,

 

 

同理可得其余两个元素为12,19。如果10000个维度的矩阵采用这样的计算方式是十分低效的。

为了有效地进行计算,这种稀疏状态下不会进行矩阵乘法计算,可以看到矩阵的计算的结果实际上是矩阵对应的向量中值为1的索引,上面的例子中,左边向量中取值为1的对应维度为3(下标从0开始),那么计算结果就是矩阵的第3行(下标从0开始)—— [10, 12, 19],这样模型中的隐层权重矩阵便成了一个”查找表“(lookup table),进行矩阵计算时,直接去查输入向量中取值为1的维度下对应的那些权重值。隐层的输出就是每个输入单词的“嵌入词向量”。
经过神经网络隐层的计算,ants这个词会从一个1 x 10000的向量变成1 x 300的向量,再被输入到输出层。输出层是一个softmax回归分类器,它的每个结点将会输出一个0-1之间的值(概率),这些所有输出层神经元结点的概率之和为1。

下面是一个例子,训练样本为 (input word: “ants”, output word: “car”) 的计算示意图。


直觉上的理解如果两个不同的单词有着非常相似的“上下文”(也就是窗口单词很相似,比如“Kitty climbed the tree”和“Cat climbed the tree”),那么通过的模型训练,这两个单词的嵌入向量将非常相似。

 

那么两个单词拥有相似的“上下文”到底是什么含义呢?比如对于同义词“intelligent”和“smart”,觉得这两个单词应该拥有相同的“上下文”。而例如”engine“和”transmission“这样相关的词语,可能也拥有着相似的上下文。

实际上,这种方法实际上也可以帮助你进行词干化(stemming),例如,神经网络对”ant“和”ants”两个单词会习得相似的词向量。

词干化(stemming)就是去除词缀得到词根的过程。
如何在skip-gram模型上进行高效的训练。

Word2Vec模型是一个超级大的神经网络(权重矩阵规模非常大)。

举个栗子,拥有10000个单词的词汇表,如果想嵌入300维的词向量,那么的输入-隐层权重矩阵和隐层-输出层的权重矩阵都会有 10000 x 300 = 300万个权重,在如此庞大的神经网络中进行梯度下降是相当慢的。更糟糕的是,你需要大量的训练数据来调整这些权重并且避免过拟合。百万数量级的权重矩阵和亿万数量级的训练样本意味着训练这个模型将会是个灾难(太凶残了)。

1 、Word pairs and "phases"

一些单词组合(或者词组)的含义和拆开以后具有完全不同的意义。比如“Boston Globe”是一种报刊的名字,而单独的“Boston”和“Globe”这样单个的单词却表达不出这样的含义。因此,在文章中只要出现“Boston Globe”,就应该把它作为一个单独的词来生成其词向量,而不是将其拆开。同样的例子还有“New York”,“United Stated”等。

在Google发布的模型中,它本身的训练样本中有来自Google News数据集中的1000亿的单词,但是除了单个单词以外,单词组合(或词组)又有3百万之多。

在第一部分的中,展示了训练样本是如何从原始文档中生成出来的,这里我再重复一次。的原始文本为“The quick brown fox jumps over the laze dog”,如果我使用大小为2的窗口,那么可以得到图中展示的那些训练样本。

 

但是对于“the”这种常用高频单词,这样的处理方式会存在下面两个问题:

当得到成对的单词训练样本时,("fox", "the") 这样的训练样本并不会给提供关于“fox”更多的语义信息,因为“the”在每个单词的上下文中几乎都会出现。

由于在文本中“the”这样的常用词出现概率很大,因此将会有大量的(”the“,...)这样的训练样本,而这些样本数量远远超过了学习“the”这个词向量所需的训练样本数。

2.高频词

Word2Vec通过“抽样”模式来解决这种高频词问题。它的基本思想如下:对于在训练原始文本中遇到的每一个单词,它们都有一定概率被从文本中删掉,而这个被删除的概率与单词的频率有关。

如果设置窗口大小span=10(即skip/window=5),并且从的文本中删除所有的“the”,那么会有下面的结果:

由于删除了文本中所有的“the”,那么在的训练样本中,“the”这个词永远也不会出现在的上下文窗口中。

当“the”作为input word时,的训练样本数至少会减少10个。

这句话应该这么理解,假如的文本中仅出现了一个“the”,那么当这个“the”作为input word时,设置span=10,此时会得到10个训练样本 ("the", ...) ,如果删掉这个“the”,就会减少10个训练样本。实际中的文本中不止一个“the”,因此当“the”作为input word的时候,至少会减少10个训练样本。

上面提到的这两个影响结果实际上就帮助解决了高频词带来的问题。

抽样率

3、负采样(negative sampling)

训练一个神经网络意味着要输入训练样本并且不断调整神经元的权重,从而不断提高对目标的准确预测。每当神经网络经过一个训练样本的训练,它的权重就会进行一次调整。vocabulary的大小决定了的Skip-Gram神经网络将会拥有大规模的权重矩阵,所有的这些权重需要通过数以亿计的训练样本来进行调整,这是非常消耗计算资源的,并且实际中训练起来会非常慢。负采样(negative sampling)解决了这个问题,它是用来提高训练速度并且改善所得到词向量的质量的一种方法。不同于原本每个训练样本更新所有的权重,负采样每次让一个训练样本仅仅更新一小部分的权重,这样就会降低梯度下降过程中的计算量。

当用训练样本 ( input word: "fox",output word: "quick") 来训练的神经网络时,“ fox”和“quick”都是经过one-hot编码的。如果的vocabulary大小为10000时,在输出层,期望对应“quick”单词的那个神经元结点输出1,其余9999个都应该输出0。在这里,这9999个期望输出为0的神经元结点所对应的单词称为“negative” word。

当使用负采样时,将随机选择一小部分的negative words(比如选5个negative words)来更新对应的权重。也会对的“positive” word进行权重更新(在上面的例子中,这个单词指的是”quick“)。对于小规模数据集,选择5-20个negative words会比较好,对于大规模数据集可以仅选择2-5个negative words。回忆一下的隐层-输出层拥有300 x 10000的权重矩阵。如果使用了负采样的方法仅仅去更新的positive word-“quick”的和选择的其他5个negative words的结点对应的权重,共计6个输出神经元,相当于每次只更新1800个权重。对于3百万的权重来说,相当于只计算了0.06%的权重,这样计算效率就大幅度提高。

如何选择negative words

使用“一元模型分布(unigram distribution)”来选择“negative words”。

要注意的一点是,一个单词被选作negative sample的概率跟它出现的频次有关,出现频次越高的单词越容易被选作negative words。

在word2vec的C语言实现中,你可以看到对于这个概率的实现公式。每个单词被选为“negative words”的概率计算公式与其出现的频次有关。

有了这张表以后,每次去进行负采样时,只需要在0-1亿范围内生成一个随机数,然后选择表中索引号为这个随机数的那个单词作为的negative word即可。一个单词的负采样概率越大,那么它在这个表中出现的次数就越多,它被选中的概率就越大。

学习收获与思考:

推荐系统接收的商品和用户信息是海量的,首先通用的编码是one-hot但是这个编码出来生成的是高维稀疏矩阵,要解决这个问题需要用到Embedding技术,经典的就是word2vec.对于词向量还有一些方法控制生成的向量的维度,总结一下就是将常见的单词组合(word pairs)或者词组作为单个“words”来处理。对高频次单词进行抽样来减少训练样本的个数。对优化目标采用“negative sampling”方法,这样每个训练样本的训练只会更新一小部分的模型权重,从而降低计算负担。事实证明,对常用词抽样并且对优化目标采用“negative sampling”不仅降低了训练过程中的计算负担,还提高了训练的词向量的质量。对于信息的编码决定了模型计算的复杂程度,对于后面进行特征交叉也非常重要。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值