nextrec 0.4.27__py3-none-any.whl → 0.4.28__py3-none-any.whl

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.
nextrec/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.4.27"
1
+ __version__ = "0.4.28"
@@ -5,13 +5,27 @@ Date: create on 03/12/2025
5
5
  Author: Yang Zhou, zyaztec@gmail.com
6
6
  """
7
7
 
8
- from typing import Any, Mapping
8
+ from typing import Any, Mapping, Literal
9
9
 
10
10
  import numpy as np
11
11
  import torch
12
12
 
13
13
 
14
- def stack_section(batch: list[dict], section: str):
14
+ def stack_section(batch: list[dict], section: Literal["features", "labels", "ids"]):
15
+ """
16
+ input example:
17
+ batch = [
18
+ {"features": {"f1": tensor1, "f2": tensor2}, "labels": {"label": tensor3}},
19
+ {"features": {"f1": tensor4, "f2": tensor5}, "labels": {"label": tensor6}},
20
+ ...
21
+ ]
22
+ output example:
23
+ {
24
+ "f1": torch.stack([tensor1, tensor4], dim=0),
25
+ "f2": torch.stack([tensor2, tensor5], dim=0),
26
+ }
27
+
28
+ """
15
29
  entries = [item.get(section) for item in batch if item.get(section) is not None]
16
30
  if not entries:
17
31
  return None
@@ -22,7 +36,13 @@ def stack_section(batch: list[dict], section: str):
22
36
  for item in batch
23
37
  if item.get(section) is not None and name in item[section]
24
38
  ]
25
- merged[name] = torch.stack(tensors, dim=0)
39
+ tensor_sample = tensors[0]
40
+ if isinstance(tensor_sample, torch.Tensor):
41
+ merged[name] = torch.stack(tensors, dim=0)
42
+ elif isinstance(tensor_sample, np.ndarray):
43
+ merged[name] = np.stack(tensors, axis=0)
44
+ else:
45
+ merged[name] = tensors
26
46
  return merged
27
47
 
28
48
 
@@ -2,7 +2,7 @@
2
2
  Dataloader definitions
3
3
 
4
4
  Date: create on 27/10/2025
5
- Checkpoint: edit on 24/12/2025
5
+ Checkpoint: edit on 01/01/2026
6
6
  Author: Yang Zhou,zyaztec@gmail.com
7
7
  """
8
8
 
