0
点赞
收藏
分享

微信扫一扫

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式


学习总结

召回中,一般的训练方式分为三种:point-wise、pair-wise、list-wise。在datawhale的RecHub中,用参数​​mode​​来指定训练方式,每一种不同的训练方式也对应不同的Loss。

对应的三种训练方式可以参考下图(3种),其中a表示user的embedding,b+表示正样本的embedding,b-表示负样本的embedding。

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据

文章目录

  • ​​学习总结​​
  • ​​零、召回模型引言​​
  • ​​0.1 Movielens数据集​​
  • ​​0.2 YiDian-News​​
  • ​​(1)全量数据​​
  • ​​1)数据列表:​​
  • ​​2)数据项说明:​​
  • ​​(2)文件夹内的采样数据​​
  • ​​(3)其他​​
  • ​​0.3 双塔模型对比​​
  • ​​一、召回相关基础​​
  • ​​1.1 召回中的三种训练方式​​
  • ​​(1)Point wise (mode = 0)​​
  • ​​(2)Pair wise (mode = 1)​​
  • ​​(3)List wise(mode = 2)​​
  • ​​1.2 温度系数​​
  • ​​(1)多分类场景下的损失函数:​​
  • ​​(2)一个场景栗子​​
  • ​​二、DSSM模型​​
  • ​​2.1 DSSM模型架构​​
  • ​​2.2 DSSM模型​​
  • ​​(1)微软​​
  • ​​三、模型代码​​
  • ​​3.1 特征预处理​​
  • ​​3.2 DSSM双塔模型代码​​
  • ​​四、双塔模型在业界的应用​​
  • ​​4.1 离线存储​​
  • ​​4.2 在线召回​​
  • ​​Reference​​

零、召回模型引言

0.1 Movielens数据集

使用ml-1m数据集,使用其中原始特征7个user特征​​'user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip',"cate_id"​​​,2个item特征​​"movie_id", "cate_id"​​,一共9个sparse特征。

  • 构造用户观看历史特征​​hist_movie_id​​​,使用​​mean​​池化该序列embedding
  • 使用随机负采样构造负样本 (sample_method=0),内含随机负采样、word2vec负采样、流行度负采样、Tencent负采样等多种方法
  • 将每个用户最后一条观看记录设置为测试集
  • 原始数据下载地址:https://grouplens.org/datasets/movielens/1m/
  • 处理完整数据csv下载地址:https://cowtransfer.com/s/5a3ab69ebd314e

Model\Metrics

Hit@100

Recall@100

Precision@100

DSSM

2.43%

2.43%

0.02%

YoutubeDNN

YoutubeSBC

FacebookDSSM

0.2 YiDian-News

一点资讯-CTR比赛数据集

(1)全量数据

  • 原始数据为NewsDataset.zip​​(​​,包括下面数据列表说明的信息。
  • ​1.1 EDA&preprocess-train_data​​​ and ​​1.2 EDA&preprocess-user_info​​ 是对原始数据train_data.txt和user_info.txt的EDA和预处理,输出user_item.pkl和user.pkl。(PS:pkl的读取速度是csv的好几倍,所以存储为pkl格式)​
  • ​2. merge&transform​​​ 读取上一步的输出,将user和user-item连接,将showPos、refresh分桶,将network转为One-Hot向量,输出all_data.pkl。**此notebook对内存要求较高,建议60G以上。**最终数据量1亿8千万,38列。​​​​
1)数据列表:
  1. 用户信息user_info.txt,“\t”分割,各列字段为:用户id、设备名称、操作系统、所在省、所在市、年龄、性别;
  2. 文章信息doc_info.txt,“\t”分割,各列字段为:文章id、标题、发文时间、图片数量、一级分类、二级分类、关键词;
  3. 训练数据train_data.txt,“\t”分割,各列字段为:用户id、文章id、展现时间、网路环境、刷新次数、展现位置、是否点击、消费时长(秒);
2)数据项说明:
  1. 网络环境:0:未知;1:离线;2:WiFi;3:2g;4:3g;5:4g;
  2. 刷新次数:用户打开APP后推荐页的刷新次数,直到退出APP则清零;
  3. 训练数据取自用户历史12天的行为日志,测试数据采样自第13天的用户展现日志;

(2)文件夹内的采样数据

文件内​​yidian_news_sampled.csv​​​是从​​train_data.txt​​中取出的前1000行数据,与user_info进行合并后得到的数据,没有数据缺失和格式不一致的情况。

