推荐算法实战-3-embedding

 

本文是推荐算法实战系列第三篇文章。

前面文章包括:

  1. 推荐系统简介
  2. 特征工程

上一节提到,类别特征是推荐系统的一等公民,享受VIP待遇。但是类别特征不能直接接入深度学习模型,必须先转化为数值类型的向量,才能被模型消费。

对类比特征最常见的预处理技术是OneHot和embedding。embedding不仅能实现类别特征的数值化,还能“无中生有”,提高推荐系统的泛化性(扩展性)。

1、类别特征为什么需要编码

以“国籍”特征为例,它可以取值“美国”,“中国”,“印度”等。特征的原始值是文本,无法直接输入模型,必须先进行编码。

如果用数字编码,例如,“美国”,“中国”,“印度”分别编码为1、2、3,编码后可以被模型消费。但是有个问题,1+2=3,会出现“美国”+“中国”=“印度”,这是毫无意义的。所以不能简单用数字编码。

一种处理方式是onenot编码。不会出现上述数字歧义。且相加后恰好出现two-hot(两个位置是1,其它位置是0),可以表示同时包含中国和美国,具有较好的语义。所以onehot是类别特征最简单常见的预处理方式。

onehot有一个比较严重的缺陷:高维稀疏,每个特征需要用一个N-维的向量表示,只有1个位置是1,其它都是0。如果对ID特征onehot编码,N非常大,数亿维不在话下。模型参数量急剧膨胀,很多冗余。

对此的改进是embedding。可以形式化表示如下:

\[[embedding向量]_{1 \times D} = [OneHot向量]_{1 \times N} \times [参数矩阵]_{N \times D}\]

embedding不仅能将高位稀疏的onehot向量转化为稠密向量(dense vector),还有一个巨大的附加好处:扩展性(泛化性)。

稠密向量虽然维度下降,但是每一维的值扩大到实数域,取值无限,语义空间表达能力瞬间打开。

例如,“中国”和“美国”两个特征值在onehot编码空间是两个独立的向量,没有任何联系。但是,它们在embedding编码空间具有丰富的语义。它们的向量比较相似,表示中美都是两个大国。

embedding还有一个好处,它将表征层(representation)和应用层解耦,而且embedding的学习结果保存为参数矩阵,使得“预训练+微调”和“迁移学习”非常方便。这一特性,在大语言模型时代大放异彩。

2、推荐算法的记忆性——LR评分卡模型

推荐算法面临的经典问题主要是两个:“记忆”与“扩展”。

所谓记忆性是指模型能够学习并“记住”数据集中的不同模式,当有新的样本输入时,能够凭记忆合理打分,并推荐合理结果。

这件事情虽然简单,但是价值很大。因为数据集中的模式千奇百怪,且极具隐蔽性,人力很难挖掘。模型能做好,也是大功一件。

传统推荐算法主要擅长解决记忆性问题,例如评分卡模型。

数据中的模式通过特征或特征组合刻画。每个特征或者特征组合对应评分卡中的一项,每一项有一个分数,由LR模型学习,表示对模型最终目标的贡献度。评分由LR模型的参数权重与特征值相乘而来。

这里的每一项是特征值而非特征名。例如,国籍特征下的“中国”、“美国”各有一项评分。

每条样本能够命中评分卡中的多项,得到多个评分,最终得分由所有评分累加。

LR模型(评分卡)的优点包括:

  • 强记忆性。只要特征足够细,评分卡规模足够大,它能记住历史上所有模式。
  • 弱于扩展。它不能发掘出新模式,只负责评估已有模式的重要性。
  • 模式即特征,所有的模式依赖人工输入,即特征工程。在LR时代,特征工程是一项艺术。
  • 如果评分卡规模过大,可以通过正则,剔除一些得分较低的罕见模式,即LR模型中权重特别低的项,可以降低过拟合。

举个例子,LR模型很擅长在节日期间给中国人推荐饺子,给美国人推荐火鸡,因为数据中存在大量这样的模式,LR记性很好。

如果中国人想开洋荤,吃火鸡,LR模型能推荐出来吗?大概率不会。因为<中国人,火鸡>属于小众模式,在历史样本中极少出现,正则化后可能从评分卡中直接剔除了。

