万物皆可Embedding,从word2vec到item2vec、node2vec

[参考link]
[参考link]
[参考link]

-0- 中心思想

话不多说,先上中心思想:

IDs字典中有M个ID,Hidden Layer有N个神经元
M个ID的输入Layer和N个输出的Hidden Layer的Weights Matrix大小为
训练得到的这个二维矩阵就相当于一个Embedding Vector Lookup Table
每个ID对应一行 N维的向量,即该ID的N维Embedding Vector

-1- 什么是embedding?

简单来说,embedding就是用一个低维的向量表示一个ID类的物体or对象,可以是一个词,或是一个商品,或是一个电影等等。这个embedding vector的主要性质是:
* 距离相近的向量对应的物体有相近的含义
比如: Embedding(复仇者联盟)和Embedding(钢铁侠)之间的距离就会很接近,但 Embedding(复仇者联盟)和Embedding(乱世佳人)的距离就会远一些。
* 除此之外Embedding甚至还具有数学运算的关系
比如:Embedding(马德里)-Embedding(西班牙)≈ Embedding(巴黎) - Embedding(法国)

从另外一个空间表达物体,甚至揭示了物体间的潜在关系,上次体会这样神奇的操作还是在学习傅里叶变换的时候,从某种意义上来说,Embedding方法甚至具备了一些本体论的哲学意义。

-2- 为什么说embedding是深度学习的基本操作?

言归正传,Embedding能够用低维向量对物体进行编码还能保留其含义的特点非常适合深度学习
在传统机器学习模型构建过程中,我们经常使用one hot encoding对离散特征,特别是id类特征进行编码。
但是,生活中ID类的对象通常是超大数量级的,由于one hot encoding的维度等于物体的总数,比如阿里的商品one hot encoding的维度就至少是千万量级的。这样的编码方式对于商品来说是极端稀疏的。
甚至,就算是使用multi hot encoding对用户浏览历史的编码也会是一个非常稀疏的向量。

而深度学习的特点以及工程方面的原因,导致DNN不利于稀疏特征向量的处理(这里希望大家讨论一下为什么?)。

因此如果能把物体编码为一个低维稠密向量再喂给DNN,自然是一个高效的基本操作。

-3- word2vec:使embedding空前流行

对word的vector表达的研究早已有之,但让embedding方法空前流行,我们还是要归功于google的word2vec。
既然我们要训练一个对word的语义表达,那么训练样本显然是一个句子的集合。
假设其中一个长度为T的句子为, , ..., 。
这时我们假定每个词都跟其相邻的词的关系最密切,换句话说每个词都是由相邻的词决定的(CBOW模型的动机),或者每个词都决定了相邻的词(Skip-gram模型的动机)。

CBOW & Skip-gram

如上图,
* CBOW的输入是 周边的词,预测的输出是 ,
*Skip-gram则反之,输入的是,输出的是 周边的词。

经验上讲Skip-gram的效果好一点,所以本文从Skip-gram模型出发讲解模型细节。

为了产生训练模型的正样本,我们设一个滑动窗口,其长度置为2c+1(目标词前后各选c个词),从句子左边滑倒右边,每滑一次,窗口中的词就形成了我们的一个正样本。

有了训练样本之后我们就可以着手定义优化目标了:
既然每个词 都决定了相邻词 ,
基于极大似然,我们希望所有样本的条件概率 之积最大,
再通过 将极大似然里面的连乘变连加,
即:
\begin{equation} \begin{split} Model &= arg\,\max_{weight\_matrix} {\prod_{t=1}^T{\prod_{-c \le j \le +c,\ j \ne 0}{P(w_{t+j}|w_t)}}} \\ &= arg\,\max_{weight\_matrix} {\sum_{t=1}^T{\sum_{-c \le j \le +c,\ j \ne 0}{log\ P(w_{t+j}|w_t)}}}\\ \end{split} \end{equation}

接下来的问题是怎么定义
作为一个多分类问题,最简单最直接的方法当然是直接用函数,
我们又希望用向量 表示每个词,用词之间的距离or向量之间的夹角 :
考虑到:
我们用 表示词、语义的接近程度,

那么我们的条件概率的定义就可以很直观的写出:

