nextrec 0.3.1__tar.gz → 0.3.3__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 (117) hide show
  1. {nextrec-0.3.1 → nextrec-0.3.3}/PKG-INFO +10 -4
  2. {nextrec-0.3.1 → nextrec-0.3.3}/README.md +9 -3
  3. {nextrec-0.3.1 → nextrec-0.3.3}/README_zh.md +10 -4
  4. nextrec-0.3.3/asserts/Feature Configuration.png +0 -0
  5. nextrec-0.3.3/asserts/Model Parameters.png +0 -0
  6. nextrec-0.3.3/asserts/Training Configuration.png +0 -0
  7. nextrec-0.3.3/asserts/Training logs.png +0 -0
  8. nextrec-0.3.3/asserts/nextrec_diagram_en.png +0 -0
  9. nextrec-0.3.3/asserts/nextrec_diagram_zh.png +0 -0
  10. nextrec-0.3.3/asserts/test data.png +0 -0
  11. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/conf.py +1 -1
  12. nextrec-0.3.3/nextrec/__version__.py +1 -0
  13. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/features.py +10 -23
  14. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/layers.py +18 -61
  15. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/loggers.py +1 -1
  16. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/metrics.py +55 -33
  17. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/model.py +258 -394
  18. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/data/__init__.py +2 -2
  19. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/data/data_utils.py +80 -4
  20. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/data/dataloader.py +36 -57
  21. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/data/preprocessor.py +5 -4
  22. nextrec-0.3.3/nextrec/models/generative/__init__.py +5 -0
  23. nextrec-0.3.3/nextrec/models/generative/hstu.py +399 -0
  24. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/match/dssm.py +2 -2
  25. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/match/dssm_v2.py +2 -2
  26. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/match/mind.py +2 -2
  27. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/match/sdm.py +2 -2
  28. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/match/youtube_dnn.py +2 -2
  29. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/multi_task/esmm.py +1 -1
  30. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/multi_task/mmoe.py +1 -1
  31. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/multi_task/ple.py +1 -1
  32. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/multi_task/poso.py +1 -1
  33. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/multi_task/share_bottom.py +1 -1
  34. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/afm.py +1 -1
  35. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/autoint.py +1 -1
  36. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/dcn.py +1 -1
  37. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/deepfm.py +1 -1
  38. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/dien.py +1 -1
  39. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/din.py +1 -1
  40. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/fibinet.py +1 -1
  41. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/fm.py +1 -1
  42. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/masknet.py +2 -2
  43. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/pnn.py +1 -1
  44. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/widedeep.py +1 -1
  45. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/xdeepfm.py +1 -1
  46. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/utils/__init__.py +2 -1
  47. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/utils/common.py +21 -2
  48. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/utils/optimizer.py +7 -3
  49. {nextrec-0.3.1 → nextrec-0.3.3}/pyproject.toml +1 -1
  50. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_losses.py +1 -1
  51. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_multitask_models.py +1 -1
  52. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/example_match_dssm.py +1 -1
  53. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/example_multitask.py +1 -1
  54. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/example_ranking_din.py +9 -11
  55. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/movielen_match_dssm.py +3 -2
  56. nextrec-0.3.3/tutorials/run_all_tutorials.py +59 -0
  57. nextrec-0.3.1/nextrec/__version__.py +0 -1
  58. nextrec-0.3.1/nextrec/models/generative/hstu.py +0 -0
  59. {nextrec-0.3.1 → nextrec-0.3.3}/.github/workflows/publish.yml +0 -0
  60. {nextrec-0.3.1 → nextrec-0.3.3}/.github/workflows/tests.yml +0 -0
  61. {nextrec-0.3.1 → nextrec-0.3.3}/.gitignore +0 -0
  62. {nextrec-0.3.1 → nextrec-0.3.3}/.readthedocs.yaml +0 -0
  63. {nextrec-0.3.1 → nextrec-0.3.3}/CODE_OF_CONDUCT.md +0 -0
  64. {nextrec-0.3.1 → nextrec-0.3.3}/CONTRIBUTING.md +0 -0
  65. {nextrec-0.3.1 → nextrec-0.3.3}/LICENSE +0 -0
  66. {nextrec-0.3.1 → nextrec-0.3.3}/MANIFEST.in +0 -0
  67. {nextrec-0.3.1 → nextrec-0.3.3}/asserts/logo.png +0 -0
  68. {nextrec-0.3.1 → nextrec-0.3.3}/asserts/mmoe_tutorial.png +0 -0
  69. {nextrec-0.3.1 → nextrec-0.3.3}/dataset/ctcvr_task.csv +0 -0
  70. {nextrec-0.3.1 → nextrec-0.3.3}/dataset/match_task.csv +0 -0
  71. {nextrec-0.3.1 → nextrec-0.3.3}/dataset/movielens_100k.csv +0 -0
  72. {nextrec-0.3.1 → nextrec-0.3.3}/dataset/multitask_task.csv +0 -0
  73. {nextrec-0.3.1 → nextrec-0.3.3}/dataset/ranking_task.csv +0 -0
  74. {nextrec-0.3.1 → nextrec-0.3.3}/docs/en/Getting started guide.md +0 -0
  75. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/Makefile +0 -0
  76. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/index.md +0 -0
  77. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/make.bat +0 -0
  78. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/modules.rst +0 -0
  79. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/nextrec.basic.rst +0 -0
  80. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/nextrec.data.rst +0 -0
  81. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/nextrec.loss.rst +0 -0
  82. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/nextrec.rst +0 -0
  83. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/nextrec.utils.rst +0 -0
  84. {nextrec-0.3.1 → nextrec-0.3.3}/docs/rtd/requirements.txt +0 -0
  85. {nextrec-0.3.1 → nextrec-0.3.3}/docs/zh//345/277/253/351/200/237/344/270/212/346/211/213.md" +0 -0
  86. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/__init__.py +0 -0
  87. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/__init__.py +0 -0
  88. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/activation.py +0 -0
  89. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/callback.py +0 -0
  90. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/basic/session.py +0 -0
  91. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/loss/__init__.py +0 -0
  92. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/loss/listwise.py +0 -0
  93. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/loss/loss_utils.py +0 -0
  94. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/loss/pairwise.py +0 -0
  95. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/loss/pointwise.py +0 -0
  96. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/generative/tiger.py +0 -0
  97. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/match/__init__.py +0 -0
  98. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/__init__.py +0 -0
  99. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/models/ranking/dcn_v2.py +0 -0
  100. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/utils/embedding.py +0 -0
  101. {nextrec-0.3.1 → nextrec-0.3.3}/nextrec/utils/initializer.py +0 -0
  102. {nextrec-0.3.1 → nextrec-0.3.3}/pytest.ini +0 -0
  103. {nextrec-0.3.1 → nextrec-0.3.3}/requirements.txt +0 -0
  104. {nextrec-0.3.1 → nextrec-0.3.3}/test/__init__.py +0 -0
  105. {nextrec-0.3.1 → nextrec-0.3.3}/test/conftest.py +0 -0
  106. {nextrec-0.3.1 → nextrec-0.3.3}/test/run_tests.py +0 -0
  107. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_layers.py +0 -0
  108. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_match_models.py +0 -0
  109. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_preprocessor.py +0 -0
  110. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_ranking_models.py +0 -0
  111. {nextrec-0.3.1 → nextrec-0.3.3}/test/test_utils.py +0 -0
  112. {nextrec-0.3.1 → nextrec-0.3.3}/test_requirements.txt +0 -0
  113. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/movielen_ranking_deepfm.py +0 -0
  114. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/notebooks/en/Hands on dataprocessor.ipynb +0 -0
  115. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/notebooks/en/Hands on nextrec.ipynb +0 -0
  116. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/notebooks/zh/Hands on dataprocessor.ipynb +0 -0
  117. {nextrec-0.3.1 → nextrec-0.3.3}/tutorials/notebooks/zh/Hands on nextrec.ipynb +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextrec
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: A comprehensive recommendation library with match, ranking, and multi-task learning models
5
5
  Project-URL: Homepage, https://github.com/zerolovesea/NextRec
