1.BPR
1.1 做法
- 构建样本对
- 假设背后是某个常见模型:如MF
- 排序对成立情况下倒推U/V向量,计算UV乘积,得到完整评分矩阵
矩阵分解:Xˉ=WHT\bar{X}=WH^TXˉ=WHT
贝叶斯:P(θ∣>u)=P(>u∣θ)P(θ)P(>u)P(\theta|>_u)=\frac{P(>_u|\theta)P(\theta)}{P(>_u)}P(θ∣>u)=P(>u)P(>u∣θ)P(θ)
<u,i,j> :P(i>uj∣θ)P(i>_u j|\theta)P(i>uj∣θ),i在j前面,用户u,θ\thetaθ是W、H,是个模型
P(>u∣θ)P(>_u|\theta)P(>u∣θ)极大似然估计
Πu∈UP(>u∣θ)=Π(u,i,j)∈U×I×IP(i>uj∣θ)δ((u,i,j)∈D)(1−P(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)})Πu∈UP(>u∣θ)=Π(u,i,j)∈U×I×IP(i>uj∣θ)δ((u,i,j)∈D)(1−P(i>uj∣θ)δ((u,i,j)∈/D))
D:已有的评分矩阵
P(i>uj∣θ)=σ(xˉuij(θ))P(i>_u j|\theta)=\sigma(\bar{x}_{uij}(\theta))P(i>uj∣θ)=σ(xˉuij(θ))
xˉuij=xuiˉ−xujˉ\bar{x}_{uij}=\bar{x_{ui}}-\bar{x_{uj}}xˉuij=xuiˉ−xujˉ
Πu∈UP(>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}})Πu∈UP(>u∣θ)=Π(u,i,j)∈Dσ(xuiˉ−xujˉ)
->这是在预测矩阵X的对应的值
P(θ)P(\theta)P(θ)假设是高斯分布
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||^2lnP(θ∣>u)正比ln(P(>u∣θ)P(θ))=∑(u,i,j)∈Dσ(xuiˉ−xujˉ)+λ∣∣θ∣∣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_jloss = - (prediction_i - prediction_j).sigmoid().log().sum()