看到上面的条件概率公式,很多同学可能会习惯性的忽略一个事实,就是:
我们用 去预测 ,但其实这二者的向量表达并不在一个向量空间内。

就像上面的条件概率公式写的一样, 和 分别是词w的输出向量表达和输入向量表达。
那什么是输入向量表达和输出向量表达呢?
我们画一个word2vec的神经网络架构图就明白了。

word2vec的神经网络架构

根据 的定义,我们可以把两个vector的乘积再套上一个softmax的形式转换成上面的神经网络架构。

需要非常注意的一点事hidden layer的激活函数,
大家要思考一下,到底是sigmoid函数还是普通的线性函数,为什么?

在训练过程中我们就可以通过梯度下降的方式求解模型参数了。
那么上文所说的
* 输入向量表达就是input layer到hidden layer的权重矩阵
* 输出向量表达就是hidden layer到output layer的权重矩阵

那么到底什么是我们通常意义上所说的词向量 呢?
其实就是我们上面所说的输入向量矩阵 中每一行对应的权重向量。
于是这个权重矩阵自然转换成了word2vec的lookup table。

Dense Weight Matrix = Embedding Vector Lookup Table

那么问题也来了:
我们能把输出矩阵 的列向量当作word的vector表达吗?
大家可以讨论一下。

当然在训练word2vec的过程中还有很多工程技巧,比如:
* 用negative sampling或Hierarchical Softmax减少词汇空间过大带来的计算量
* 对高频词汇进行降采样避免对于这些低信息词汇的无谓计算等

在具体实现的时候最好参考2013/10发表的Google的原文:「1310.4546 : Distributed Representations of Words and Phrases and their Compositionality」

-4- item2vec :从word2vec到item2vec

在word2vec诞生之后,embedding的思想迅速从NLP领域扩散到几乎所有机器学习的领域。

我们既然可以对一个句字序列中的进行embedding,那自然可以:
* 对用户购买序列中的一个商品进行embedding
* 对用户观看序列中的一个电影进行embedding

而广告、推荐、搜索等领域用户数据的稀疏性几乎必然要求在构建DNN之前对user和item进行embedding后才能进行有效的训练。
具体来讲,如果item存在于一个序列中,item2vec的方法与word2vec没有任何区别。
而如果我们摒弃 序列中item的空间关系,在原来的目标函数基础上,
* 自然是不存在时间窗口的概念了:
* 取而代之的是item set中两两之间的条件概率,即:

具体可以参考2016/03发表的item2vec的原文:「1603.04259 : Item2Vec:Neural Item Embedding for Collaborative Filtering」

但embedding的应用又远不止于此,事实上,由于我们也可以把输出矩阵的列向量当作item embedding,这大大解放了我们可以用复杂网络生成embedding的能力。

[参考link]
「Deep Neural Networks for YouTube Recommendations」

YouTube在serve其candidate generation model的时候,
* 只将最后softmax层的输出矩阵的列向量当作item embedding vector,
* 而将softmax之前一层的值当作user embedding vector。

在线上serving时
* 不用部署整个模型,
* 而是只存储user vector和item vector,再用最近邻索引进行快速搜索
这无疑是非常实用的embedding工程经验,
也证明了我们可以用复杂网络生成user和item的embedding。

YouTube :user和video embedding网络

KDD 2018 best paper :
「Real-time Personalization using Embeddings for Search Ranking at Airbnb」
也介绍了Airbnb的embedding最佳实践,主要内容涉及Airbnb如何将业务场景与embedding方法结合起来。

最后,可以思考下:
* 为什么说深度学习的特点不适合处理特征过于稀疏的样本?
* 我们能把输出矩阵中的权重向量当作词向量吗?
* 为什么在计算word similarity的时候,我们要用cosine distance,我们能够用其他距离吗?
* 在word2vec的目标函数中,两个词 w_i,w_j 的词向量 v_i,v_j 其实分别来自输入权重矩阵和输出权重矩阵,那么在实际使用时,我们需要分别存储输入矩阵和输出矩阵吗?还是直接用输入矩阵当作word2vec计算similarity就好了?
* 隐层的激活函数是什么?是sigmoid吗?

你可能感兴趣的:(万物皆可Embedding,从word2vec到item2vec、node2vec)