文件内所提取的特征列也相比于全量数据更少,主要是以跑通模型代码为目的。

(3)其他

因为暂时没有用到doc info,所以全量数据的处理里没有做doc info的EDA和预处理。

此外,无论是否click,都有​​消费时长 = -1​​的情况,比赛官方也没有解释-1有什么意义,因为也没有用到duration,所以也没做处理。

0.3 双塔模型对比

双塔模型的正负样本选择:

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_损失函数_02

模型

学习模式

损失函数

样本构造

label

DSSM

point-wise

BCE

全局负采样,一条负样本对应label 0

1或0

YoutubeDNN

list-wise

CE

全局负采样,每条正样本对应k条负样本

0(item_list中第一个位置为正样本)

YoutubeSBC

list-wise

CE

Batch内随机负采样,每条正样本对应k条负样本,加入采样权重做纠偏处理

0(item_list中第一个位置为正样本)

FacebookDSSM

pair-wise

BPR/Hinge

全局负采样,每条正样本对应1个负样本,需扩充负样本item其他属性特征

无label

一、召回相关基础

MatchTrainer 召回模型训练与评估(对应的损失函数)

  • Point-wise样本构造:BCE Loss
  • Pair-wise样本构造:BPR Hinge Loss
  • List-wise样本构造:softmax Loss
  • 向量化召回:使用annoy

1.1 召回中的三种训练方式

召回中,一般的训练方式分为三种:point-wise、pair-wise、list-wise。在datawhale的RecHub中,用参数​​mode​​来指定训练方式,每一种不同的训练方式也对应不同的Loss。

对应的三种训练方式可以参考下图(3种),其中a表示user的embedding,b+表示正样本的embedding,b-表示负样本的embedding。

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据

(1)Point wise (mode = 0)

思想:将召回视作二分类,独立看待每个正样本、。

对于一个召回模型:

  • 输入二元组<User, Item>,
  • 输出, Item, 表示 User 对 Item 的感兴趣程度。
  • 训练目标为: 若物品为正样本, 输出应尽可能接近 1 , 负样本则输出尽可能接近 0 。 采用的 Loss 最常见的就是 BCELoss(Binary Cross Entropy Loss)。

(2)Pair wise (mode = 1)

思想:用户对正样本感兴趣的程度应该大于负样本

对于一个召回模型:

  • 输入三元组<User, ItemPositive, ItemNegative>,
  • 输出兴趣得分User, ItemPositiveUser, ItemNegative, 表示用户对正样本物品和负样 本物品的兴趣得分。
  • 训练目标为:正样本的兴趣得分应尽可能大于负样本的兴趣得分。

torch-rechub框架中采用的 Loss 为 BPRLoss(Bayes Personalized Ranking Loss)。Loss 的公式这里放 一个公式, 详细可以参考【​​贝叶斯个性化排序(BPR)算法小结​​】(链接里的内容和下面的公式有些细微的差别, 但是思想是一 样的)

sigmoid pos_score neg_score

(3)List wise(mode = 2)

思想:思想同Pair wise,但是实现上不同。

对于一个召回模型:

  • 输入元 组User, ItemPositive, ItemNeg_1,…, ItemNeg_N
  • 输出用户对 1 个正样本和
  • 训练目标为:对正样本的兴趣得分应该尽可能大于其他所有负样本的兴趣得分。

torch rechub框架中采用的 Loss 为 ​​torch.nn.CrossEntropyLoss​​, 即对输出进行 Softmax 处理后取交叉熵。

PS: 这里的 List wise 方式容易和 Ranking 中的 List wise 混淆, 虽然二者名字一样, 但 ranking 的 List wise 考虑了样本之间的顺序关系。例如 ranking 中会考虑 MAP、NDCP 等考虑顺序的指标作为评价指标, 而 Matching 中的 List wise 没有考虑顺序

1.2 温度系数

复习:torch.nn.CrossEntropyLoss = LogSoftmax + NLLLoss(可以参考官方文档)。

(1)多分类场景下的损失函数:

分布和API

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据_17


法一:把每一个类别的确定看作是一个二分类问题。利用交叉熵。

为了解决抑制问题,就不要输出每个类别的概率,且满足每个概率大于0和概率之和为1的条件。(二分类我们输出的是分布,求出一个然后用1减去即可,多分类虽然也可以这样,但是最后1减去其他所有概率的计算,还需要构建计算图有点麻烦)。
之前二分类中的交叉熵的两项中只能有一项为0.

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_二分类_18


