随着深度学习在工业届不断火热,Embedding技术便作为“基本操作”广泛应用于推荐、广告、搜索等互联网核心领域中。Embedding作为深度学习的热门研究方向,经历了从序列样本、图样本、再到异构的多特征样本的发展过程。本文主要主要参考几个篇大神写的文章,总结了现在主流的Embedding技术,简单介绍它们的基本原理,以及在推荐下的使用场景,希望对大家快速整理相关知识有所帮助。
1. Embedding背景与简介
在提到Embedding时,首先想到的是“向量化”,主要作用是将高维稀疏向量转化为稠密向量,从而方便下游模型处理。那什么是embedding呢?下面是大家对embedding的定义:
In mathematics, an embedding is one instance of some mathematical structure contained within another instance, such as a group that is a subgroup.
– Wikipedia
An embedding is a mapping from discrete objects, such as words, to vectors of real numbers.
– Tensorflow社区
Embedding是用一个低维稠密向量来表示一个对象,使得这个向量能够表达相应对象的某些特征,同时向量之间的距离能反应对象之间的相似性。
– 王喆《深度学习推荐系统》
将一个实例(instance)从复杂的空间嵌入(投射)到相对简单的空间,以便对原始实例进行理解,或者在相对简单的空间中进行后续操作。
– chrisyi《Network embedding概述》
在embedding之前,如果要表示一个词,一般用oneHot方法,只有一个维度是1,其余都是0,例如“猫”表示为
[0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
但是onehot有一个致命的缺点是:维数灾难,而且词之间是孤立的,不能体现词和词之间的关系。
而embedding可每个词表达成n维稠密、连续的实数向量,例如词表示为:
[0.792, 0.177, 0.107, 0.109, 0.542]
可以看出,Embedding可以解决“词汇鸿沟”问题,并可通过计算向量之间的距离来体现词与词的相似性。
总的来说,embedding是数据的表达方式,将稀疏的信息压缩成稠密向量,泛化能力强。
RGB(三原色,red,green,blue)任何颜色都可以用一个RGB向量来表示,其每一维度都有明确的物理含义(和一个具体的物理量相对应)。当然RGB这个例子比较特殊,和我们一般意义的embedding还不一样,因为RGB的特殊性就在,他的每一维度都是事先规定好的,所以解释性很强。而一般意义的embedding则是神经网络倒数第二层的参数权重,只具有整体意义和相对意义,不具备局部意义和绝对含义,这与embedding的产生过程有关,任何embedding一开始都是一个随机数,然后随着优化算法,不断迭代更新,最后网络收敛停止迭代的时候,网络各个层的参数就相对固化,得到隐层权重表(此时就相当于得到了我们想要的embedding),然后在通过查表可以单独查看每个元素的embedding。
2. Embedding发展史
从1986年Hinton,提出embedding的概念。到出现第一个在工业上取得不错结果的模型---word2vec,先驱们经历了勇敢的尝试,探索,在此向大神致敬。
MF矩阵分解,已经隐约看到了embedding的影子,此时embedding还是一种经验感觉的模糊存在,没有人旗帜鲜明的提出这个概念,属于是embedding诞生的前夜。
毫不夸张的说word2vec是embedding界开天辟地的大事件,从这之后一切事物都可embedding 了,在这之后的任何embedding 都能看到word2vec的影子。随着item2vec,wide and weep和youtube等各种算法的提出,embedding也迅速的用到了特征工程,画像构建召回排序等方面。而faiss作为专业的向量近邻检索工具则解决了向量召回在工程上的最后一公里的问题。
embedding作为一种新思想,他的意义包含以下几个方面
- embedding表示,把自然语言转化为一串数字,从此自然语言可以计算。
- embedding替代oneHot极大的降低了特征的维度(天下人苦oneHot久矣)
- embedding替代协同矩阵,极大地降低了计算复杂度
3. Embedding使用场景
除了单词可以进行embedding,万物皆可embedding。经过embedding后,和词向量的特性一样,越相似,其embedding距离越短。在推荐系统与受众定位系统中,对用户进行embedding是重中之重。物品推荐中,可以把物品embedding化。
常见可embedding的,如下图所示:
那如何生成embedding向量呢?
4. Embedding生成的方法
embedding的生成有如下这几类方法,下面会逐类进行介绍
4.1 矩阵分解
矩阵分解,是推荐系统方法的一种常见方法,也可以看做是一种原始的embedding。一般流程是构建用户、物品的评分矩阵,然后通过矩阵分解,其解可看做是用户向量与物品向量。
矩阵分解有多种衍生方法,例如svd 、MF模型等。矩阵分解适合于小规模的数据。
4.2 静态向量
静态向量是指一旦训练完成后,向量不再改变。例如同一个单词,在不同的上下文中,对应的词向量也不会变。一般有word2vec、glove、fasttext等方法。
4.2.1 word2vec
word2vec是embedding方法经典中的经典。在深度模型的加持下,各种embedding层出不穷。
word2vec分为skip-gram与cbow两种,用nce负采样加快计算速度。word2vec可以看成是浅层的深度网络,但是它的效果强劲,最适合用于模型的baseline。
因为embedding都基于word2vec,所以原理部分还是建议了解详细一点,下面概括下word2vec的原理,
CBOW模型是将中心词的上下文作为输入来进行预测,而Skip-gram是根据中心词来预测其上下文单词。以Skip-gram为例来介绍下细节:
网络应该能从单词组的共现次数上学习到统计信息。比如词组(“Soviet”, “Union”)出现是高于(“Soviet”, “Sasquatch”),当网络在训练完成后,输入”Soviet”得到的结果中,”Union” 或 “Russia” 的概率应高于 “Sqsquatch”。
加入词汇表长度为10000,首先使用one-hot形式表示每一个单词,经过隐层300个神经元计算,最后使用Softmax层对单词概率输出。每一对单词组,前者作为x输入,后者作为y标签。
假如我们想要学习的词向量维度为300,则需要将隐层的神经元个数设置为300(300是Google在其发布的训练模型中使用的维度,可调)。隐层的权重矩阵就是词向量,我们模型学习到的就是隐层的权重矩阵。
当使用One-hot去乘以矩阵的时候,会将某一行选择出来,即查表操作,所以权重矩阵是所有词向量组成的列表。
4.2.1.1 问题
那么问题来了:
假如使用词向量维度为300,词汇量为10000个单词,那么神经网络输入层与隐层,隐层与输出层的参数量会达到惊人的300x10000=300万
训练如词庞大的神经网络需要庞大的数据量,还要避免过拟合。因此,Google在其第二篇论文中说明了训练的trick,其创新点如下:
- 将常用词对或短语视为模型中的单个”word”。
- 对频繁的词进行子采样以减少训练样例的数量。
- 在损失函数中使用”负采样(Negative Sampling)”的技术,使每个训练样本仅更新模型权重的一小部分。
子采样和负采样技术不仅降低了计算量,还提升了词向量的效果。
4.2.1.2 子采样
在以上例子中,可以看到频繁单词’the’的两个问题:
- 对于单词对(‘fox’,’the’),其对单词’fox’的语义表达并没有什么有效帮助,’the’在每个单词的上下文中出现都非常频繁。
- 预料中有很多单词对(‘the’,…),我们应更好的学习单词’the’
Word2vec使用子采样技术来解决以上问题,根据单词的频次来削减该单词的采样率。以window size为10为例子,我们删除’the’:
- 当我们训练其余单词时候,’the’不会出现在他们的上下文中。
- 当中心词为’the’时,训练样本数量少于10。
采样率 image.png image.png P(wi)=1.0(100%保留),对应的 z(wi)<=0.0026。(表示词频大于0.0026的单词才会进行子采样) P(wi)=0.5(50%保留),对应的 z(wi)=0.00746。 P(wi)=0.033(3.3%保留),对应的 z(wi)=1.0。(不可能)
4.2.1.3 负采样:
训练一个网络是,计算训练样本然后轻微调整所有的神经元权重来提高准确率。换句话说,每一个训练样本都需要更新所有神经网络的权重。
就像如上所说,当词汇表特别大的时候,如此多的神经网络参数在如此大的数据量下,每次都要进行权重更新,负担很大。
在每个样本训练时,只修改部分的网络参数,负采样是通过这种方式来解决这个问题的。
当我们的神经网络训练到单词组(‘fox’, ‘quick’)时候,得到的输出或label都是一个one-hot向量,也就是说,在表示’quick’的位置数值为1,其它全为0。
负采样是随机选择较小数量的’负(Negative)’单词(比如5个),来做参数更新。这里的’负’表示的是网络输出向量种位置为0表示的单词。当然,’正(Positive)’(即正确单词’quick’)权重也会更新。
论文中表述,小数量级上采用5-20,大数据集使用2-5个单词。
我们的模型权重矩阵为300x10000,更新的单词为5个’负’词和一个’正’词,共计1800个参数,这是输出层全部3M参数的0.06%
负采样的选取是和频次相关的,频次越高,负采样的概率越大:
论文选择0.75作为指数是因为实验效果好。C语言实现的代码很有意思:首先用索引值填充多次填充词汇表中的每个单词,单词索引出现的次数为P(wi)∗table_size。然后负采样只需要生成一个1到100M的整数,并用于索引表中数据。由于概率高的单词在表中出现的次数多,很可能会选择这些词。
4.2.2 glove
glove通过对"词-词"共现矩阵进行分解从而得到词表示的方法。
4.2.3 FastText
FastText简单来说就是将句子中的每个词先通过一个lookup层映射成词向量,然后对词向量取平均作为真个句子的句子向量,然后直接用线性分类器进行分类。
要训练静态向量,可以先用“词”来构建“句子”,这里的“词”可以是单词、app包名、操作统计点等等。“句子”可以是真正的句子,也可以是tag列表、操作统计点列表等。
4.3 动态向量
动态向量指的是,不同上下文,其向量会发生改变。典型的方法有elmo、gpt、bert。其中bert特别出色的,在许多nlp任务中取得优秀的效果,对bert的借用、改进,衍生出各种各样的方法。但是bert参数多,模型大,在轻量级业务可能有些过重。
4.4 深度匹配
深度匹配指的是用用户向量与物品向量的距离来拟合用户对物品喜欢程度。例如用户a越喜欢物品b,则用户向量a与物品b的距离越小。
深度匹配模型框架如下图所示,一般是双塔结构,一个塔用于生成用户向量,另一个塔用于生成物品向量。最后,用户向量与物品向量的距离与两者真实距离计算损失函数。
输入的是用户特征、物品特征。双塔的内部结构可以多种多样,可以玩出花来,神经网络的经典网络都可以套进来,例如全链接层、cnn、lstm、attention、fm等。
Dssm是较早的双塔模型,一个塔是query词,一个塔是待搜索的文档,两塔共用参数,两塔实际只有一个塔。query词或文档分别输入这个塔,经过多次全连接层,得到向量。
Youtube的dnn推荐模型也是一种深度匹配模型结构,这个模型实际只是训练用户向量。取消了物品塔,物品向量应该是用其他的一些方法直接算出来,例如word2vec。
4.5 图模型
世间万物是相互关联的,各种关联关系,就形成了一张图,例如人际关系、互联网、快递物流网络等等。如下所示:
有了图,就可以用图模型来生成embedding。图模型可以分为浅层图模型和深层图模型。
浅层图模型以deepwalk为代表,通过随机游戏走 word2vec来训练向量。
深层图模型将图与深层模型结构,一般分成四大类:图卷积网络GCN、图注意力网络GAT、图自编码器GA、图生成网络GGN。
4.5.1 浅层图模型
浅层图模型以deepwalk为代表,也包括node2vec、LINE等。一般通过对节点进行随机游戏走,生成多条节点列表,每个列表相当于有多个单词的句子,再用word2vec来训练每个节点的向量。
这些方法所不同的是,如何进行随机游走。遍历方法有深度遍历优先DFS、广度遍历优先BFS两种,或对其进行优化。例如node2vec,用两个参数来平衡这两种遍历。
4.5.2 深层图模型
GCN等方法,学到的是每个节点的一个唯一确定的embedding;而GraphSAGE方法学到的node embedding,是根据node的邻居关系的变化而变化的。
GraphSAGE经过多阶的聚合(前馈网络)得到节点的embedding,再对这些embedding构建损失函数(有监督与无监督两种区别),通过损失函数优化embedding。
图注意模型GAT认为每条边的权重都不一样的,在学习embedding的时候,也要学习每条边的权重,这相当于做了attention。GAT又衍生出各种方法,例如MultiGAT、FM-GAT、Transformer-GAT、Transfer-GAT、MultiTask-GAT、Weighted-GAT等等。有兴趣的同学可以自己研究一下。
图模型比较适合于社交网络、社区网络这样的数据,可以用社交网络给推荐系统添加新信息。
4.6 Embedding生成方法优缺点比较
- 矩阵分解:只是使用用户对物品的点击数据,没有side info等数据。适合于小规模数据,在小型推荐系统可以尝试。
- 静态向量:word2vec能适应大规模的数据,训练速度快,可扩展性强。但是难以添加side info等信息,例如物品分类等特征。
- 深度匹配:优点是添加side info信息比较方便,但是用户向量与物品向量共同训练,可能导致收敛比较慢。
- 图模型:适合社会关系、社区网络等图数据。在数据量不够多的时候,也可以用图模型的随机游走来增加训练数据量。
5. Embedding在推荐中的使用
5.1 推荐基础 i2i u2i等理解
- i2i:计算item-item相似度,用于相似推荐、相关推荐、关联推荐;
- u2i:基于矩阵分解、协同过滤的结果,直接给u推荐i;
- u2u2i:基于用户的协同过滤,先找相似用户,再推荐相似用户喜欢的item;
- u2i2i:基于物品的协同过滤,先统计用户喜爱的物品,再推荐他喜欢的物品;
- u2tag2i:基于标签的泛化推荐,先统计用户偏好的tag向量,然后匹配所有的Item,这个tag一般是item的标签、分类、关键词等tag;4.7.2 item embedding一般item有文字与图片两种:4.7.2.1 text embedding
5.2 item embedding
item大致可以分为文本和图片,这里分开讲述一下处理区别。
5.2.1 text embedding
如4.3所述文本的embedding处理方式,再总结一下:
基于词向量的固定表征:word2vec、fastText、glove
基于词向量的动态表征:elmo、GPT、bert
动态词向量相较于静态词向量,更加充分利用了上下文信息,所以可以解决一词多义的问题。在工程实践上其优越性也得到了证明(BERT 在多个 NLP 任务中也表现优异)。
5.2.2 image embedding
可通过 resnet 得到图片的向量,还可以通过 image caption 得到对一张图片的中文描述;
还可以利用 facenet 识别出组图中,哪一张包含明星;
带有文字的图片可以利用 OCR 识别出图片里的文字;
对于年龄,性别有明显倾向的场景还可以利用 resnet 改变图片的风格。
对于 CNN 结构来说,不同层级的神经元学习到了不同类型的图像特征,由底向上特征形成层级结构,对人脸识别任务,训练好网络后,把每层神经元学习到的特征可视化,肉眼看一看每层学到了啥特征,我们会看到最底层的神经元学到的是线段等特征,图示的第二个隐层学到的是人脸五官的轮廓,第三层学到的是人脸的轮廓,通过三步形成了特征的层级结构,越是底层的特征越是所有不论什么领域的图像都会具备的比如边角线弧线等底层基础特征,越往上抽取出的特征越与手头任务相关。
正因为此,所以预训练好的网络参数,尤其是底层的网络参数抽取出特征跟具体任务越无关,越具备任务的通用性,所以这是为何一般用底层预训练好的参数初始化新任务网络参数的原因。而高层特征跟任务关联较大,实际可以不用使用,或者采用 Fine-tuning 用新数据集清洗掉高层无关的特征抽取器。
5.3 user embedding
- 从用户画像中筛选出一些在排序模型中重要性较大的特征来做向量化(比如通过特征重要度分析,发现标签(tag),一级分类(cat1),二级分类(cat2),主题(topic)等特征对于用户是否点击item的影响是最大的)。
- 使用了更多特征,模型采用了 DSSM(确保 user 和 item 在同一向量空间)
- 利用 bert lstm 对用户的行为序列进行了建模
5.4 基于Embedding召回
得到 item,user 向量后,就可以做各种基于向量的召回了,从 embedding 本身的使用方式上看,大致可以分成以下几种召回方式。
5.4.1 embedding 的基础用法——i2i 召回算法
单纯使用 fasttext faiss 就可以实现好几路召回算法,比如 item2vec,media2vec,tag2vec,loc2vec,title2vec。
tag2vec 就是利用词向量去做召回,比如可以用文章的标签向量表示文章的向量,如果一个文章有 4 个 tag(keywords: "蒋凡;离婚;张大奕;网红张大奕")
经验是取前 3 个 tag,做等权重向量相加,效果最好。当然了这不是唯一的做法,关于 embedding 向量的用法有很多种比如,等权重相加,加权相加,取平均,取最大等。
得到文章向量之后就是典型的 item2item 的计算过程了,利用 faiss 计算每篇文章的相似文章,比如为每一篇文章查询询出 1000 篇候选文章后,按相似度作一个截断,比如 cosin sim<0.6 舍去,对余下的文章,再利用文章的其他特征比如热度,CTR,新鲜度作一个加权,最简单的 tag2vec 召回就诞生了。
其他召回和这个套路类似,就是训练 embedding 向量的时候,略有差异。
- tag2vec 是训练中文词语的向量,而 item2vec 是训练文章 ID(aid)所对应的向量;
- media2vec 训练的是文章的作者 ID(mid)所对应的向量,loc2vec 是训练地域名称所对应的向量;
- title2vec 是用 LSTM 训练得到的文章标题向量;
- doc2vec 是用 bert 计算出的文章正文(或者摘要)的向量;
- entity2vec 是利用我们自己构建的知识图谱通过 transE 得到。
5.4.2 u2i 召回算法初步
u2i 有user2vec,word2vec 个性化,crosstag,DSSM 个性化等召回算法;
- user2vec 是拿用户的 tag 向量和文章的 tag 向量求相似度,做的召回;
- DSSM 个性化是拿用户的 DSSM 向量和文章的 DSSM 向量求相似度,做的召回;
- crosstag 相当于多个 user2vec,需要把用户的 tag 按类别进行统计,每个类取 K 个 tag,共获取 m 组 tag,然后各组分别做 user2vec,最后汇总得到用户的推荐列表。
5.4.3 u2i 召回算法进阶 分群
uese2vec 是在做召回的初级阶段,做的一些朴素的尝试,简单暴力见效快,存储压力大。每个 user 都存储一个推荐列表,在产品初期 DAU 不多时,矛盾还不明显,随着 DAU 不断提升,存储问题日益严重。
可行的策略有两条:
- 离线提前计算再存储转为线上,即时计算不存储
- 按人推荐转化为分群推荐
分群推荐:簇召回,群画像召回,LSTM 分群,DSSM 分群,bnb 分群,增量聚类,动态规则聚类
簇召回:先把所有用户的 tag 向量用聚类算法(如 minibatch-kmeans)聚成若干个簇(比如 500 个,根据肘点法确定),然后保存下簇标签,簇中心,每个用户所属的簇(一个用户可以隶属于一个簇或者多个簇)。得到用户所在的簇后,有两种做法,一种是根据实时点击日志,在簇内做实时 CF,也就是在簇内把点击过的新闻相互推。另一种做法是离线定时计算各个簇中心和候选新闻的相似度,然后和到每个簇的候选集。从实验效果来看簇内做实时 CF 效果要好一些。
群画像召回:先把用户分群,然后把同一个群里的用户画像全部抽取出来,然后融合为一个群画像,相当于把这一群人合成了一个人,然后对于群画像,再使用和单个用户画像类似的个性化召回。
LSTM 分群:和簇召回类似,不过用户的向量是通过用户最近点击文章的 m 篇文章的 bert 向量(tag2vec 向量亦可)送入 LSTM 得到用户的向量,剩下的步骤和簇召回类似,该算法有一定提升但是计算速度慢,很难铺量。
DSSM 分群:把用户画像送入 DSSM,得到一个用户 64 维的向量,把文章画像送入 DSSM,得到一个文章的 64 维的向量,剩下的步骤和簇召回类似。该算法有提升显著,已经铺量使用。
bnb 分群:借鉴 airbn(爱彼迎)公布的房源推荐算法,把文章的多个特征的 embedding(tag,topic,cat)拼接成一个向量,类似得到文章的向量。剩下的步骤和簇召回类似,该算法有一定提升,不十分显著。
5.5 Embedding排序与特征工程
在特征工程中,对于离散值,连续值,多值大致有以下几种 embedding 的方法。预先训练的 embedding 特征向量,训练样本大,参数学习更充分。end2end 是通过 embedding 层完成从高维稀疏向量到低维稠密特征向量的转换,优点是端到端,梯度统一,缺点是参数多,收敛速度慢,如果数据量少,参数很难充分训练。
6. Embedding前沿
7. Ref
- https://zhuanlan.zhihu.com/p/53194407
- https://cloud.tencent.com/developer/article/1077741 FAISS
- https://nocater.github.io/2018/12/29/word2vec详解/
- https://www.codenong.com/cs105346055/
- https://zhuanlan.zhihu.com/p/328481154
- 推荐系统 王喆