0
点赞
收藏
分享

微信扫一扫

【搜索/推荐排序】Pairwise:BPR

覃榜言 2022-04-20 阅读 66

1.BPR

在这里插入图片描述

1.1 做法

  • 构建样本对
  • 假设背后是某个常见模型:如MF
  • 排序对成立情况下倒推U/V向量,计算UV乘积,得到完整评分矩阵

矩阵分解:Xˉ=WHT\bar{X}=WH^T
贝叶斯:P(θ>u)=P(>uθ)P(θ)P(>u)P(\theta|>_u)=\frac{P(>_u|\theta)P(\theta)}{P(>_u)}
<u,i,j> :P(i>ujθ)P(i>_u j|\theta),i在j前面,用户u,θ\theta是W、H,是个模型
P(>uθ)P(>_u|\theta)极大似然估计
ΠuUP(>uθ)=Π(u,i,j)U×I×IP(i>ujθ)δ((u,i,j)D)(1P(i>ujθ)δ((u,i,j)D))\Pi_{u\in U}P(>_u|\theta)=\Pi_{(u,i,j)\in U\times I\times I}P(i>_u j|\theta)^{\delta((u,i,j)\in D)}(1-P(i>_u j|\theta)^{\delta((u,i,j)\notin D)})
D:已有的评分矩阵
P(i>ujθ)=σ(xˉuij(θ))P(i>_u j|\theta)=\sigma(\bar{x}_{uij}(\theta))
xˉuij=xuiˉxujˉ\bar{x}_{uij}=\bar{x_{ui}}-\bar{x_{uj}}
ΠuUP(>uθ)=Π(u,i,j)Dσ(xuiˉxujˉ)\Pi_{u\in U}P(>_u|\theta)=\Pi_{(u,i,j)\in D}\sigma(\bar{x_{ui}}-\bar{x_{uj}})
->这是在预测矩阵X的对应的值

P(θ)P(\theta)假设是高斯分布
lnP(θ>u)ln(P(>uθ)P(θ))=(u,i,j)Dσ(xuiˉxujˉ)+λθ2lnP(\theta|>_u)正比ln(P(>_u|\theta)P(\theta))=\sum_{(u,i,j)\in D}\sigma(\bar{x_{ui}}-\bar{x_{uj}})+\lambda||\theta||^2

计算:求导,使用梯度上升
在这里插入图片描述

1.1.1 构建样本对

  • 构建样本对:
    • 假设我们现在有 N 个视频,每个视频有两种用户行为:被用户点击,没有被用户点击。
    • 现在设定用户给物品的评分如下:
      • 正例:被用户点击过的视频得分 +1 ,
      • 负例:从没有被用户点击过的视频中进行采样得到一部分视频,这部分视频被认为是用户不喜欢的视频,得分 -1 。

1.1.2 假设

  • 假设
    假设用户对物品的评分背后的模型是某个常见模型,比如矩阵分解模型,也就是用户对物品的评分 R = U’ * V ,其中 U 是用户向量,而 V 是物品向量。算法假定所有得分 +1 的物品和所有得分 -1 的物品,如果用评分矩阵 R 重新对物品进行打分,原本得分 +1 的物品的新得分将高于原本得分 -1 的物品的新得分。

  • 诉求/流程
    本质诉求是在**可能的满足原有的 +1 物品得分高于 -1 物品得分的排序对成立的情况下,倒推出 R 评分分解后的 U 和 V 向量。**通过计算 U和 V 的乘积,得到用户对物品的完整评分矩阵,完成整个算法过程

1.2 实现/代码

class BPR(nn.Module):
	def __init__(self, user_num, item_num, factor_num):
		super(BPR, self).__init__()
		"""
		user_num: number of users;
		item_num: number of items;
		factor_num: number of predictive factors.
		"""		
		self.embed_user = nn.Embedding(user_num, factor_num)
		self.embed_item = nn.Embedding(item_num, factor_num)

		nn.init.normal_(self.embed_user.weight, std=0.01)
		nn.init.normal_(self.embed_item.weight, std=0.01)

	def forward(self, user, item_i, item_j):
		user = self.embed_user(user)
		item_i = self.embed_item(item_i)
		item_j = self.embed_item(item_j)

		prediction_i = (user * item_i).sum(dim=-1)
		prediction_j = (user * item_j).sum(dim=-1)
		return prediction_i, prediction_j

loss = - (prediction_i - prediction_j).sigmoid().log().sum()