3、传统机器学习时代提高推荐算法扩展性的方法——特征工程

在LR时代,可以通过特征工程提高扩展性。其基本思想是,将细粒度特征拆解成一系列粗粒度特征。

特征粒度越细,记忆性越强,越容易区分不同样本。特征粒度越粗,越容易将不同样本建立联系,挖掘共有模式,实现泛化。

“饺子”和“火鸡”是两个独立的概念,但是根据先验知识,我们知道它们有很多隐藏的相似性。例如,都是食品、都与节日相关,等等。为了让模型识别这些相似性,可以增加几维特征。原本不相干的样本在新加的特征上具有了共性,建立了联系。

这样评分卡模型中包含<节日,节日相关的食物>的打分,当推荐<中国人,火鸡>时,命中这些粗粒度特征,获得相应评分,最终有可能得到曝光机会,实现了扩展性。

4、深度学习时代提高推荐算法扩展性的核心套路——无中生有的embedding

深度学习的核心套路是“无中生有”,如果用到一个概念的特征v,或者一个函数f(例如DIN中的序列pooling函数),但是不知道如何定义它们,我们可以按照以下三步走:

  • 先将v声明为特征向量(e.g. embedding),f声明为神经网络,并随机初始化。
  • 让v和f,随主目标一同被SGD算法优化。
  • 当主目标优化完成时,我们也得到了有意义的v和f。

Embedding的思想在矩阵分解时代已经有了,当时叫“隐向量”(latent vector)。它的核心是变“精确匹配”为“模糊查找”,从而让模型“举一反三”,提高泛化性。

5、embedding实现细节

每个类别特征是一个field,每个field所有特征取值的集合预先设定定好,作为一个字典。

每个field有自己独立的Embedding Layer,底层有自己独立的embedding参数矩阵,用vocab_name(即field_name)标识。

参数矩阵W的维度是:vocab_size * embed_size。W的每一行代表一个fea_id对应的稠密向量。fea_id为该特征在字典中的索引。

W的不同行向量可以独立训练。每一行的不同维度必须一起训练。

稀疏训练:通常每个样本只会命中W的一行(one-hot)或多行(multihot),为了提高训练效率,在每个batch内,不用更新整个embedding矩阵,只更新在该batch中出现的有限几个非零特征对应的那几行。

Field拼接:多个field的embedding可以拼接在一起,展开为一个一维向量再向上层传递。可以通过EmbeddingCombineLayer实现多个EmbeddingLayer的集合。

Tensorflow和PyTorch都有成熟简洁的Embedding接口,封装了上述细节。

6、embedding的共享和独占

例如,模型要用到“近7天安装的APP”、“近7天启动的APP”、“近7天卸载的APP”三个field。三个field都与APP相关。它们可以共用一套embedding参数矩阵,也可以不共享。

二者各有优劣:

  • 共享embedding可以节省空间,有利于缓解训练数据不足;
  • 独占embedding可以根据不同场景表达不同的语义,避免相互干扰。

FM模型采用共享embedding。每个特征只有一个embedding向量,在与其它不同特征交叉时共用同一个embedding向量。

FFM模型采用独占embedding。每个特征在与不同特征交叉时使用不同的embedding向量。

阿里的CAN也采用独占embedding的思想。

7、Parameter Server

PS采用分布式训练,同时具备数据并行和模型并行能力。

  • Server:模型参数由一群PS Server节点共同存储、读写,避免“单点失效”。每个Server只处理海量参数中的一部分。
    • 更新参数:server只更新参数,不计算梯度。
    • Pull:将Worker请求的参数的最新值发送回去。
    • Push: 聚合各个Worker发送过来的梯度,利用SGD算法更新模型参数。
  • Worker:
    • 训练:利用本地数据训练,计算梯度。不更新参数。
    • Pull:从server拉取最新参数。
    • Push:向server推送梯度。

业界有多种基于PS的训练平台,例如,阿里的XDL,百度的PaddlePaddle,腾讯的Angel,快手的Persia等。


本文总访问量