简介:多模态推荐工具箱MMRec完整代码包,面向推荐系统开发者和研究人员,集成10多个先进模型,包括协同过滤、SVD/PMF等矩阵分解方法,以及MTransE、CDAE、MMoE等深度模型,覆盖从数据预处理、特征编码到模型训练与评估的完整流程,可复用于电商、社交等内容推荐场景。压缩包共59个文件,含29个Python脚本(模型实现与核心工具)、18个YAML配置文件(模型与实验参数)、4个Jupyter Notebook(分步演示数据拆分、特征编码、交互矩阵生成等流程),另有Markdown说明、报告PDF等文档,整体仅446KB,目录结构清晰。已有265人浏览学习。借助Notebook实验模板、公开数据集支持和灵活的扩展接口,读者能快速跑通基线模型并对比不同算法,降低多模态推荐系统的研究门槛,适合希望高效上手并深入扩展推荐算法的工程师、学者及竞赛玩家。
1. 多模态推荐的痛点与 MMRec 的定位
做推荐系统的人多半有过这种体验:单一模态的数据已经喂不出新东西了,用户行为稀疏、物品属性单薄,调参调到头也就是在一个小点位上反复震荡。多模态信息确实能补足短板,但真正动手做的时候,问题接踵而至——图像特征怎么和文本特征对齐?交互序列应该用什么样的图结构表达?多个损失函数放在一起怎么平衡?这些问题每个都能让人卡上两个星期。MMRec 就是在这种背景下出现的一套基于 Python 和 Jupyter Notebook 的研究工具箱,它把 10 多个多模态推荐模型集中到一套统一的数据流里,从数据预处理到模型训练再到评估,全部提供了可复用模板。适合两类人:一是做推荐方向研究、需要拿基线模型跑对比实验的学生和研究员,二是工程团队里负责算法验证、想在接入线上系统之前快速评估多模态方案效果的工程师。
2. 工程结构与配置体系:从目录布局看设计思路
2.1 顶层目录与核心模块划分
拿到 MMRec 压缩包,先别急着跑训练,它的目录结构本身就是一套设计文档。顶层有src作为算法逻辑的核心,preprocessing作为数据处理的工作区,这些安排是有明确分工的。传统的推荐工具通常把数据处理和模型代码都堆在一起,MMRec 则直接把二者拆成了两个端到端的阶段,这样可以保证你更换数据集或修改特征处理方式时,不需要触碰模型训练代码。
核心的src目录下有几个关键子目录,含义如下:
| 模块 | 作用 | 关键文件 |
|---|---|---|
configs | 模型和数据集的配置入口,记录所有可调参数 | 各模型对应的 yaml 文件 |
utils | 通用工具函数,比如日志、评估指标的计算封装 | 通用计算函数 |
common | 数据集加载、批处理采样、特征对齐等基础组件 | 数据集类定义 |
models | 所有推荐模型的实现代码 | 各模型对应的模块文件 |
main.py | 训练流程入口,负责任务的分发与执行 | 主程序 |
实际使用中,你是通过main.py配合配置文件来运行整套流程的,而不是直接操作底层的模型逻辑。这样的好处是,新模型集成进来时可以复用大部分基础设施,尤其是数据加载和评估流程完全不需要重写。你会发现研究人员说的“加一个新模型”实际上是两步:在模型目录里写完网络结构,在配置里拿到数据实例,剩下的交给框架来处理。
2.2 核心配置参数与运行入口
在src/configs目录下,每个模型都有对应的配置文件。我们看一下典型配置中的关键字段。下面是一个常见的数据集配置示例(以电商类的多模态数据集为例):
# mmrec 数据集配置示例 dataset: amazon data_path: '../data/' save_model: true batch_size: 512 learning_rate: 0.001 epochs: 300 embedding_size: 64 num_neg: 4 device: 'cuda:0' seed: 2024batch_size直接影响显存占用和训练稳定性,多模态模型需要同时加载图像或文本的特征向量,这个值通常比纯协同过滤要小;embedding_size决定了融合向量的最终表达维度,在多模态场景下并不是越大越好,因为视觉和文本特征本身的维度往往不一致,统一映射时需要慎重;num_neg是负采样数量,这个值对 BPR 类损失影响很大,我一般会在 4 到 8 之间调;seed在多模态实验中远比单一模态场景重要,因为特征编码器的初始化会对融合结果产生连锁影响。
模型训练的运行入口很常规:
python src/main.py --model=MMGCN --dataset=amazon --config=configs/amazon.yaml--model参数指定要训练的模型,--config指向对应的配置文件路径。这里有个常见的误区:configs里有些参数是全局共用的,比如数据路径和日志级别;有些则是模型专用的,比如图神经网络的层数。以--model和--config为代表的参数入口把这两种情况分离了,框架内部会先加载公用参数,再用模型配置覆盖私有参数,这种处理方式在多模型对比实验时可以省掉大量重复参数传递。
3. 数据预处理流水线:从原始评分到特征编码
3.1 原始评分到交互序列
MMRec 的preprocessing目录下有一套独立的 Jupyter Notebook 流水线,专门负责把原始用户行为数据转换成模型能消费的格式。这个流水线的起点是一个名为0rating2inter.ipynb的 Notebook,它处理的是最通用的场景:从带评分的评分表转换成隐式反馈交互序列。
# 将原始评分数据转化为隐式反馈 import pandas as pd df = pd.read_csv('raw_ratings.csv') # 仅保留交互关系,丢弃具体评分值,转为隐式反馈 df['label'] = 1 # 按用户分组,保留行为发生时间以便排序 df_sorted = df.sort_values(['user_id', 'timestamp']) df_inter = df_sorted[['user_id', 'item_id', 'label']] df_inter.to_csv('interactions.csv', index=False)逻辑说明:label列全部置 1,意味着我们只关心用户是否与物品发生过交互,而不关心具体评分高低;使用timestamp排序是为了保证后续构造序列模型训练数据时的顺序一致性。参数方面,sort_values用的timestamp列必须存在,如果源数据里没有,可以改为随机打乱或者按行号处理,但这会影响序列类模型的语义。
3.2 数据划分与用户物品对齐
接下来是1splitting.ipynb。这里的核心任务是按时间顺序或随机方式把交互数据划分成训练集、验证集和测试集。MMRec 默认的策略是每个用户的最后交互作为测试集,倒数第二条作为验证集,其余作为训练集;这种划分方式在序列推荐和多模态推荐中是最常用的,因为它能真实地模拟预测未来行为的场景。划分完之后,代码会做两件关键的事:给用户和物品重新建立索引,从 0 开始的稠密编号,同时把无交互的冷启动物品从特征矩阵中剔除。
3.3 结构重索引与特征编码器
2reindex-feat.ipynb这一步比较容易被忽略,但它实际上是在构造训练过程需要的两个核心文件:item_index2entity_id.txt和item_image_feat.npy等特征文件。多模态模型在读取一个物品时,往往需要同时查询它的 ID 和视觉/文本特征,如果这两者之间存在断裂,训练时就会报出难以排查的维度错误。这个 Notebook 的思路是生成一个从数据集内部索引到原始特征的映射表,并且确保和用户交互文件一一对应:
# 构建物品 ID 到特征索引的映射 item_mapping = {} for idx, item_id in enumerate(item_ids): item_mapping[item_id] = idx # 把原始特征矩阵重新排序 feat_mat = np.zeros((len(item_ids), feat_dim)) for i, item_id in enumerate(item_ids): feat_mat[i] = raw_feat[item_mapping[item_id]] np.save('item_image_feat.npy', feat_mat)实现说明:feat_mat的存储顺序必须和交互文件中的item_id编号一致,否则训练时检索到的特征张冠李戴。这里的feat_dim取决于你使用什么预训练特征提取器,常见的是 2048 维的 ResNet 特征或 768 维的 BERT 文本特征。3feat-encoder.ipynb则负责把多模态特征做统一的维度压缩,这里通常是直接用一层全连接映射到模型 embedding 相同的空间。常见做法是让图像和文本各自经过一个独立的编码器后再拼接,因为过早合并会丢失模态专属的信息。
4. 模型训练与多模态融合策略
4.1 三种典型模型的选型参考
作为一套集成了 10 多个模型的工具箱,MMRec 的覆盖范围从传统算法到图神经网络都有。不同模型之间的收益差异非常大,不是所有模型都值得在同一数据集上跑一遍。从实践角度,我根据项目和数据集特征做了分类,见表:
| 模型类型 | 代表模型 | 适用场景 | 数据要求 |
|---|---|---|---|
| 传统协同过滤 | SVD、PMF | 稀疏数据下的快速基线 | 交互行为充分即可 |
| 多模态融合 | MMoE、MTransE | 模态特征丰富、文本图像互补性强 | 必须有完整的多模态特征 |
| 图神经网络 | LATTICE、MMGCN | 用户物品关系复杂、高阶结构重要 | 需要计算物品关系图或用户行为图 |
MMGCN 这类图模型可以从用户行为中学习每个模态的独立性,再通过图卷积逐层融合。但代价是需要预计算物品之间的相似度图,通常由dualgnn-gen-u-u-matrix.py这个脚本生成。该脚本计算用户-用户或物品-物品的关系矩阵,是后续图卷积输入的邻接表。
4.2 多模态特征对齐与融合层
多模态推荐中,最影响效果的是不同模态特征的对齐方式。MMRec 的代码里常见做法是先单独编码视觉和文本特征,再做融合。以一段融合逻辑为例(伪代码级别),核心思路来自多模态融合论文中常用的门控机制:
import torch import torch.nn as nn class MMoEFusion(nn.Module): def __init__(self, embed_dim, num_experts=3): super().__init__() self.experts = nn.ModuleList([ nn.Linear(embed_dim * 2, embed_dim) for _ in range(num_experts) ]) self.gate = nn.Linear(embed_dim * 2, num_experts) def forward(self, feat_vis, feat_txt): concat_feat = torch.cat([feat_vis, feat_txt], dim=-1) gate_weight = torch.softmax(self.gate(concat_feat), dim=-1) expert_out = torch.stack( [expert(concat_feat) for expert in self.experts], dim=1 ) fused = torch.sum(gate_weight.unsqueeze(-1) * expert_out, dim=1) return fused逻辑说明:concat_feat是视觉特征和文本特征拼接后的向量,num_experts可以理解为不同的融合专家网络;gate根据输入内容动态地给出每个专家的权重,softmax保证权重和为 1。相对于简单的相加或拼接,这个结构可以提高融合的灵活性——当一条数据的文本特征非常稀疏时,观察门控权重往往会发现视觉特征对应的专家被给予了更高的权重。参数上,embed_dim一般取 64 或 128,num_experts在 2 到 4 之间效果稳定,超过 4 之后收益不大但计算开销明显增加。
4.3 完整的实验运行流程
在src/main.py中已经封装了完整的训练、验证和测试流程。运行数据集测试的完整命令如下:
# 以 BPR 基准和多模态特征训练 LATTICE cd src python main.py --model=LATTICE --dataset=amazon \ --config=configs/lattice_amazon.yaml \ --gpu=0一个容易出错的地方在于你的数据路径。如果不修改配置中的data_path,模型会直接从默认的相对路径读取文件,而这取决于你运行命令时所在的目录。所以我的建议是把命令始终放在src目录下执行,配置文件里的data_path写成相对于项目根目录的路径,这样在整个生命周期中不会出现路径混乱。
训练过程中需要重点关注的几个日志输出项是:recall@20、ndcg@20、loss。其中loss下降到不再变化并不意味着模型已经收敛,还要观察验证集上的recall,如果出现过拟合迹象,通常的做法是减少epochs或加大num_neg。
5. 多模态特征编码器复现与实验对比技巧
5.1 更换特征编码器的必要性和操作
模型效果不好时,很多人第一时间去调整的是学习率和训练轮数,但在多模态推荐中,特征的质量通常比模型结构更容易产生决定性的影响。拿视觉特征为例,MMRec 默认提供的通常是 ResNet50 预训练特征,如果你的数据集中物品封面风格与 ImageNet 差异很大,这种特征就不一定是最优选择。
你可以在3feat-encoder.ipynb里更换特征编码逻辑,生成的矩阵只要保证维度和configs中feat_dim一致即可。具体操作逻辑是把原始图像通过一个新的特征提取网络,得到和原来相同格式的.npy文件。使用转换后的特征时,需要注意原有的配置文件中feat_path是否指向了正确的文件名,以及模型读取特征的维度是否已经重新设置。
5.2 带偏差控制的模型对比实验
在做模型对比实验时,MMRec 的配置文件之间有着微妙的相互独立关系。直接复制一份配置并修改model名称,有时会出现评估指标异常偏高,原因是在多模态实验中,不同模型的评价指标受随机的嵌入初始化影响较大。我建议多模态推荐模型的每次实验都固定seed为同一个值(比如 2024 或 42),这样至少能保证相同配置下的结果是可复现的。此外,所有对比模型的embedding_size和batch_size必须保持一致,不然你无法区分效果的差异到底来自模型结构的改进还是参数占优。
在多模态推荐论文的复现对比中,如果某个模型的指标和原论文始终不匹配,优先检查数据预处理中的2reindex-feat.ipynb这个步骤;如果这一步骤的物品和特征对齐出现问题,后续的一切操作都会在无形中受到影响。另一个快速验证办法是直接调用已保存模型进行测试。在 MMRec 的main.py中,测试过程可以用单条命令触发:
python main.py --model=MMGCN --dataset=amazon \ --config=configs/mmgcn_amazon.yaml --mode=test \ --load_model=checkpoints/mmgcn_amazon.pth--mode=test表示跳过训练阶段,直接加载--load_model指定的 checkpoint 文件执行推理。这一步可以避免重新训练一遍只是为了验证改动,对于特征编码器替换后的对比实验非常有帮助。
本文还有配套的精品资源,点击获取