6
6
  Project-URL: Repository, https://github.com/zerolovesea/NextRec
@@ -63,7 +63,7 @@ Description-Content-Type: text/markdown
63
63
  ![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)
64
64
  ![PyTorch](https://img.shields.io/badge/PyTorch-1.10+-ee4c2c.svg)
65
65
  ![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)
66
- ![Version](https://img.shields.io/badge/Version-0.3.1-orange.svg)
66
+ ![Version](https://img.shields.io/badge/Version-0.3.3-orange.svg)
67
67
 
68
68
  English | [中文文档](README_zh.md)
69
69
 
@@ -75,13 +75,19 @@ English | [中文文档](README_zh.md)
75
75
 
76
76
  NextRec is a modern recommendation framework built on PyTorch, delivering a unified experience for modeling, training, and evaluation. It follows a modular design with rich model implementations, data-processing utilities, and engineering-ready training components. NextRec focuses on large-scale industrial recall scenarios on Spark clusters, training on massive offline parquet features.
77
77
 
78
- ### Why NextRec
78
+ ## Why NextRec
79
79
 
80
80
  - **Unified feature engineering & data pipeline**: Dense/Sparse/Sequence feature definitions, persistent DataProcessor, and batch-optimized RecDataLoader, matching offline feature training/inference in industrial big-data settings.
81
81
  - **Multi-scenario coverage**: Ranking (CTR/CVR), retrieval, multi-task learning, and more marketing/rec models, with a continuously expanding model zoo.
82
82
  - **Developer-friendly experience**: Stream processing/training/inference for csv/parquet/pathlike data, plus GPU/MPS acceleration and visualization support.
83
83
  - **Efficient training & evaluation**: Standardized engine with optimizers, LR schedulers, early stopping, checkpoints, and detailed logging out of the box.
84
84
 
85
+ ## Architecture
86
+
87
+ NextRec adopts a modular and low-coupling engineering design, enabling full-pipeline reusability and scalability across data processing → model construction → training & evaluation → inference & deployment. Its core components include: a Feature-Spec-driven Embedding architecture, the BaseModel abstraction, a set of independent reusable Layers, a unified DataLoader for both training and inference, and a ready-to-use Model Zoo.
88
+
89
+ ![NextRec Architecture](asserts/nextrec_diagram_en.png)
90
+
85
91
  > The project borrows ideas from excellent open-source rec libraries. Early layers referenced [torch-rechub](https://github.com/datawhalechina/torch-rechub) but have been replaced with in-house implementations. torch-rechub remains mature in architecture and models; the author contributed a bit there—feel free to check it out.
86
92
 
87
93
  ---
@@ -104,7 +110,7 @@ To dive deeper, Jupyter notebooks are available:
104
110
  - [Hands on the NextRec framework](/tutorials/notebooks/en/Hands%20on%20nextrec.ipynb)
105
111
  - [Using the data processor for preprocessing](/tutorials/notebooks/en/Hands%20on%20dataprocessor.ipynb)
106
112
 
107
- > Current version [0.3.1]: the matching module is not fully polished yet and may have compatibility issues or unexpected errors. Please raise an issue if you run into problems.
113
+ > Current version [0.3.3]: the matching module is not fully polished yet and may have compatibility issues or unexpected errors. Please raise an issue if you run into problems.
108
114
 
109
115
  ## 5-Minute Quick Start
110
116
 
@@ -7,7 +7,7 @@
7
7
  ![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)
8
8
  ![PyTorch](https://img.shields.io/badge/PyTorch-1.10+-ee4c2c.svg)
9
9
  ![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)
10
- ![Version](https://img.shields.io/badge/Version-0.3.1-orange.svg)
10
+ ![Version](https://img.shields.io/badge/Version-0.3.3-orange.svg)
11
11
 
12
12
  English | [中文文档](README_zh.md)
13
13
 
@@ -19,13 +19,19 @@ English | [中文文档](README_zh.md)
19
19
 
20
20
  NextRec is a modern recommendation framework built on PyTorch, delivering a unified experience for modeling, training, and evaluation. It follows a modular design with rich model implementations, data-processing utilities, and engineering-ready training components. NextRec focuses on large-scale industrial recall scenarios on Spark clusters, training on massive offline parquet features.
21
21
 
22
- ### Why NextRec
22
+ ## Why NextRec
23
23
 
24
24
  - **Unified feature engineering & data pipeline**: Dense/Sparse/Sequence feature definitions, persistent DataProcessor, and batch-optimized RecDataLoader, matching offline feature training/inference in industrial big-data settings.
25
25
  - **Multi-scenario coverage**: Ranking (CTR/CVR), retrieval, multi-task learning, and more marketing/rec models, with a continuously expanding model zoo.
26
26
  - **Developer-friendly experience**: Stream processing/training/inference for csv/parquet/pathlike data, plus GPU/MPS acceleration and visualization support.
27
27
  - **Efficient training & evaluation**: Standardized engine with optimizers, LR schedulers, early stopping, checkpoints, and detailed logging out of the box.
28
28
 
29
+ ## Architecture
30
+
31
+ NextRec adopts a modular and low-coupling engineering design, enabling full-pipeline reusability and scalability across data processing → model construction → training & evaluation → inference & deployment. Its core components include: a Feature-Spec-driven Embedding architecture, the BaseModel abstraction, a set of independent reusable Layers, a unified DataLoader for both training and inference, and a ready-to-use Model Zoo.
32
+
33
+ ![NextRec Architecture](asserts/nextrec_diagram_en.png)
34
+
29
35
  > The project borrows ideas from excellent open-source rec libraries. Early layers referenced [torch-rechub](https://github.com/datawhalechina/torch-rechub) but have been replaced with in-house implementations. torch-rechub remains mature in architecture and models; the author contributed a bit there—feel free to check it out.
30
36
 
31
37
  ---
@@ -48,7 +54,7 @@ To dive deeper, Jupyter notebooks are available:
48
54
  - [Hands on the NextRec framework](/tutorials/notebooks/en/Hands%20on%20nextrec.ipynb)
49
55
  - [Using the data processor for preprocessing](/tutorials/notebooks/en/Hands%20on%20dataprocessor.ipynb)
50
56
 
51
- > Current version [0.3.1]: the matching module is not fully polished yet and may have compatibility issues or unexpected errors. Please raise an issue if you run into problems.
57
+ > Current version [0.3.3]: the matching module is not fully polished yet and may have compatibility issues or unexpected errors. Please raise an issue if you run into problems.
52
58
 
53
59
  ## 5-Minute Quick Start
54
60
 
@@ -7,7 +7,7 @@
7
7
  ![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)
8
8
  ![PyTorch](https://img.shields.io/badge/PyTorch-1.10+-ee4c2c.svg)
9
9
  ![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)
10
- ![Version](https://img.shields.io/badge/Version-0.3.1-orange.svg)
10
+ ![Version](https://img.shields.io/badge/Version-0.3.3-orange.svg)
11
11
 
12
12
  [English Version](README.md) | 中文文档
13
13
 
@@ -19,14 +19,20 @@
19
19
 
20
20
  NextRec 是一个基于 PyTorch 构建的现代推荐系统框架,为研究人员与工程团队提供统一的建模、训练与评估体验。框架采用模块化设计,内置丰富的模型实现、数据处理工具和工程化训练组件,可快速覆盖多种推荐场景,主要面向Spark集群下,基于大数据量parquet离线特征训练的工业推荐召回算法场景。
21
21
 
22
- ### Why NextRec
22
+ ## Why NextRec
23
23
 
24
24
  - **统一的特征工程与数据流水线**:NextRec框架提供了 Dense/Sparse/Sequence 特征定义、可持久化的 DataProcessor、批处理优化的 RecDataLoader,符合工业大数据场景下,基于离线特征的模型训练推理流程。
25
25
  - **多场景推荐能力**:同时覆盖排序(CTR/CVR)、召回、多任务学习等推荐/营销模型,并且持续扩充模型库中。
26
26
  - **友好的工程体验**:NextRec框架支持各种格式数据(csv/parquet/pathlike)的流式处理/训练/推理,并支持 GPU/MPS 加速与可视化监控。
27
27
  - **高效训练与评估**:NextRec框架的标准化训练引擎内置多种优化器、学习率调度、早停、模型检查点与详细的日志管理,开箱即用。
28
28
 
29
- > 项目借鉴了一些优秀的开源推荐算法库,其中最初版的layer层借鉴了DataWhaleChina社区的[torch-rechub](https://github.com/datawhalechina/torch-rechub),现已替换为了自有实现。torch-rechub在开发架构和模型实现上相对成熟,本人也参与了其中一小部分的维护,欢迎感兴趣的开发者前往了解。
29
+ ## 架构
30
+
31
+ NextRec采用模块化、低耦合的工程设计,使得推荐系统从数据处理 → 模型构建 → 训练评估 → 推理部署 全链路都具备复用性与可扩展性。其中的核心组件包括:Feature Spec驱动的Embedding架构;模型基类BaseModel;独立Layer模块;支持训练和推理的统一的DataLoader;开箱即用的模型库。
32
+
33
+ ![NextRec架构](asserts/nextrec_diagram_zh.png)
34
+
35
+ > 项目的架构借鉴了一些优秀的开源推荐算法库,其中最初版的layer层借鉴了DataWhaleChina社区的[torch-rechub](https://github.com/datawhalechina/torch-rechub),现已替换为了自有实现。torch-rechub在开发架构和模型实现上相对成熟,本人也参与了其中一小部分的维护,欢迎感兴趣的开发者前往了解。
30
36
 
31
37
  ---
32
38
 
@@ -48,7 +54,7 @@ NextRec 是一个基于 PyTorch 构建的现代推荐系统框架,为研究人
48
54
  - [如何上手NextRec框架](/tutorials/notebooks/zh/Hands%20on%20nextrec.ipynb)
49
55
  - [如何使用数据处理器进行数据预处理](/tutorials/notebooks/zh/Hands%20on%20dataprocessor.ipynb)
50
56
 
51
- > 当前版本[0.3.1],召回模型模块尚不完善,可能存在一些兼容性问题或意外报错,如果遇到问题,欢迎开发者在Issue区提出问题。
57
+ > 当前版本[0.3.3],召回模型模块尚不完善,可能存在一些兼容性问题或意外报错,如果遇到问题,欢迎开发者在Issue区提出问题。
52
58
 
53
59
  ## 5分钟快速上手
54
60
 
Binary file
Binary file
@@ -11,7 +11,7 @@ sys.path.insert(0, str(PROJECT_ROOT / "nextrec"))
11
11
  project = "NextRec"
12
12
  copyright = "2025, Yang Zhou"
13
13
  author = "Yang Zhou"
14
- release = "0.3.1"
14
+ release = "0.3.3"
15
15
 
16
16
  extensions = [
17
17
  "myst_parser",
@@ -0,0 +1 @@
1
+ __version__ = "0.3.3"
@@ -2,19 +2,16 @@
2
2
  Feature definitions
3
3
 
4
4
  Date: create on 27/10/2025
5
- Checkpoint: edit on 29/11/2025
5
+ Checkpoint: edit on 02/12/2025
6
6
  Author: Yang Zhou, zyaztec@gmail.com
7
7
  """
8
8
  import torch
9
9
  from nextrec.utils.embedding import get_auto_embedding_dim
10
+ from nextrec.utils.common import normalize_to_list
10
11
 
11
12
  class BaseFeature(object):
12
13
  def __repr__(self):
13
- params = {
14
- k: v
15
- for k, v in self.__dict__.items()
16
- if not k.startswith("_")
17
- }
14
+ params = {k: v for k, v in self.__dict__.items() if not k.startswith("_") }
18
15
  param_str = ", ".join(f"{k}={v!r}" for k, v in params.items())
19
16
  return f"{self.__class__.__name__}({param_str})"
20
17
 
@@ -93,11 +90,8 @@ class DenseFeature(BaseFeature):
93
90
  else:
94
91
  self.use_embedding = use_embedding # user decides for dim <= 1
95
92
 
96
- class FeatureSpecMixin:
97
- """
98
- Mixin that normalizes dense/sparse/sequence feature lists and target/id columns.
99
- """
100
- def _set_feature_config(
93
+ class FeatureSet:
94
+ def set_all_features(
101
95
  self,
102
96
  dense_features: list[DenseFeature] | None = None,
103
97
  sparse_features: list[SparseFeature] | None = None,
@@ -111,21 +105,14 @@ class FeatureSpecMixin:
111
105
 
112
106
  self.all_features = self.dense_features + self.sparse_features + self.sequence_features
113
107
  self.feature_names = [feat.name for feat in self.all_features]
114
- self.target_columns = self._normalize_to_list(target)
115
- self.id_columns = self._normalize_to_list(id_columns)
108
+ self.target_columns = normalize_to_list(target)
109
+ self.id_columns = normalize_to_list(id_columns)
116
110
 
117
- def _set_target_id_config(
111
+ def set_target_id(
118
112
  self,
119
113
  target: str | list[str] | None = None,
120
114
  id_columns: str | list[str] | None = None,
121
115
  ) -> None:
122
- self.target_columns = self._normalize_to_list(target)
123
- self.id_columns = self._normalize_to_list(id_columns)
116
+ self.target_columns = normalize_to_list(target)
117
+ self.id_columns = normalize_to_list(id_columns)
124
118
 
125
- @staticmethod
126
- def _normalize_to_list(value: str | list[str] | None) -> list[str]:
127
- if value is None:
128
- return []
129
- if isinstance(value, str):
130
- return [value]
131
- return list(value)
@@ -18,23 +18,6 @@ from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
18
18
  from nextrec.utils.initializer import get_initializer
19
19
  from nextrec.basic.activation import activation_layer
20
20
 
21
- __all__ = [
22
- "PredictionLayer",
23
- "EmbeddingLayer",
24
- "InputMask",
25
- "LR",
26
- "ConcatPooling",
27
- "AveragePooling",
28
- "SumPooling",
29
- "MLP",
30
- "FM",
31
- "CrossLayer",
32
- "SENETLayer",
33
- "BiLinearInteractionLayer",
34
- "MultiHeadSelfAttention",
35
- "AttentionPoolingLayer",
36
- ]
37
-
38
21
  class PredictionLayer(nn.Module):
39
22
  def __init__(
40
23
  self,
@@ -44,12 +27,10 @@ class PredictionLayer(nn.Module):
44
27
  return_logits: bool = False,
45
28
  ):
46
29
  super().__init__()
47
- if isinstance(task_type, str):
48
- self.task_types = [task_type]
49
- else:
50
- self.task_types = list(task_type)
30
+ self.task_types = [task_type] if isinstance(task_type, str) else list(task_type)
51
31
  if len(self.task_types) == 0:
52
32
  raise ValueError("At least one task_type must be specified.")
33
+
53
34
  if task_dims is None:
54
35
  dims = [1] * len(self.task_types)
55
36
  elif isinstance(task_dims, int):
@@ -64,7 +45,7 @@ class PredictionLayer(nn.Module):
64
45
  self.total_dim = sum(self.task_dims)
65
46
  self.return_logits = return_logits
66
47
 
67
- # Keep slice offsets per task
48
+ # slice offsets per task
68
49
  start = 0
69
50
  self._task_slices: list[tuple[int, int]] = []
70
51
  for dim in self.task_dims:
@@ -85,27 +66,25 @@ class PredictionLayer(nn.Module):
85
66
  logits = x if self.bias is None else x + self.bias
86
67
  outputs = []
87
68
  for task_type, (start, end) in zip(self.task_types, self._task_slices):
88
- task_logits = logits[..., start:end] # Extract logits for the current task
69
+ task_logits = logits[..., start:end] # logits for the current task
89
70
  if self.return_logits:
90
71
  outputs.append(task_logits)
91
72
  continue
92
- activation = self._get_activation(task_type)
73
+ task = task_type.lower()
74
+ if task == 'binary':
75
+ activation = torch.sigmoid
76
+ elif task == 'regression':
77
+ activation = lambda x: x
78
+ elif task == 'multiclass':
79
+ activation = lambda x: torch.softmax(x, dim=-1)
80
+ else:
81
+ raise ValueError(f"[PredictionLayer Error]: Unsupported task_type '{task_type}'.")
93
82
  outputs.append(activation(task_logits))
94
83
  result = torch.cat(outputs, dim=-1)
95
84
  if result.shape[-1] == 1:
96
85
  result = result.squeeze(-1)
97
86
  return result
98
87
 
99
- def _get_activation(self, task_type: str):
100
- task = task_type.lower()
101
- if task == 'binary':
102
- return torch.sigmoid
103
- if task == 'regression':
104
- return lambda x: x
105
- if task == 'multiclass':
106
- return lambda x: torch.softmax(x, dim=-1)
107
- raise ValueError(f"[PredictionLayer Error]: Unsupported task_type '{task_type}'.")
108
-
109
88
  class EmbeddingLayer(nn.Module):
110
89
  def __init__(self, features: list):
111
90
  super().__init__()
@@ -145,7 +124,7 @@ class EmbeddingLayer(nn.Module):
145
124
  self.dense_input_dims[feature.name] = in_dim
146
125
  else:
147
126
  raise TypeError(f"[EmbeddingLayer Error]: Unsupported feature type: {type(feature)}")
148
- self.output_dim = self._compute_output_dim()
127
+ self.output_dim = self.compute_output_dim()
149
128
 
150
129
  def forward(
151
130
  self,
@@ -181,7 +160,7 @@ class EmbeddingLayer(nn.Module):
181
160
  sparse_embeds.append(pooling_layer(seq_emb, feature_mask).unsqueeze(1))
182
161
 
183
162
  elif isinstance(feature, DenseFeature):
184
- dense_embeds.append(self._project_dense(feature, x))
163
+ dense_embeds.append(self.project_dense(feature, x))
185
164
 
186
165
  if squeeze_dim:
187
166
  flattened_sparse = [emb.flatten(start_dim=1) for emb in sparse_embeds]
@@ -212,7 +191,7 @@ class EmbeddingLayer(nn.Module):
212
191
  raise ValueError("[EmbeddingLayer Error]: squeeze_dim=False requires at least one sparse/sequence feature or dense features with identical projected dimensions.")
213
192
  return torch.cat(output_embeddings, dim=1)
214
193
 
215
- def _project_dense(self, feature: DenseFeature, x: dict[str, torch.Tensor]) -> torch.Tensor:
194
+ def project_dense(self, feature: DenseFeature, x: dict[str, torch.Tensor]) -> torch.Tensor:
216
195
  if feature.name not in x:
217
196
  raise KeyError(f"[EmbeddingLayer Error]:Dense feature '{feature.name}' is missing from input.")
218
197
  value = x[feature.name].float()
@@ -228,11 +207,7 @@ class EmbeddingLayer(nn.Module):
228
207
  dense_layer = self.dense_transforms[feature.name]
229
208
  return dense_layer(value)
230
209
 
231
- def _compute_output_dim(self, features: list[DenseFeature | SequenceFeature | SparseFeature] | None = None) -> int:
232
- """
233
- Compute flattened embedding dimension for provided features or all tracked features.
234
- Deduplicates by feature name to avoid double-counting shared embeddings.
235
- """
210
+ def compute_output_dim(self, features: list[DenseFeature | SequenceFeature | SparseFeature] | None = None) -> int:
236
211
  candidates = list(features) if features is not None else self.features
237
212
  unique_feats = OrderedDict((feat.name, feat) for feat in candidates) # type: ignore[assignment]
238
213
  dim = 0
@@ -249,14 +224,13 @@ class EmbeddingLayer(nn.Module):
249
224
  return dim
250
225
 
251
226
  def get_input_dim(self, features: list[object] | None = None) -> int:
252
- return self._compute_output_dim(features) # type: ignore[assignment]
227
+ return self.compute_output_dim(features) # type: ignore[assignment]
253
228
 
254
229
  @property
255
230
  def input_dim(self) -> int:
256
231
  return self.output_dim
257
232
 
258
233
  class InputMask(nn.Module):
259
- """Utility module to build sequence masks for pooling layers."""
260
234
  def __init__(self):
261
235
  super().__init__()
262
236
 
@@ -271,7 +245,6 @@ class InputMask(nn.Module):
271
245
  return mask.unsqueeze(1).float()
272
246
 
273
247
  class LR(nn.Module):
274
- """Wide component from Wide&Deep (Cheng et al., 2016)."""
275
248
  def __init__(
276
249
  self,
277
250
  input_dim: int,
@@ -287,7 +260,6 @@ class LR(nn.Module):
287
260
  return self.fc(x)
288
261
 
289
262
  class ConcatPooling(nn.Module):
290
- """Concatenates sequence embeddings along the temporal dimension."""
291
263
  def __init__(self):
292
264
  super().__init__()
293
265
 
@@ -295,7 +267,6 @@ class ConcatPooling(nn.Module):
295
267
  return x.flatten(start_dim=1, end_dim=2)
296
268
 
297
269
  class AveragePooling(nn.Module):
298
- """Mean pooling with optional padding mask."""
299
270
  def __init__(self):
300
271
  super().__init__()
301
272
 
@@ -308,7 +279,6 @@ class AveragePooling(nn.Module):
308
279
  return sum_pooling_matrix / (non_padding_length.float() + 1e-16)
309
280
 
310
281
  class SumPooling(nn.Module):
311
- """Sum pooling with optional padding mask."""
312
282
  def __init__(self):
313
283
  super().__init__()
314
284
 
@@ -319,7 +289,6 @@ class SumPooling(nn.Module):
319
289
  return torch.bmm(mask, x).squeeze(1)
320
290
 
321
291
  class MLP(nn.Module):
322
- """Stacked fully connected layers used in the deep component."""
323
292
  def __init__(
324
293
  self,
325
294
  input_dim: int,
@@ -345,7 +314,6 @@ class MLP(nn.Module):
345
314
  return self.mlp(x)
346
315
 
347
316
  class FM(nn.Module):
348
- """Factorization Machine (Rendle, 2010) second-order interaction term."""
349
317
  def __init__(self, reduce_sum: bool = True):
350
318
  super().__init__()
351
319
  self.reduce_sum = reduce_sum
@@ -359,7 +327,6 @@ class FM(nn.Module):
359
327
  return 0.5 * ix
360
328
 
361
329
  class CrossLayer(nn.Module):
362
- """Single cross layer used in DCN (Wang et al., 2017)."""
363
330
  def __init__(self, input_dim: int):
364
331
  super(CrossLayer, self).__init__()
365
332
  self.w = torch.nn.Linear(input_dim, 1, bias=False)
@@ -370,7 +337,6 @@ class CrossLayer(nn.Module):
370
337
  return x
371
338
 
372
339
  class SENETLayer(nn.Module):
373
- """Squeeze-and-Excitation block adopted by FiBiNET (Huang et al., 2019)."""
374
340
  def __init__(
375
341
  self,
376
342
  num_fields: int,
@@ -388,7 +354,6 @@ class SENETLayer(nn.Module):
388
354
  return v
389
355
 
390
356
  class BiLinearInteractionLayer(nn.Module):
391
- """Bilinear feature interaction from FiBiNET (Huang et al., 2019)."""
392
357
  def __init__(
393
358
  self,
394
359
  input_dim: int,
@@ -416,7 +381,6 @@ class BiLinearInteractionLayer(nn.Module):
416
381
  return torch.cat(bilinear_list, dim=1)
417
382
 
418
383
  class MultiHeadSelfAttention(nn.Module):
419
- """Multi-head self-attention layer from AutoInt (Song et al., 2019)."""
420
384
  def __init__(
421
385
  self,
422
386
  embedding_dim: int,
@@ -438,13 +402,6 @@ class MultiHeadSelfAttention(nn.Module):
438
402
  self.dropout = nn.Dropout(dropout)
439
403
 
440
404
  def forward(self, x: torch.Tensor) -> torch.Tensor:
441
- """
442
- Args:
443
- x (torch.Tensor): Tensor of shape (batch_size, num_fields, embedding_dim)
444
-
445
- Returns:
446
- torch.Tensor: Output tensor of shape (batch_size, num_fields, embedding_dim)
447
- """
448
405
  batch_size, num_fields, _ = x.shape
449
406
  Q = self.W_Q(x) # [batch_size, num_fields, embedding_dim]
450
407
  K = self.W_K(x)
@@ -106,7 +106,7 @@ def setup_logger(session_id: str | os.PathLike | None = None):
106
106
 
107
107
  console_format = '%(message)s'
108
108
  file_format = '%(asctime)s - %(levelname)s - %(message)s'
109
- date_format = '%H:%M:%S'
109
+ date_format = '%Y-%m-%d %H:%M:%S'
110
110
 
111
111
  logger = logging.getLogger()
112
112
  logger.setLevel(logging.INFO)