1. 项目概述:基于用户对的上下文项目推荐排序模型
这个项目源于一个咖啡爱好者的真实需求——当我和妻子一起挑选咖啡豆时,发现现有的推荐系统无法很好地满足"两人共同偏好"的场景。大多数推荐引擎只针对单个用户优化,而现实生活中我们经常需要为两人或小群体做出共同决策。于是,我决定构建一个能够学习用户对偏好的排序模型(Learning to Rank, LTR),并将其应用于咖啡推荐场景。
核心挑战在于如何将两个用户的特征与项目特征有机结合,让模型理解"这对用户组合"的独特偏好模式。与传统推荐系统不同,我们不是简单地将两个用户的偏好取平均值,而是通过神经网络学习他们偏好的交互模式。举个例子,我可能偏爱果香浓郁的非洲豆,妻子则喜欢醇厚的印尼曼特宁,但当我们一起喝咖啡时,反而都倾向于选择平衡度高的哥伦比亚豆——这种复杂的联合偏好关系正是模型需要捕捉的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据准备与特征工程
2.1 数据收集与标注
我们手工创建了一个小型咖啡评分数据集:
- 品尝了16种不同产地的咖啡豆
- 每位用户独立评分(0-10分)
- 最终标签取两人评分之和(0-20分)
- 记录咖啡的产地、加工方式、风味描述等特征
注意:虽然样本量较小,但这种精心设计的小数据集对于验证模型可行性非常有效。在实际应用中,建议至少收集200组以上的评分数据。
2.2 特征处理关键技术
文本特征嵌入
使用HuggingFace的BGE模型(bge-base-en-v1.5)处理咖啡描述文本:
python复制from sentence_transformers import SentenceTransformer
model = SentenceTransformer('BAAI/bge-base-en-v1.5')
descriptions = ["fruity notes with chocolate finish", ...]
embeddings = model.encode(descriptions)
类别特征处理
用户ID和咖啡ID都转换为嵌入向量:
python复制import torch.nn as nn
user_embedding = nn.Embedding(num_users, embedding_dim)
coffee_embedding = nn.Embedding(num_coffees, embedding_dim)
数值特征标准化
对专家评分等数值特征使用RobustScaler:
python复制from sklearn.preprocessing import RobustScaler
scaler = RobustScaler()
scaled_features = scaler.fit_transform([[90], [85], ...])
3. 模型架构设计
3.1 网络结构详解
模型采用双塔结构处理用户对和咖啡特征:
code复制用户A特征 → 用户塔 →
合并层 → 全连接网络 → 预测得分
用户B特征 → 用户塔 →
咖啡特征 → 项目塔 →
关键代码实现:
python复制class RankModel(nn.Module):
def __init__(self, user_dim, item_dim):
super().__init__()
self.user_tower = nn.Sequential(
nn.Linear(user_dim, 64),
nn.ReLU(),
nn.Linear(64, 32)
)
self.item_tower = nn.Sequential(
nn.Linear(item_dim, 64),
nn.ReLU(),
nn.Linear(64, 32)
)
self.combined = nn.Sequential(
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 1)
)
def forward(self, user1, user2, item):
u1 = self.user_tower(user1)
u2 = self.user_tower(user2)
i = self.item_tower(item)
return self.combined(torch.cat([u1*u2, i], dim=1)) # 元素乘积捕捉交互
3.2 训练技巧
- 使用Pairwise Ranking Loss:
python复制criterion = nn.MarginRankingLoss(margin=1.0) - 学习率设置为0.001,batch size=4
- 添加Dropout层(0.3)防止过拟合
4. 评估与结果分析
4.1 评估指标
采用两种指标评估模型性能:
| 指标 | 公式 | 说明 |
|---|---|---|
| NDCG@k | $\frac{DCG@k}{IDCG@k}$ | 衡量前k个结果的排序质量 |
| Top-1准确率 | $\frac{\text{正确预测第一名次数}}{\text{总测试次数}}$ | 简单有效性指标 |
4.2 基准模型对比
与逻辑回归模型对比结果:
| 模型 | NDCG@3 | Top-1准确率 |
|---|---|---|
| PyTorch LTR | 0.958 | 0.875 |
| LogisticRegression | 0.950 | 0.812 |
虽然在小数据集上差异不大,但神经网络模型展现出更好的排序能力,特别是在捕捉非线性交互方面。
5. 实战应用与扩展
5.1 实际应用场景
- 情侣电影推荐:结合两人的观影历史推荐电影
- 家庭购物:根据家庭成员偏好推荐商品
- 团队活动策划:满足团队成员不同兴趣的活动推荐
5.2 生产环境优化建议
- 使用TensorFlow Ranking或LightGBM等成熟框架
- 引入更多上下文特征(时间、地点等)
- 实现在线学习机制持续更新模型
实操心得:在小样本情况下,预训练文本嵌入能显著提升模型表现。我们测试过,使用原始文本特征时NDCG下降约15%,说明高质量的特征工程至关重要。
6. 常见问题排查
6.1 问题与解决方案速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| NDCG始终为1 | 数据泄露 | 检查验证集是否混入训练数据 |
| 损失不下降 | 学习率过高 | 尝试1e-4到1e-6的学习率 |
| 预测结果相同 | 梯度消失 | 检查激活函数,添加BatchNorm |
| 过拟合严重 | 模型复杂度过高 | 增加Dropout,减少层数 |
6.2 调试技巧
- 可视化嵌入空间:使用TSNE降维观察用户/项目分布
- 检查梯度流动:
torch.autograd.gradcheck() - 监控中间层输出:确保没有异常值
这个项目最让我惊喜的是,即使使用如此小的数据集,只要特征工程得当,神经网络也能学习到有意义的排序规律。下一步我计划引入注意力机制,让模型能够自动识别哪些特征对特定用户对更重要。比如,当年轻夫妇选择咖啡时,风味描述可能比产地更重要;而老年夫妇可能更关注咖啡因含量。