(1)​​NLLLoss​​函数计算如下红色框:

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据_19


(2)可以直接使用​​torch.nn.CrossEntropyLoss​​(将下列红框计算纳入)。注意右侧是由类别生成独热编码向量。

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据_20


交叉熵,最后一层网络不需要激活,因为在最后的​​Torch.nn.CrossEntropyLoss​​已经包括了激活函数softmax。

(1)交叉熵手写版本

import numpy as np
y = np.array([1, 0, 0])
z = np.array([0.2, 0.1, -0.1])
y_predict = np.exp(z) / np.exp(z).sum()
loss = (- y * np.log(y_predict)).sum()
print(loss)
# 0.9729189131256584

(2)交叉熵pytorch栗子

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据_21


交叉熵损失和NLL损失的区别(读文档):

  • https://pytorch.org/doc s/stable/nn.html#crossentropyloss
  • ​​https://pytorch.org/docs/stable/nn.html#nllloss​​
  • 搞懂为啥:CrossEntropyLoss <==> LogSoftmax + NLLLoss

(2)一个场景栗子

场景:采用List wise的训练方式,1个正样本,3个负样本,cosine相似度作为训练过程中的衡量指标。

假设当前的模型完美的预测了一条训练数据, 即输出的 logits 为 ,则loss理应很非常小。但此时如果采用 ​​​CrossEntropyLoss​​​, 得到的 Loss 是:

但此时如果对 logits 除上一个温度系数 temperature , 即 logits 为 , -5), 经过 ​​​CrossEntropyLoss​​​, 得到的 Loss 是:

这样就会得到一个很小到可以忽略不计的 Loss了。对 logits 除上一个 temperature 的作用是扩大 logits 中每个元素中的上下限, 拉回 softmax 运算的敏感范围。业界一般 L2 Norm 与 temperature 搭配使用。

二、DSSM模型

​​DSSM 论文链接​​

2.1 DSSM模型架构

从推荐系统的角度看DSSM双塔模型:

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_推荐算法_27


双塔模型结构简单,一个user塔,另一个item塔,两边的DNN机构最后一层(全连接层)隐藏单元个数相同,保证user embedding和item embedding维度相同,后面相似度计算(如cos内积计算),损失函数使用二分类交叉熵损失函数。DSSM模型无法像deepFM一样使用user和item的交叉特征。

业界推荐系统常用多路召回(如CF召回、语义向量召回等,其中DSSM也是语义向量召回的其中一种),DSSM离线训练和普通的DNN训练相同。某baidu大佬有言:精排是特征的艺术,召回是样本的艺术。

  • DSSM召回的样本中:
  • 正样本就是曝光给用户并且用户点击的item;
  • 负样本:常见错误是直接使用曝光并且没被user点击的item,但是会导致SSB(sample selection bias)样本选择偏差问题——因为召回在线时时从全量候选item中召回,而不是从有曝光的item中召回

