multimodal-recommender 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. multimodal_recommender-0.1.0/.github/workflows/ci.yml +44 -0
  2. multimodal_recommender-0.1.0/.github/workflows/release.yml +94 -0
  3. multimodal_recommender-0.1.0/.gitignore +18 -0
  4. multimodal_recommender-0.1.0/.python-version +1 -0
  5. multimodal_recommender-0.1.0/LICENSE +21 -0
  6. multimodal_recommender-0.1.0/PKG-INFO +338 -0
  7. multimodal_recommender-0.1.0/README.md +307 -0
  8. multimodal_recommender-0.1.0/benchmarks/benchmark.py +81 -0
  9. multimodal_recommender-0.1.0/benchmarks/evaluate.py +54 -0
  10. multimodal_recommender-0.1.0/benchmarks/streaming_smoke.py +94 -0
  11. multimodal_recommender-0.1.0/docs/AUDIT.md +97 -0
  12. multimodal_recommender-0.1.0/docs/installation.md +63 -0
  13. multimodal_recommender-0.1.0/docs/model-catalog.md +56 -0
  14. multimodal_recommender-0.1.0/docs/releasing.md +69 -0
  15. multimodal_recommender-0.1.0/examples/quickstart.py +19 -0
  16. multimodal_recommender-0.1.0/pyproject.toml +60 -0
  17. multimodal_recommender-0.1.0/scripts/package_smoke.py +35 -0
  18. multimodal_recommender-0.1.0/src/mmrec/__init__.py +15 -0
  19. multimodal_recommender-0.1.0/src/mmrec/__main__.py +5 -0
  20. multimodal_recommender-0.1.0/src/mmrec/cli.py +39 -0
  21. multimodal_recommender-0.1.0/src/mmrec/config.py +140 -0
  22. multimodal_recommender-0.1.0/src/mmrec/data.py +203 -0
  23. multimodal_recommender-0.1.0/src/mmrec/discovery.py +202 -0
  24. multimodal_recommender-0.1.0/src/mmrec/ensemble.py +119 -0
  25. multimodal_recommender-0.1.0/src/mmrec/evaluation.py +124 -0
  26. multimodal_recommender-0.1.0/src/mmrec/features.py +114 -0
  27. multimodal_recommender-0.1.0/src/mmrec/hpo.py +89 -0
  28. multimodal_recommender-0.1.0/src/mmrec/models/__init__.py +37 -0
  29. multimodal_recommender-0.1.0/src/mmrec/models/base.py +248 -0
  30. multimodal_recommender-0.1.0/src/mmrec/models/bpr.py +197 -0
  31. multimodal_recommender-0.1.0/src/mmrec/models/graph/__init__.py +45 -0
  32. multimodal_recommender-0.1.0/src/mmrec/models/graph/base.py +333 -0
  33. multimodal_recommender-0.1.0/src/mmrec/models/graph/bm3.py +116 -0
  34. multimodal_recommender-0.1.0/src/mmrec/models/graph/common.py +357 -0
  35. multimodal_recommender-0.1.0/src/mmrec/models/graph/dragon.py +103 -0
  36. multimodal_recommender-0.1.0/src/mmrec/models/graph/freedom.py +84 -0
  37. multimodal_recommender-0.1.0/src/mmrec/models/graph/lattice.py +101 -0
  38. multimodal_recommender-0.1.0/src/mmrec/models/graph/lgmrec.py +120 -0
  39. multimodal_recommender-0.1.0/src/mmrec/models/graph/lightgcn.py +53 -0
  40. multimodal_recommender-0.1.0/src/mmrec/models/graph/mgcn.py +114 -0
  41. multimodal_recommender-0.1.0/src/mmrec/models/graph/mmgcn.py +121 -0
  42. multimodal_recommender-0.1.0/src/mmrec/models/item_cf.py +156 -0
  43. multimodal_recommender-0.1.0/src/mmrec/models/multimodal_item_knn.py +143 -0
  44. multimodal_recommender-0.1.0/src/mmrec/models/multimodal_late_fusion.py +136 -0
  45. multimodal_recommender-0.1.0/src/mmrec/models/popularity.py +79 -0
  46. multimodal_recommender-0.1.0/src/mmrec/models/vbpr.py +253 -0
  47. multimodal_recommender-0.1.0/src/mmrec/predictor.py +1538 -0
  48. multimodal_recommender-0.1.0/src/mmrec/py.typed +0 -0
  49. multimodal_recommender-0.1.0/src/mmrec/registry.py +161 -0
  50. multimodal_recommender-0.1.0/src/mmrec/results.py +68 -0
  51. multimodal_recommender-0.1.0/src/mmrec/scalable.py +299 -0
  52. multimodal_recommender-0.1.0/src/mmrec/storage.py +204 -0
  53. multimodal_recommender-0.1.0/tests/test_automl_features.py +128 -0
  54. multimodal_recommender-0.1.0/tests/test_automl_workflow.py +277 -0
  55. multimodal_recommender-0.1.0/tests/test_discovery.py +42 -0
  56. multimodal_recommender-0.1.0/tests/test_evaluation.py +43 -0
  57. multimodal_recommender-0.1.0/tests/test_hpo.py +32 -0
  58. multimodal_recommender-0.1.0/tests/test_model_selection.py +116 -0
  59. multimodal_recommender-0.1.0/tests/test_optional_runtime.py +45 -0
  60. multimodal_recommender-0.1.0/tests/test_recommender.py +131 -0
  61. multimodal_recommender-0.1.0/tests/test_scalable.py +120 -0
  62. multimodal_recommender-0.1.0/tests/test_storage.py +86 -0
  63. multimodal_recommender-0.1.0/tests/test_torch_models.py +189 -0
  64. multimodal_recommender-0.1.0/uv.lock +903 -0
  65. multimodal_recommender-0.1.0/uv.toml +6 -0
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ core:
10
+ name: test (core, no torch) · ${{ matrix.os }} · py${{ matrix.python-version }}
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest, windows-latest]
16
+ python-version: ["3.11", "3.12"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ enable-cache: true
24
+ - name: Install core + dev dependencies
25
+ run: uv sync --group dev --frozen
26
+ - name: Lint
27
+ run: uv run ruff check src tests
28
+ - name: Test
29
+ run: uv run pytest
30
+
31
+ torch-smoke:
32
+ name: test (torch, CPU) · ubuntu
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: astral-sh/setup-uv@v5
37
+ with:
38
+ python-version: "3.12"
39
+ - name: Install core + dev dependencies
40
+ run: uv sync --group dev --frozen
41
+ - name: Install torch (CPU index)
42
+ run: uv pip install torch --index-url https://download.pytorch.org/whl/cpu
43
+ - name: Test torch model layer
44
+ run: uv run pytest tests/test_torch_models.py -q
@@ -0,0 +1,94 @@
1
+ name: Package and publish
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ release:
9
+ types: [published]
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+ - name: Check release tag matches package version
23
+ if: github.event_name == 'release'
24
+ env:
25
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
26
+ run: |
27
+ python - <<'PY'
28
+ import os, tomllib
29
+ with open("pyproject.toml", "rb") as f:
30
+ version = tomllib.load(f)["project"]["version"]
31
+ assert os.environ["RELEASE_TAG"] == f"v{version}", "Release tag must match package version"
32
+ PY
33
+ - name: Build and validate distributions
34
+ run: |
35
+ python -m pip install --upgrade build twine
36
+ python -m build
37
+ python -m twine check --strict dist/*
38
+ - name: Install from source distribution and test
39
+ run: |
40
+ python -m pip install dist/*.tar.gz pytest ruff
41
+ python -m pip check
42
+ ruff check .
43
+ python -m pytest
44
+ cd "${RUNNER_TEMP}"
45
+ python "${GITHUB_WORKSPACE}/scripts/package_smoke.py"
46
+ mmrec --help
47
+ - uses: actions/upload-artifact@v4
48
+ with:
49
+ name: distributions
50
+ path: dist/
51
+ if-no-files-found: error
52
+
53
+ install-wheel:
54
+ needs: build
55
+ strategy:
56
+ fail-fast: false
57
+ matrix:
58
+ os: [ubuntu-latest, macos-latest, windows-latest]
59
+ python: ["3.11", "3.12"]
60
+ runs-on: ${{ matrix.os }}
61
+ steps:
62
+ - uses: actions/checkout@v4
63
+ - uses: actions/setup-python@v5
64
+ with:
65
+ python-version: ${{ matrix.python }}
66
+ - uses: actions/download-artifact@v4
67
+ with:
68
+ name: distributions
69
+ path: dist/
70
+ - name: Install wheel in fresh environment
71
+ shell: bash
72
+ run: |
73
+ python -m pip install dist/*.whl
74
+ python -m pip check
75
+ cd "${RUNNER_TEMP}"
76
+ python "${GITHUB_WORKSPACE}/scripts/package_smoke.py"
77
+ mmrec --help
78
+
79
+ publish:
80
+ if: github.event_name == 'release'
81
+ needs: [build, install-wheel]
82
+ runs-on: ubuntu-latest
83
+ environment:
84
+ name: pypi
85
+ url: https://pypi.org/project/multimodal-recommender/
86
+ permissions:
87
+ id-token: write
88
+ steps:
89
+ - uses: actions/download-artifact@v4
90
+ with:
91
+ name: distributions
92
+ path: dist/
93
+ - name: Publish to PyPI using Trusted Publishing
94
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,18 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .coverage
8
+ dist/
9
+ build/
10
+ artifacts/
11
+ .mmrec/
12
+ .uv-cache/
13
+
14
+ # Local secrets and operating-system metadata
15
+ .env
16
+ .env.*
17
+ !.env.example
18
+ .DS_Store
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ziyan Zhu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,338 @@
1
+ Metadata-Version: 2.5
2
+ Name: multimodal-recommender
3
+ Version: 0.1.0
4
+ Summary: AutoML-style multimodal recommendation toolkit
5
+ Project-URL: Repository, https://github.com/LazzyXP/Multimodal-Recommender-System
6
+ Project-URL: Issues, https://github.com/LazzyXP/Multimodal-Recommender-System/issues
7
+ Project-URL: Documentation, https://github.com/LazzyXP/Multimodal-Recommender-System/blob/main/README.md
8
+ Author: Multimodal Recommender contributors
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: automl,multimodal,ranking,recommender-system,retrieval
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: numpy>=1.26
21
+ Requires-Dist: pandas>=2.1
22
+ Requires-Dist: pyarrow>=14
23
+ Provides-Extra: all
24
+ Requires-Dist: faiss-cpu>=1.8; extra == 'all'
25
+ Requires-Dist: torch>=2.2; extra == 'all'
26
+ Provides-Extra: faiss
27
+ Requires-Dist: faiss-cpu>=1.8; extra == 'faiss'
28
+ Provides-Extra: torch
29
+ Requires-Dist: torch>=2.2; extra == 'torch'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # Multimodal Recommender
33
+
34
+ 一个使用 `uv` 管理、采用 AutoML 工作流的多模态推荐框架。用户提供交互数据、用户特征、
35
+ 物品特征和少量配置,框架在统一协议下训练多个模型,并输出每个模型及融合模型的推荐结果和评测报告。
36
+
37
+ 当前版本是一个可运行的 MVP,包含:
38
+
39
+ - CSV、TSV、TXT、JSONL、Parquet 和 pandas DataFrame 输入
40
+ - 文本数据流式转换为 ZSTD Parquet,并按源文件指纹复用缓存
41
+ - 用户级 leave-one-out 时间切分
42
+ - `Popularity`、`ItemCF`、`BPRMF`、早期/晚期多模态 KNN 与 `VBPR`
43
+ - 可选 PyTorch 图模型:`LightGCN`、`MMGCN`、`LATTICE`、`BM3`、`FREEDOM`、`MGCN`、`DRAGON`、`LGMRec`(各自实现论文核心机制,见 [model catalog](docs/model-catalog.md))
44
+ - 学到的堆叠集成:非负逻辑回归 meta-learner 在 holdout 上学出融合权重,输出 `RankFusion`
45
+ - Recall、NDCG、MRR、Hit Rate、MAP、Precision、AUC 与 catalog coverage
46
+ - 多模型推荐结果、leaderboard、报告导出和模型保存加载
47
+ - 自定义模型注册接口
48
+ - 文本、类别、数值与预计算图片 embedding 的多模态物品编码
49
+ - 用户/物品多模态 Schema 校验与持久化
50
+
51
+ `Popularity` 和 `ItemCF` 只消费交互数据;`MultiModalItemKNN` 会把用户历史物品的多模态向量
52
+ 聚合成用户画像,并支持尚未产生交互但已经存在特征的冷启动物品。更重的编码器和 Two Tower
53
+ 模型会复用相同的 API 与评测协议。
54
+
55
+ `models="auto"` 默认运行多个互补候选。`medium_quality` 在具备两种以上物品模态时会自动运行
56
+ `Popularity + ItemCF + BPRMF + MultiModalItemKNN + MultiModalLateFusionKNN + VBPR`。安装
57
+ `[torch]` extra 后,自动模式还会加入 `LightGCN`、`MMGCN`、`LATTICE`、`BM3`、`FREEDOM`、
58
+ `MGCN`、`DRAGON` 和 `LGMRec`,最后生成 `RankFusion`。完整模型分层和论文来源见
59
+ [model catalog](docs/model-catalog.md);对标 AutoGluon 的验收自审见
60
+ [audit](docs/AUDIT.md)。
61
+
62
+ ## 安装
63
+
64
+ **发布状态:尚未发布到 PyPI。** 当前不能使用 `pip install multimodal-recommender`
65
+ 从 PyPI 安装;此前文档把计划中的发布方式写成已可用,这是错误的。
66
+ 目前需要 Python 3.11+ 和 Git,可直接从 GitHub 安装:
67
+
68
+ ```bash
69
+ python -m pip install "git+https://github.com/LazzyXP/Multimodal-Recommender-System.git@main"
70
+ # 可选 PyTorch 图模型
71
+ python -m pip install "multimodal-recommender[torch] @ git+https://github.com/LazzyXP/Multimodal-Recommender-System.git@main"
72
+ ```
73
+
74
+ `main` 会更新;需要复现时,将 `@main` 换成具体提交 SHA。
75
+ 也可以克隆后安装:
76
+
77
+ ```bash
78
+ git clone https://github.com/LazzyXP/Multimodal-Recommender-System.git
79
+ cd Multimodal-Recommender-System
80
+ python -m pip install .
81
+ # 开发环境(需先安装 uv)
82
+ uv sync --group dev
83
+ ```
84
+
85
+ 首次 PyPI 发布还需要维护者配置账号和 Trusted Publisher,具体步骤见
86
+ [发布说明](docs/releasing.md)。GitHub Release 或构建产物不等于已经发布到 PyPI。
87
+
88
+ The core wheel has no platform-specific native dependency beyond NumPy, pandas and
89
+ PyArrow. The optional graph layer uses the official PyTorch wheel for the current
90
+ Python/OS/accelerator combination; CPU works on macOS, Linux and Windows, while
91
+ CUDA and Apple MPS are selected automatically when available. Set `device="cpu"`,
92
+ `device="cuda"` or `device="mps"` on an explicit graph model to override selection.
93
+ For a complete platform and China-mirror installation matrix, see
94
+ [installation.md](docs/installation.md). CUDA is for NVIDIA Linux/Windows hosts;
95
+ macOS uses MPS or CPU.
96
+
97
+ ## 数据导入与转换
98
+
99
+ CSV、TSV、TXT 和 JSONL 只是导入格式。框架不会直接用这些文本文件训练,而是先通过 PyArrow
100
+ 分批读取并转换为带字典编码和统计信息的 ZSTD Parquet。默认缓存目录是 `.mmrec/cache`,缓存键
101
+ 包含源文件路径、大小和修改时间,因此未发生变化的数据不会重复转换。
102
+
103
+ 可以提前显式转换:
104
+
105
+ ```bash
106
+ mmrec convert data/interactions.csv data/interactions.parquet
107
+ mmrec convert data/interactions.txt data/interactions.parquet --delimiter $'\t'
108
+ ```
109
+
110
+ 也可以在 Python 中转换:
111
+
112
+ ```python
113
+ from mmrec import convert_to_parquet
114
+
115
+ path = convert_to_parquet("data/interactions.csv", compression="zstd")
116
+ ```
117
+
118
+ ## 大数据执行模式
119
+
120
+ `execution_mode="auto"` 会根据 Parquet 行数自动选择内存或流式执行。默认超过 200 万条交互时:
121
+
122
+ - 使用 Arrow Dataset 分批扫描,只读取用户、物品、时间和标签列
123
+ - 扫描全量数据并在 catalog 预算内统计物品频次;`Popularity` 被选中重训时使用该统计
124
+ - `ItemCF` 和 `MultiModalItemKNN` 使用按用户稳定哈希得到的有界样本
125
+ - `fit_summary()` 的 `training_scope` 明确标识 `full` 或 `sampled`
126
+ - 推荐时从原始 Parquet 精确读取当前用户历史,排除已交互物品
127
+
128
+ ```python
129
+ recommender = MultiModalRecommender(
130
+ execution_mode="auto",
131
+ max_in_memory_interactions=2_000_000,
132
+ sample_interactions=1_000_000,
133
+ scan_batch_size=262_144,
134
+ inference_batch_size=10_000,
135
+ history_partitions=256,
136
+ max_catalog_items=2_000_000,
137
+ max_sample_history_per_user=200,
138
+ )
139
+ recommender.fit("data/interactions.parquet", models="auto")
140
+ ```
141
+
142
+ 大规模离线推荐应直接分批写 Parquet,避免在内存中构造完整结果表。用户参数可以是 ID 列表、
143
+ DataFrame、CSV 或 Parquet 用户表:
144
+
145
+ ```python
146
+ recommender.recommend_to_parquet(
147
+ users="data/target_users.parquet",
148
+ path="artifacts/recommendations.parquet",
149
+ k=100,
150
+ batch_size=10_000,
151
+ )
152
+ ```
153
+
154
+ 流式模型默认引用缓存中的历史分桶索引,以避免复制大型数据。需要把模型部署到另一台机器时,
155
+ 显式把索引打进模型目录:
156
+
157
+ ```python
158
+ recommender.save("artifacts/model", include_history_index=True)
159
+ deployed = MultiModalRecommender.load("artifacts/model")
160
+ ```
161
+
162
+ 当前流式模式保证数据扫描和结果输出内存有界。ItemCF 仍是样本模型,不适合对全量高活跃用户
163
+ 构建无界共现矩阵;生产级全量召回应使用后续的分批 Two Tower 与 FAISS/HNSW 索引。
164
+ 当物品基数超过 `max_catalog_items` 时,框架保留重频候选集并在数据摘要中设置
165
+ `catalog_truncated=True`,避免 catalog 状态无限增长。
166
+
167
+ ## 自动选模与部署
168
+
169
+ 默认通过验证集主指标选择最佳单模型或 `RankFusion`,保存在 `model_best`。
170
+ `recommend()`、`predict()` 和 `recommend_to_parquet()` 默认使用最佳模型;
171
+ 需要比较所有候选时显式传入 `models="all"`(这是相对于早期 MVP 的默认行为变化)。
172
+
173
+ ```python
174
+ recommender = MultiModalRecommender(eval_metric="ndcg@20")
175
+ recommender.fit(
176
+ interactions=train,
177
+ validation_data=validation,
178
+ test_data=test,
179
+ items=items,
180
+ time_limit=3600,
181
+ refit_full="best",
182
+ )
183
+ print(recommender.model_best)
184
+ print(recommender.leaderboard()) # score_val 用于选模,is_best 标记选中的模型
185
+ recommendations = recommender.recommend(users=["u1"], k=20)
186
+ recommender.save("artifacts/best", best_only=True)
187
+ ```
188
+
189
+ 训练分两个阶段:先完成候选训练、验证与评测,再对最佳模型重训;如果融合胜出,
190
+ 重训其全部基础模型。`refit_full=False` 禁用重训,`refit_full="all"` 重训所有成功候选。
191
+ `fit_summary().models` 记录候选训练时间、`chosen_config`、`refit_status` 和重训耗时。
192
+ 重训失败或预算不足时保留原候选;融合依赖未全部重训成功时整体保留原版本。
193
+ checkpoint 分别保存候选和已完成的重训阶段,可在追加预算后复用。
194
+
195
+ 显式 `validation_data` 用于 HPO、融合权重与模型选择;显式 `test_data` 只用于评测,
196
+ 不会进入训练或全量重训。只传验证集而不传测试集时,leaderboard 是验证集结果,
197
+ 报告的 `score_split` 会明确标记。完全不传时,仍自动进行 train/val/test 三路划分。
198
+ 候选验证和测试指标均来自仅用 train 训练的版本,**不是重训后模型的实测分数**。
199
+ 未传外部测试集时,全量重训会使用全部输入交互(包含内部划出的 holdout);
200
+ 传入外部验证集时还会合并该验证集,但始终排除外部测试集。
201
+
202
+ `split="global_temporal"` 按全局时间窗口留出末尾约 20% 的事件,再从剩余部分留出
203
+ 验证窗口;相同时间戳不会跨分区。显式分区使用该选项时,要求 train、validation、test
204
+ 时间严格递增。原 `temporal` 仍表示按用户 leave-one-out,不保证全局时间隔离。
205
+ 显式分区中重复的交互事件会被拒绝;无时间戳时以用户—物品对判定重叠。
206
+ 历史物品默认从推荐结果排除,重复消费场景需自行设计与该策略一致的评测数据。
207
+ 流式模式的自动划分和候选评测仍基于用户样本,并非全流时间窗口评测。
208
+
209
+ 可用 `set_model_best("ItemCF")` 手动指定已训练模型。`save(best_only=True)` 仅保存选中的
210
+ 模型;选中融合时保留全部依赖。`predict()` 对融合模型返回基于每个用户传入候选集合
211
+ 计算的 RRF 分数,分数随候选集合变化,不是概率。
212
+
213
+ 当前融合权重和融合模型选择共享单次验证集,验证分数可能乐观;独立测试集只做最终报告。
214
+ 验证集没有可用分数时发出 warning,并回退到第一个成功候选,不会使用测试分数选模。
215
+
216
+ ## 训练预算、并行与数据划分
217
+
218
+ `fit()` 支持 AutoGluon 风格的训练控制:
219
+
220
+ ```python
221
+ recommender.fit(
222
+ interactions,
223
+ models="auto",
224
+ presets="best_quality", # 决定候选集与每个模型的训练强度
225
+ time_limit=3600, # 总 wall-clock 预算(秒)
226
+ num_workers=4, # 并行训练非 torch 模型
227
+ split="temporal", # temporal / random / cold_start / global_temporal
228
+ hyperparameter_tune=True, # TPE 式采样 + successive-halving 超参搜索
229
+ n_trials=8,
230
+ checkpoint_dir="artifacts/checkpoint", # 断点续训
231
+ )
232
+ ```
233
+
234
+ - `time_limit`:从数据准备开始计时的总 wall-clock 预算。内置可训练模型会在每个训练阶段使用
235
+ 剩余预算并在边界优雅早停;预算耗尽后剩余模型标记为 `skipped`,已成功的模型仍会生成报告。
236
+ 任意自定义模型的硬中断仍由模型工厂自行负责。
237
+ - `num_workers`:用线程池并行训练非 torch 模型;torch 图模型始终串行训练,避免在 CPU/CUDA/MPS
238
+ 上并发导致的内存超限与稳定性问题(会发出 warning)。
239
+ - `split`:`temporal`(按时间 leave-one-out,默认)、`random`(随机 leave-one-out)、
240
+ `cold_start`(随机保留一部分用户整体作为冷启动测试集)。
241
+ - `presets` 现在真正影响训练强度:`fast_training < medium_quality < best_quality` 逐级提高
242
+ `BPRMF`/`VBPR` 的 epoch、因子维度和训练样本上限。
243
+ - `hyperparameter_tune`:对 `BPRMF`/`VBPR`/Torch 图模型做「简化 TPE 采样 + successive-halving」
244
+ 搜索——先用 2 个 epoch 粗筛保留较优的一半,再对幸存配置跑满 epoch 精筛。
245
+ - `checkpoint_dir`:每个模型完成后落盘 `checkpoint.pkl`;包含交互、用户和物品表的内容指纹,
246
+ 用相同数据和参数重跑时自动跳过已完成的候选与重训阶段,只补训剩余(尤其适合配合 `time_limit` 加预算续跑)。
247
+
248
+ 评测指标扩展为 `recall@k`、`ndcg@k`、`mrr@k`、`hit_rate@k`、`map@k`、`precision@k` 与
249
+ 列表截断的 `auc@k`。`leaderboard()` 额外给出每个模型的 `train_time_s`、`num_params`、
250
+ `size_bytes`、`status` 与 `early_stopped`;`save()` 写入的 `metadata.json` 现在包含依赖版本、
251
+ 交互 schema hash 和逐模型统计,便于复现与审计。
252
+
253
+ 安装 `[faiss]` extra 后,`MultiModalItemKNN` 可设置 `use_ann=True` 使用 FAISS 近似最近邻
254
+ 检索以支撑超大物品 catalog;未安装 FAISS 时自动回退到精确向量内积。
255
+
256
+ ## 快速开始
257
+
258
+ ```python
259
+ import pandas as pd
260
+
261
+ from mmrec import MultiModalRecommender
262
+
263
+ interactions = pd.read_parquet("interactions.parquet")
264
+ users = pd.read_parquet("users.parquet")
265
+ items = pd.read_parquet("items.parquet")
266
+
267
+ recommender = MultiModalRecommender(
268
+ user_id="user_id",
269
+ item_id="item_id",
270
+ timestamp="timestamp",
271
+ label="clicked",
272
+ eval_metrics=["recall@10", "ndcg@10", "mrr@10"],
273
+ cache_dir="artifacts/cache",
274
+ )
275
+
276
+ recommender.fit(
277
+ interactions=interactions,
278
+ users=users,
279
+ items=items,
280
+ modalities={
281
+ "user": {
282
+ "categorical": ["country", "device"],
283
+ "numerical": ["age"],
284
+ },
285
+ "item": {
286
+ "categorical": ["category", "brand"],
287
+ "numerical": ["price"],
288
+ "text": ["title", "description"],
289
+ # 当前 MVP 接收预计算图片向量;原始图片编码器将在后续模型包中提供。
290
+ "image": ["image_embedding"],
291
+ },
292
+ },
293
+ # auto 会在检测到 item modalities 后加入 MultiModalItemKNN。
294
+ models="auto",
295
+ presets="medium_quality",
296
+ model_configs={"LightGCN": {"device": "auto", "layers": 2}},
297
+ )
298
+
299
+ # 默认仅返回自动选中的最佳模型;models="all" 返回各候选和融合结果。
300
+ recommendations = recommender.recommend(users=["u1", "u2"], k=20)
301
+ recommendations.to_parquet("artifacts/recommendations.parquet")
302
+
303
+ print(recommender.leaderboard())
304
+ recommender.evaluation_report.export("artifacts/report")
305
+ recommender.save("artifacts/model")
306
+ ```
307
+
308
+ 推荐结果使用统一长表:
309
+
310
+ | user_id | item_id | rank | score | model |
311
+ |---|---|---:|---:|---|
312
+ | u1 | i17 | 1 | 0.932 | ItemCF |
313
+ | u1 | i08 | 2 | 0.881 | ItemCF |
314
+ | u1 | i17 | 1 | 0.033 | RankFusion |
315
+
316
+ 不同模型的原始 `score` 不保证在同一尺度上。融合使用排名而非直接相加原始分数。
317
+
318
+ ## 数据契约
319
+
320
+ 交互表至少包含用户和物品 ID。默认还要求 `timestamp`;不具备时间信息时可在构造函数中设置
321
+ `timestamp=None`。正负反馈数据可指定 `label`,当前版本只将 `label > 0` 的记录作为隐式正反馈。
322
+
323
+ 用户表的用户 ID 必须唯一,物品表的物品 ID 必须唯一。`modalities` 中声明的每一列必须存在于
324
+ 对应特征表。
325
+
326
+ ## 开发
327
+
328
+ ```bash
329
+ uv run pytest
330
+ uv run ruff check .
331
+ uv run python examples/quickstart.py
332
+ uv run python benchmarks/streaming_smoke.py --rows 1000000
333
+ uv build
334
+ ```
335
+
336
+ 构建结果位于 `dist/`。`Package and publish` 工作流会验证源码包和 wheel 的安装、
337
+ 训练、推荐及保存加载;仅在发布版本号匹配的 GitHub Release 时尝试上传 PyPI。
338
+ 首次发布配置与安装验收步骤见 [发布说明](docs/releasing.md)。