RankNet

RankNet


RankNet 论文的笔记。原文:
Learning to rank using gradient descent.

模型

  • 特征 xid
  • 模型函数: f:d

f(xi)>f(xj) 则表示模型预测 i 排在 j 前面: xixj

后验概率 Pij=P(xixj) 用如下形式:

Pij=11+eoijoijoiojoif(xi)

损失函数使用交叉熵的形式,并根据上面的定义变形为:

CijC(oij)=P¯ijlogPij(1P¯ij)log(1Pij)=P¯ijoij+log(1+eoij)

其中根据样本中两个 item 排序的在前、在后和同序关系,目标取值为:

P¯ij={1,0.5,0}

关于假设合理性的讨论

论文中已经证明上述模型假设的一致性、传递性。由于 oik=oioj+(ojok)=oij+ojk ,则容易得到:

Pij=PijPjk1+2PijPjkPijPjk

  • 自洽性
    上式满足 0<Pij<1 .

  • 传递性:
    在概率等于 p{0,0,5,1} 的时候,等号具有传递性:

    P(AB)=p,P(BC)=p,P(AC)=P

    P<0.5 时,小于号传递性:

    P(AB)=p,P(BC)=p,P(AC)<P

    0.5<P<1 时,大于号传递性:

    P(AB)=p,P(BC)=p,P(AC)>P

    以上的传递不限于两步,经过多步仍然满足。

优模型化

oi 的取值使用神经网络模型

oi=g3jw32jg2(kw21jkxk+b2j)+b3ig3i

其中 g3,g2,w32,w21,b2,b3 分别为第三、第二层激活函数,第三、第二层的权重、第二、第三层偏置。

定义一个 pair 样本的损失为 l(o2o1) (论文中用 f 表示,这里换成 l),则参数的梯度 αl=(αo2αo1)l 。注意 αo2=αf(x2)

lb3=l(g3(x2)g3(x1))Δ32Δ31lw32i=Δ32g2i(x2)Δ31g2i(x1)lb2i=Δ32w32ig2i(x2)Δ31w32ig2i(x1)Δ22,iΔ21,ilw21ij=Δ22,ix2,jΔ21,ix1,j

所有参数都可以根据上面的梯度,用梯度下降法来优化。

### 使用 PyTorch 实现 RankNet 模型 RankNet 是一种用于学习排序函数的经典深度学习模型,能够通过神经网络估计两个输入之间的相对排序。在具体应用中,比如问答系统的匹配排序问题里,输入可以是问题和答案对,目标则是学习两者间的匹配程度[^2]。 #### 导入必要的库 要构建 RankNet 的 PyTorch 版本,首先需要导入一些基本的 Python 库以及 PyTorch 自身: ```python import torch from torch import nn, optim import numpy as np ``` #### 定义 RankNet 类 接下来定义 `RankNet` 类继承自 `nn.Module`,这是所有神经网络模块的基础类。这里假设已经预处理好了数据并准备好训练集。 ```python class RankNet(nn.Module): def __init__(input_size=768): # 假设BERT embedding size or other feature vector length super(RankNet, self).__init__() hidden_layers = [ nn.Linear(input_size, 256), nn.ReLU(), nn.Dropout(p=0.5), nn.Linear(256, 128), nn.ReLU(), nn.Dropout(p=0.5), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), # Output layer with single neuron for score prediction nn.Sigmoid() # Sigmoid activation function to get probability-like output between [0, 1] ] model = nn.Sequential(*hidden_layers) init_weights(model) self.model = model @staticmethod def init_weights(m): if isinstance(m, nn.Linear): nn.init.xavier_uniform_(m.weight.data) def init_weights(model): model.apply(RankNet.init_weights) ``` 这段代码创建了一个简单的多层感知机结构作为评分器,并初始化权重以促进更好的收敛性能[^5]。 #### 计算文档对的概率差值 给定一对文档 \( U_i \) 和 \( U_j \),计算它们各自经过上述定义好的 `model()` 函数后的得分 s(i) 和 s(j),再利用这些分数来决定哪一个更有可能与查询相关联。这一步骤可以通过下面的方法完成: ```python def forward(self, doc_i, doc_j): """ Forward pass through the network. Args: doc_i (Tensor): Features of document i. doc_j (Tensor): Features of document j. Returns: Tensor: Probability that doc_i is ranked higher than doc_j. """ si = self.model(doc_i).squeeze(-1) sj = self.model(doc_j).squeeze(-1) prob_ij = torch.sigmoid(si - sj) return prob_ij ``` 此方法接收两个文档特征向量作为输入,并返回一个表示第一个文档相对于第二个文档被判定为更重要的概率值。 #### 构建损失函数 为了优化这个模型,在训练阶段会使用交叉熵损失函数衡量实际标签 y 和预测结果 p 之间的差异。由于 RankNet 关心的是成对比较而非绝对位置,因此这里的 y 只有两种可能取值:如果希望前者排位更高则设置为 1;反之,则应设定为 0。 ```python criterion = nn.BCELoss() optimizer = optim.Adam(rank_net.parameters(), lr=0.001) ``` 以上配置了 Adam 优化算法和二元交叉熵损失函数 BCE Loss 来指导模型的学习过程[^3]。 #### 开始训练循环 最后进入正式的训练环节,迭代遍历整个数据集多次直到达到满意的精度水平为止。每次更新都会调整内部参数使得整体误差逐渐减小。 ```python for epoch in range(num_epochs): running_loss = 0.0 for data in dataloader: optimizer.zero_grad() docs_i, docs_j, labels = data['doc_i'], data['doc_j'], data['label'] outputs = rank_net(docs_i, docs_j) loss = criterion(outputs, labels.float()) loss.backward() optimizer.step() running_loss += loss.item() print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss:.4f}') ``` 该片段展示了完整的训练流程,包括前向传播、反向传播及参数更新操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值