@@ -523,13 +523,8 @@ def build_tensors_from_data(
523
523
  raise KeyError(
524
524
  f"[RecDataLoader Error] ID column '{id_col}' not found in provided data."
525
525
  )
526
- try:
527
- id_arr = np.asarray(column, dtype=np.int64)
528
- except Exception as exc:
529
- raise TypeError(
530
- f"[RecDataLoader Error] ID column '{id_col}' must contain numeric values. Received dtype={np.asarray(column).dtype}, error: {exc}"
531
- ) from exc
532
- id_tensors[id_col] = to_tensor(id_arr, dtype=torch.long)
526
+ # Normalize all id columns to strings for consistent downstream handling.
527
+ id_tensors[id_col] = np.asarray(column, dtype=str)
533
528
  if not feature_tensors:
534
529
  return None
535
530
  return {"features": feature_tensors, "labels": label_tensors, "ids": id_tensors}
@@ -61,9 +61,9 @@ from nextrec.utils.model import select_features
61
61
  from nextrec.utils.types import TaskTypeName
62
62
 
63
63
 
64
- class PPNetBlock(nn.Module):
64
+ class PPNet(nn.Module):
65
65
  """
66
- PEPNet block with per-layer gates conditioned on task context.
66
+ PPNet: per-task tower with layer-wise gates conditioned on task context.
67
67
  """
68
68
 
69
69
  def __init__(
@@ -274,18 +274,21 @@ class PEPNet(BaseModel):
274
274
  )
275
275
  task_dim = domain_dim + user_dim + item_dim
276
276
 
277
- self.feature_gate = GateMLP(
277
+ # EPNet: shared feature-level gate (paper's EPNet).
278
+ self.epnet = GateMLP(
278
279
  input_dim=input_dim + domain_dim,
279
280
  hidden_dim=feature_gate_mlp_params["hidden_dim"],
280
281
  output_dim=input_dim,
281
282
  activation=feature_gate_mlp_params["activation"],
282
283
  dropout=feature_gate_mlp_params["dropout"],
283
284
  use_bn=feature_gate_mlp_params["use_bn"],
285
+ scale_factor=2.0,
284
286
  )
285
287
 
286
- self.ppn_blocks = nn.ModuleList(
288
+ # PPNet: per-task gated towers (paper's PPNet).
289
+ self.ppnet_blocks = nn.ModuleList(
287
290
  [
288
- PPNetBlock(
291
+ PPNet(
289
292
  input_dim=input_dim,
290
293
  output_dim=1,
291
294
  gate_input_dim=input_dim + task_dim,
@@ -300,9 +303,9 @@ class PEPNet(BaseModel):
300
303
  self.prediction_layer = TaskHead(
301
304
  task_type=self.task, task_dims=[1] * self.nums_task
302
305
  )
303
- self.grad_norm_shared_modules = ["embedding", "feature_gate"]
306
+ self.grad_norm_shared_modules = ["embedding", "epnet"]
304
307
  self.register_regularization_weights(
305
- embedding_attr="embedding", include_modules=["feature_gate", "ppn_blocks"]
308
+ embedding_attr="embedding", include_modules=["epnet", "ppnet_blocks"]
306
309
  )
307
310
 
308
311
  def forward(self, x: dict[str, torch.Tensor]) -> torch.Tensor:
@@ -327,11 +330,11 @@ class PEPNet(BaseModel):
327
330
  task_sf_emb = torch.cat(task_parts, dim=-1)
328
331
 
329
332
  gate_input = torch.cat([dnn_input.detach(), domain_emb], dim=-1)
330
- dnn_input = self.feature_gate(gate_input) * dnn_input
333
+ dnn_input = self.epnet(gate_input) * dnn_input
331
334
 
332
335
  task_logits = []
333
- for block in self.ppn_blocks:
334
- task_logits.append(block(o_ep=dnn_input, o_prior=task_sf_emb))
336
+ for block in self.ppnet_blocks:
337
+ task_logits.append(block(o_ep=dnn_input, o_prior=task_sf_emb))
335
338
 
336
339
  y = torch.cat(task_logits, dim=1)
337
340
  return self.prediction_layer(y)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextrec
3
- Version: 0.4.27
3
+ Version: 0.4.28
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
@@ -69,7 +69,7 @@ Description-Content-Type: text/markdown
69
69
  ![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)
70
70
  ![PyTorch](https://img.shields.io/badge/PyTorch-1.10+-ee4c2c.svg)
71
71
  ![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)
72
- ![Version](https://img.shields.io/badge/Version-0.4.27-orange.svg)
72
+ ![Version](https://img.shields.io/badge/Version-0.4.28-orange.svg)
73
73
  [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/zerolovesea/NextRec)
74
74
 
75
75
  中文文档 | [English Version](README_en.md)
@@ -102,7 +102,7 @@ NextRec是一个基于PyTorch的现代推荐系统框架,旨在为研究工程
102
102
  - **高效训练与评估**:内置多种优化器、学习率调度、早停、模型检查点与详细的日志管理,开箱即用。
103
103
 
104
104
  ## NextRec近期进展
105
- - **01/01/2026** 新年好,在v0.4.27中加入了多个多目标模型的支持:[APG](nextrec/models/multi_task/apg.py), [ESCM](nextrec/models/multi_task/escm.py), [HMoE](nextrec/models/multi_task/hmoe.py), [Cross Stitch](nextrec/models/multi_task/cross_stitch.py)
105
+ - **01/01/2026** 新年好,在v0.4.28中加入了多个多目标模型的支持:[APG](nextrec/models/multi_task/apg.py), [ESCM](nextrec/models/multi_task/escm.py), [HMoE](nextrec/models/multi_task/hmoe.py), [Cross Stitch](nextrec/models/multi_task/cross_stitch.py)
106
106
  - **28/12/2025** 在v0.4.21中加入了对SwanLab和Wandb的支持,通过model的`fit`方法进行配置:`use_swanlab=True, swanlab_kwargs={"project": "NextRec","name":"tutorial_movielens_deepfm"},`
107
107
  - **21/12/2025** 在v0.4.16中加入了对[GradNorm](/nextrec/loss/grad_norm.py)的支持,通过compile的`loss_weight='grad_norm'`进行配置
108
108
  - **12/12/2025** 在v0.4.9中加入了[RQ-VAE](/nextrec/models/representation/rqvae.py)模块。配套的[数据集](/dataset/ecommerce_task.csv)和[代码](tutorials/notebooks/zh/使用RQ-VAE构建语义ID.ipynb)已经同步在仓库中
@@ -254,11 +254,11 @@ nextrec --mode=predict --predict_config=path/to/predict_config.yaml
254
254
 
255
255
  预测结果固定保存到 `{checkpoint_path}/predictions/{name}.{save_data_format}`。
256
256
 
257
- > 截止当前版本0.4.27,NextRec CLI支持单机训练,分布式训练相关功能尚在开发中。
257
+ > 截止当前版本0.4.28,NextRec CLI支持单机训练,分布式训练相关功能尚在开发中。
258
258
 
259
259
  ## 兼容平台
260
260
 
261
- 当前最新版本为0.4.27,所有模型和测试代码均已在以下平台通过验证,如果开发者在使用中遇到兼容问题,请在issue区提出错误报告及系统版本:
261
+ 当前最新版本为0.4.28,所有模型和测试代码均已在以下平台通过验证,如果开发者在使用中遇到兼容问题,请在issue区提出错误报告及系统版本:
262
262
 
263
263
  | 平台 | 配置 |
264
264
  |------|------|
@@ -1,5 +1,5 @@
1
1
  nextrec/__init__.py,sha256=_M3oUqyuvQ5k8Th_3wId6hQ_caclh7M5ad51XN09m98,235
2
- nextrec/__version__.py,sha256=M6cnWFk1Yz0fBKyJSOiFIvowDDGt2oz9dCYCtlYnCj4,23
2
+ nextrec/__version__.py,sha256=QZ0p7EqvqxpClz_YH3XtlxgPmyXKcK-CGg_B_p5Z7w0,23
3
3
  nextrec/cli.py,sha256=uOaXnlAM-ARrbxKOVWWkTE_rv-54px168kBhFUHtIAg,25073
4
4
  nextrec/basic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  nextrec/basic/activation.py,sha256=uekcJsOy8SiT0_NaDO2VNSStyYFzVikDFVLDk-VrjwQ,2949
@@ -14,10 +14,10 @@ nextrec/basic/model.py,sha256=4vBp-vXAWC5Oiu_x4mtVaXTKJCcKDYT0IJ7UOyHD5lw,110162
14
14
  nextrec/basic/session.py,sha256=mrIsjRJhmvcAfoO1pXX-KB3SK5CCgz89wH8XDoAiGEI,4475
15
15
  nextrec/basic/summary.py,sha256=b6jLo70gqZj_bQ4eb5yb8SXmr2ilZlKNN293EyVnkyc,17759
16
16
  nextrec/data/__init__.py,sha256=YZQjpty1pDCM7q_YNmiA2sa5kbujUw26ObLHWjMPjKY,1194
17
- nextrec/data/batch_utils.py,sha256=0bYGVX7RlhnHv_ZBaUngjDIpBNw-igCk98DgOsF7T6o,2879
17
+ nextrec/data/batch_utils.py,sha256=vqlBvdfrhFEIUHmiWuUdXg1oY2jkyKOO1JO2l2KpJUU,3549
18
18
  nextrec/data/data_processing.py,sha256=lhuwYxWp4Ts2bbuLGDt2LmuPrOy7pNcKczd2uVcQ4ss,6476
19
19
  nextrec/data/data_utils.py,sha256=0Ls1cnG9lBz0ovtyedw5vwp7WegGK_iF-F8e_3DEddo,880
20
- nextrec/data/dataloader.py,sha256=gTs4YC5tHHwTq0A9481KYK1XyloeN2dMVOjPAFehF_E,19972
20
+ nextrec/data/dataloader.py,sha256=2sXwoiWxupKE-V1QYeZlXjK1yJyxhDtlOhknAnJF8Wk,19727
21
21
  nextrec/data/preprocessor.py,sha256=AD5bHNbkAZAnI_SbDfJJaAh57CRtRjoOQJ6aIBkgoQs,65251
22
22
  nextrec/loss/__init__.py,sha256=rualGsY-IBvmM52q9eOBk0MyKcMkpkazcscOeDXi_SM,774
23
23
  nextrec/loss/grad_norm.py,sha256=YoE_XSIN1HOUcNq1dpfkIlWtMaB5Pu-SEWDaNgtRw1M,8316
@@ -36,7 +36,7 @@ nextrec/models/multi_task/escm.py,sha256=Djk4SjLsZ8He3sZrKfZkHdH2istR9R71GVEJc6E
36
36
  nextrec/models/multi_task/esmm.py,sha256=QRnNXV1IEArYorYJLOoBcLbxarMC_7azQLP79QTfAJ8,5273
37
37
  nextrec/models/multi_task/hmoe.py,sha256=6mTzZxC5PfSQovrmnR0O2hdhDUG_8yNqMwCdkNRlHkY,7567
38
38
  nextrec/models/multi_task/mmoe.py,sha256=Mplzstu-LYEMtiKiyiMEQZwY-xMkUeG-1FaDqqK5kws,7606
39
- nextrec/models/multi_task/pepnet.py,sha256=1da-uS5Dnl-lHs1SJrja-mQTlPJng3lKJcIRavWtFCk,13385
39
+ nextrec/models/multi_task/pepnet.py,sha256=ikCDu66TTPdfp94HU-4QzKCW5JOEvwAf5E0QEQ0SZzw,13510
40
40
  nextrec/models/multi_task/ple.py,sha256=cO-NqEm-UZKRz2MznBjqsXL8ImH7WU1HRzXdWAtb7Kk,12089
41
41
  nextrec/models/multi_task/poso.py,sha256=Xjw9JBAiGR9CGewp1uS4b1soA7fOvSWTsIT6pS9_o30,18215
42
42
  nextrec/models/multi_task/share_bottom.py,sha256=BT-nu0NZTV4HlFkva_KnoKLSxB0-gYuJWPw7PRDGwC8,5172
@@ -83,8 +83,8 @@ nextrec/utils/loss.py,sha256=GBWQGpDaYkMJySpdG078XbeUNXUC34PVqFy0AqNS9N0,4578
83
83
  nextrec/utils/model.py,sha256=PI9y8oWz1lhktgapZsiXb8rTr2NrFFlc80tr4yOFHik,5334
84
84
  nextrec/utils/torch_utils.py,sha256=UQpWS7F3nITYqvx2KRBaQJc9oTowRkIvowhuQLt6NFM,11953
85
85
  nextrec/utils/types.py,sha256=VhtLXUVvu0zAZVAUgRUML4FExRC-GH-ZmC1UiVSr3HE,1523
86
- nextrec-0.4.27.dist-info/METADATA,sha256=oKaTQkJVnQjpSxH-rjWCFICRoIRGMbopjv6K3sXV_m8,23188
87
- nextrec-0.4.27.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
88
- nextrec-0.4.27.dist-info/entry_points.txt,sha256=NN-dNSdfMRTv86bNXM7d3ZEPW2BQC6bRi7QP7i9cIps,45
89
- nextrec-0.4.27.dist-info/licenses/LICENSE,sha256=2fQfVKeafywkni7MYHyClC6RGGC3laLTXCNBx-ubtp0,1064
90
- nextrec-0.4.27.dist-info/RECORD,,
86
+ nextrec-0.4.28.dist-info/METADATA,sha256=dZDTiMVnLG8aZga9anG-7iEZ8lGGceYOnoR3ZuTX-2I,23188
87
+ nextrec-0.4.28.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
88
+ nextrec-0.4.28.dist-info/entry_points.txt,sha256=NN-dNSdfMRTv86bNXM7d3ZEPW2BQC6bRi7QP7i9cIps,45
89
+ nextrec-0.4.28.dist-info/licenses/LICENSE,sha256=2fQfVKeafywkni7MYHyClC6RGGC3laLTXCNBx-ubtp0,1064
90
+ nextrec-0.4.28.dist-info/RECORD,,