2. AutoInt

AutoInt
paper
挑战:

  • (1)输入特征通常是稀疏高维的;
  • (2)高阶特征组合能够带来效果,但耗费时间和人力

摘要

AutoInt,能够自动的学习输入特征的高阶特征交互。AutoInt是非常普适的,可以用于数值和类别输入特征。特别地,我们将数值化和类别化特征映射到同一个低维空间,然后,带有残差连接的multi-head self-attentive神经网络在低维空间显示地建模特征交互。由于multi-head self-attentive神经网络不同层的存在,不同阶的特征组合可以被建模。

贡献

  • 我们提出研究显示学习高阶特征交互的问题,以及寻找可解释好的模型的问题;
  • 我们提出基于self-attentive神经网络的方法,能够自动的学习高阶特征交互,有效的处理大规模高维稀疏数据;
  • 我们通过实验证明了所提出方法,不仅有显著的效果,还有很好的模型解释性;

相关工作:

低阶特征交互:FM/FFM/AFM/GBFM
高阶特征交互:

  • 隐式的方式:NFM,PNN、FNN、DeepCrossing、Wide&Deep、DeepFM-可解释性差
  • 显示:Deep&Cross、xDeepFM-很难解释哪些组合特征是有用的
  • 有效的训练方法:HOFM-参数过多

模型结构

在这里插入图片描述

优缺点

优点:

1.找到意思相近的embedding并进行组合,形成一些可解释性较强的组合特征;
2.大量的实验也验证这种方式的高阶交叉组合的优势

缺点:

1.个人感觉还是未能充分挖掘有意义的高阶交叉特征;此处的组合只是找到了关系相近的特征,关系相近的特征进行组合并不一定是合适的方式,也就是说multi-head selfattention能做到有意义的特征组合,但却不能说明关系不相近的特征的意义就不大。
————————————————
原文链接:https://blog.csdn.net/pearl8899/article/details/106747210

实验效果

在这里插入图片描述

代码

AFI(x)=linear(x)+fc(crossterm+res_fc(lz))+mlp(lz),cross_term=multi...(multiheadi(att_fc(lz)),lz=embed(x)AFI(x)=linear(x)+fc(cross_term+res\_fc(l_z))+mlp(l_z),cross\_term=multi...(multi-head_i(att\_fc(l_z)),l_z=embed(x)

class AutomaticFeatureInteractionModel(torch.nn.Module):
    """
    A pytorch implementation of AutoInt.

    Reference:
        W Song, et al. AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks, 2018.
    """

    def __init__(self, field_dims, embed_dim, atten_embed_dim, num_heads, num_layers, mlp_dims, dropouts, has_residual=True):
        super().__init__()
        self.num_fields = len(field_dims)
        self.linear = FeaturesLinear(field_dims)
        self.embedding = FeaturesEmbedding(field_dims, embed_dim)
        self.atten_embedding = torch.nn.Linear(embed_dim, atten_embed_dim)
        self.embed_output_dim = len(field_dims) * embed_dim
        self.atten_output_dim = len(field_dims) * atten_embed_dim
        self.has_residual = has_residual
        self.mlp = MultiLayerPerceptron(self.embed_output_dim, mlp_dims, dropouts[1])
        self.self_attns = torch.nn.ModuleList([
            torch.nn.MultiheadAttention(atten_embed_dim, num_heads, dropout=dropouts[0]) for _ in range(num_layers)
        ])
        self.attn_fc = torch.nn.Linear(self.atten_output_dim, 1)
        if self.has_residual:
            self.V_res_embedding = torch.nn.Linear(embed_dim, atten_embed_dim)

    def forward(self, x):
        """
        :param x: Long tensor of size ``(batch_size, num_fields)``
        """
        embed_x = self.embedding(x)
        atten_x = self.atten_embedding(embed_x)
        cross_term = atten_x.transpose(0, 1)
        for self_attn in self.self_attns:
            cross_term, _ = self_attn(cross_term, cross_term, cross_term)
        cross_term = cross_term.transpose(0, 1)
        if self.has_residual:
            V_res = self.V_res_embedding(embed_x)
            cross_term += V_res
        cross_term = F.relu(cross_term).contiguous().view(-1, self.atten_output_dim)
        x = self.linear(x) + self.attn_fc(cross_term) + self.mlp(embed_x.view(-1, self.embed_output_dim))
        return torch.sigmoid(x.squeeze(1))
举报

相关推荐

0 条评论