DSSM原始论文里的做法:只有正样本, 记为 , 对于用户 , 其正样本就是其点击过的 item, 负样本则是随机从 (不包含

2.2 DSSM模型

奠定基本思想:

  • 离线使用cosine优化相似度
  • 在线使用ANN向量化召回
  • 随机负采样

(1)微软

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_二分类_32

三、模型代码

这里我们使用movielen原始的数据集,可以看下对应的字段:

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_数据_33

3.1 特征预处理

这里使用两种类别的特征,分别是稀疏特征(SparseFeature)和序列特征(SequenceFeature)。

  • 对于稀疏特征,是一个离散的、有限的值(例如用户ID,一般会先进行LabelEncoding操作转化为连续整数值),模型将其输入到Embedding层,输出一个Embedding向量。
  • 对于序列特征,每一个样本是一个​​List[SparseFeature]​​(一般是观看历史、搜索历史等),对于这种特征,默认对于每一个元素取Embedding后平均,输出一个Embedding向量。此外,除了平均,还有拼接,最值等方式,可以在pooling参数中指定。
  • torch rechub框架还支持稠密特征(DenseFeature)(下面没有使用这种特征),即一个连续的特征值(例如概率),这种类型一般需归一化处理。

以上三类特征的定义在torch rechub项目中的​​torch_rechub/basic/features.py​​。

3.2 DSSM双塔模型代码

可以结合上面的DSSM结构图(两边都是DNN)

【PyTorch基础教程30】DSSM双塔模型、召回的3种训练方式_推荐算法_27

双塔模型结构简单,一个user塔,另一个item塔,两边的DNN机构最后一层(全连接层)隐藏单元个数相同,保证user embedding和item embedding维度相同,后面相似度计算(如cos内积计算),损失函数使用二分类交叉熵损失函数。DSSM模型无法像deepFM一样使用user和item的交叉特征。

import torch
from ...basic.layers import MLP, EmbeddingLayer

class DSSM(torch.nn.Module):
"""Deep Structured Semantic Model

Args:
user_features (list[Feature Class]): training by the user tower module.
item_features (list[Feature Class]): training by the item tower module.
sim_func (str): similarity function, includes `["cosine", "dot"]`, default to "cosine".
temperature (float): temperature factor for similarity score, default to 1.0.
user_params (dict): the params of the User Tower module, keys include:`{"dims":list, "activation":str, "dropout":float, "output_layer":bool`}.
item_params (dict): the params of the Item Tower module, keys include:`{"dims":list, "activation":str, "dropout":float, "output_layer":bool`}.
"""

def __init__(self, user_features, item_features, user_params, item_params, sim_func="cosine", temperature=1.0):
super().__init__()
self.user_features = user_features
self.item_features = item_features
# 计算两个塔结果embedding之间的相似度,也可以使用LSH等方法
self.sim_func = sim_func
# 温度系数
self.temperature = temperature
# 分别计算user和item的emb维度之和
self.user_dims = sum([fea.embed_dim for fea in user_features])
self.item_dims = sum([fea.embed_dim for fea in item_features])
# 构建embedding层,这里是input为特征列表,output对应特征的字典
self.embedding = EmbeddingLayer(user_features + item_features)
self.user_mlp = MLP(self.user_dims, output_layer=False, **user_params)
self.item_mlp = MLP(self.item_dims, output_layer=False, **item_params)
self.mode = None

def forward(self, x):
# user塔
user_embedding = self.user_tower(x)
# item塔
item_embedding = self.item_tower(x)
if self.mode == "user":
return user_embedding
if self.mode == "item":
return item_embedding

# 计算相似度:cosine-> similarity
if self.sim_func == "cosine":
y = torch.cosine_similarity(user_embedding, item_embedding, dim=1)
elif self.sim_func == "dot":
y = torch.mul(user_embedding, item_embedding).sum(dim=1)
else:
raise ValueError("similarity function only support %s, but got %s" % (["cosine", "dot"], self.sim_func))
y = y / self.temperature
return torch.sigmoid(y)

def user_tower(self, x):
if self.mode == "item":
return None
input_user = self.embedding(x, self.user_features, squeeze_dim=True) #[batch_size, num_features*deep_dims]
user_embedding = self.user_mlp(input_user) #[batch_size, user_params["dims"][-1]]
return user_embedding

def item_tower(self, x):
if self.mode == "user":
return None
input_item = self.embedding(x, self.item_features, squeeze_dim=True) #[batch_size, num_features*embed_dim]
item_embedding = self.item_mlp(input_item) #[batch_size, item_params["dims"][-1]]
return

四、双塔模型在业界的应用

解耦user和item侧,部署时可分离。

4.1 离线存储

  • item塔计算每个item的特征向量,可将几亿个物品向量存入向量数据库中;
  • 向量数据库需要建立索引,加速最近邻查找(如使用faiss或者LSH)
  • 虽然是有item和user塔,但是一般存的是item塔得到的item embedding,因为其变化频率一般来说没有user embedding变化快。

4.2 在线召回

  • 给定用户特征,线上计算用户向量
  • ANN查找:把用户向量作为query,返回相似度最大的k个物品
  • 避免user与每个候选item进行"计算交叉特征"、”通过DNN“等耗时操作

Reference

[1] torch-rechub项目:https://github.com/datawhalechina/torch-rechub
[2] ​​​【推荐系统】DSSM双塔模型浅析​​​ [3] ​​SysRec2016 | Deep Neural Networks for YouTube Recommendations​​ [4] torch.CROSSENTROPYLOSS的官方解释:https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html?highlight=crossentropyloss#torch.nn.CrossEntropyLoss
[5] youtubeDNN模型介绍:​​YouTubeDNN​​ [6] DSSM模型介绍:​​DSSM​​ [7] ​​推荐- Point wise、pairwise及list wise的比较​​ [8] ​​pairwise、pointwise 、 listwise算法是什么?怎么理解?主要区别是什么?​​ [9] ​​工业界推荐系统-小红书推荐场景及内部实践【矩阵补充、双塔模型】​​


举报

相关推荐

0 条评论