nextrec 0.4.22__py3-none-any.whl → 0.4.23__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.
Files changed (43) hide show
  1. nextrec/__version__.py +1 -1
  2. nextrec/basic/metrics.py +1 -2
  3. nextrec/basic/model.py +68 -73
  4. nextrec/basic/summary.py +36 -2
  5. nextrec/data/preprocessor.py +137 -5
  6. nextrec/loss/listwise.py +19 -6
  7. nextrec/loss/pairwise.py +6 -4
  8. nextrec/loss/pointwise.py +8 -6
  9. nextrec/models/multi_task/esmm.py +3 -26
  10. nextrec/models/multi_task/mmoe.py +2 -24
  11. nextrec/models/multi_task/ple.py +13 -35
  12. nextrec/models/multi_task/poso.py +4 -28
  13. nextrec/models/multi_task/share_bottom.py +1 -24
  14. nextrec/models/ranking/afm.py +3 -27
  15. nextrec/models/ranking/autoint.py +5 -38
  16. nextrec/models/ranking/dcn.py +1 -26
  17. nextrec/models/ranking/dcn_v2.py +5 -33
  18. nextrec/models/ranking/deepfm.py +2 -29
  19. nextrec/models/ranking/dien.py +2 -28
  20. nextrec/models/ranking/din.py +2 -27
  21. nextrec/models/ranking/eulernet.py +3 -30
  22. nextrec/models/ranking/ffm.py +0 -26
  23. nextrec/models/ranking/fibinet.py +8 -32
  24. nextrec/models/ranking/fm.py +0 -29
  25. nextrec/models/ranking/lr.py +0 -30
  26. nextrec/models/ranking/masknet.py +4 -30
  27. nextrec/models/ranking/pnn.py +4 -28
  28. nextrec/models/ranking/widedeep.py +0 -32
  29. nextrec/models/ranking/xdeepfm.py +0 -30
  30. nextrec/models/retrieval/dssm.py +0 -24
  31. nextrec/models/retrieval/dssm_v2.py +0 -24
  32. nextrec/models/retrieval/mind.py +0 -20
  33. nextrec/models/retrieval/sdm.py +0 -20
  34. nextrec/models/retrieval/youtube_dnn.py +0 -21
  35. nextrec/models/sequential/hstu.py +0 -18
  36. nextrec/utils/model.py +79 -1
  37. nextrec/utils/types.py +35 -0
  38. {nextrec-0.4.22.dist-info → nextrec-0.4.23.dist-info}/METADATA +7 -5
  39. nextrec-0.4.23.dist-info/RECORD +81 -0
  40. nextrec-0.4.22.dist-info/RECORD +0 -81
  41. {nextrec-0.4.22.dist-info → nextrec-0.4.23.dist-info}/WHEEL +0 -0
  42. {nextrec-0.4.22.dist-info → nextrec-0.4.23.dist-info}/entry_points.txt +0 -0
  43. {nextrec-0.4.22.dist-info → nextrec-0.4.23.dist-info}/licenses/LICENSE +0 -0
@@ -56,7 +56,7 @@ embedding 表示生成一个个性化的 “mask” 向量,通过逐元素的
56
56
  import torch
57
57
  import torch.nn as nn
58
58
  import torch.nn.functional as F
59
-
59
+ from typing import Literal
60
60
  from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
61
61
  from nextrec.basic.layers import MLP, EmbeddingLayer
62
62
  from nextrec.basic.heads import TaskHead
@@ -167,48 +167,28 @@ class MaskNet(BaseModel):
167
167
  dense_features: list[DenseFeature] | None = None,
168
168
  sparse_features: list[SparseFeature] | None = None,
169
169
  sequence_features: list[SequenceFeature] | None = None,
170
- architecture: str = "parallel", # "serial" or "parallel"
170
+ architecture: Literal[
171
+ "serial", "parallel"
172
+ ] = "parallel", # "serial" or "parallel"
171
173
  num_blocks: int = 3,
172
174
  mask_hidden_dim: int = 64,
173
175
  block_hidden_dim: int = 256,
174
176
  block_dropout: float = 0.0,
175
177
  mlp_params: dict | None = None,
176
- target: list[str] | str | None = None,
177
- task: str | list[str] | None = None,
178
- optimizer: str = "adam",
179
- optimizer_params: dict | None = None,
180
- loss: str | nn.Module | None = "bce",
181
- loss_params: dict | list[dict] | None = None,
182
- embedding_l1_reg=0.0,
183
- dense_l1_reg=0.0,
184
- embedding_l2_reg=0.0,
185
- dense_l2_reg=0.0,
186
178
  **kwargs,
187
179
  ):
188
180
  dense_features = dense_features or []
189
181
  sparse_features = sparse_features or []
190
182
  sequence_features = sequence_features or []
191
- target = target or []
192
183
  mlp_params = mlp_params or {}
193
- optimizer_params = optimizer_params or {}
194
184
 
195
185
  super().__init__(
196
186
  dense_features=dense_features,
197
187
  sparse_features=sparse_features,
198
188
  sequence_features=sequence_features,
199
- target=target,
200
- task=task or self.default_task,
201
- embedding_l1_reg=embedding_l1_reg,
202
- dense_l1_reg=dense_l1_reg,
203
- embedding_l2_reg=embedding_l2_reg,
204
- dense_l2_reg=dense_l2_reg,
205
189
  **kwargs,
206
190
  )
207
191
 
208
- if loss is None:
209
- loss = "bce"
210
- self.loss = loss
211
-
212
192
  self.dense_features = dense_features
213
193
  self.sparse_features = sparse_features
214
194
  self.sequence_features = sequence_features
@@ -293,12 +273,6 @@ class MaskNet(BaseModel):
293
273
  self.register_regularization_weights(
294
274
  embedding_attr="embedding", include_modules=["mask_blocks", "final_mlp"]
295
275
  )
296
- self.compile(
297
- optimizer=optimizer,
298
- optimizer_params=optimizer_params,
299
- loss=loss,
300
- loss_params=loss_params,
301
- )
302
276
 
303
277
  def forward(self, x: dict[str, torch.Tensor]) -> torch.Tensor:
304
278
  field_emb = self.embedding(x=x, features=self.mask_features, squeeze_dim=False)
@@ -36,7 +36,7 @@ PNN 是一种 CTR 预估模型,通过将线性信号与乘积信号结合,
36
36
 
37
37
  import torch
38
38
  import torch.nn as nn
39
-
39
+ from typing import Literal
40
40
  from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
41
41
  from nextrec.basic.layers import MLP, EmbeddingLayer
42
42
  from nextrec.basic.heads import TaskHead
@@ -59,18 +59,10 @@ class PNN(BaseModel):
59
59
  sparse_features: list[SparseFeature] | None = None,
60
60
  sequence_features: list[SequenceFeature] | None = None,
61
61
  mlp_params: dict | None = None,
62
- product_type: str = "inner", # "inner" (IPNN), "outer" (OPNN), "both" (PNN*)
62
+ product_type: Literal[
63
+ "inner", "outer", "both"
64
+ ] = "inner", # "inner" (IPNN), "outer" (OPNN), "both" (PNN*)
63
65
  outer_product_dim: int | None = None,
64
- target: list[str] | str | None = None,
65
- task: str | list[str] | None = None,
66
- optimizer: str = "adam",
67
- optimizer_params: dict | None = None,
68
- loss: str | nn.Module | None = "bce",
69
- loss_params: dict | list[dict] | None = None,
70
- embedding_l1_reg=0.0,
71
- dense_l1_reg=0.0,
72
- embedding_l2_reg=0.0,
73
- dense_l2_reg=0.0,
74
66
  **kwargs,
75
67
  ):
76
68
 
@@ -80,20 +72,11 @@ class PNN(BaseModel):
80
72
  mlp_params = mlp_params or {}
81
73
  if outer_product_dim is not None and outer_product_dim <= 0:
82
74
  raise ValueError("outer_product_dim must be a positive integer.")
83
- optimizer_params = optimizer_params or {}
84
- if loss is None:
85
- loss = "bce"
86
75
 
87
76
  super(PNN, self).__init__(
88
77
  dense_features=dense_features,
89
78
  sparse_features=sparse_features,
90
79
  sequence_features=sequence_features,
91
- target=target,
92
- task=task or self.default_task,
93
- embedding_l1_reg=embedding_l1_reg,
94
- dense_l1_reg=dense_l1_reg,
95
- embedding_l2_reg=embedding_l2_reg,
96
- dense_l2_reg=dense_l2_reg,
97
80
  **kwargs,
98
81
  )
99
82
 
@@ -144,13 +127,6 @@ class PNN(BaseModel):
144
127
  embedding_attr="embedding", include_modules=modules
145
128
  )
146
129
 
147
- self.compile(
148
- optimizer=optimizer,
149
- optimizer_params=optimizer_params,
150
- loss=loss,
151
- loss_params=loss_params,
152
- )
153
-
154
130
  def compute_inner_products(self, field_emb: torch.Tensor) -> torch.Tensor:
155
131
  interactions = []
156
132
  for i in range(self.num_fields - 1):
@@ -38,8 +38,6 @@ Wide & Deep 同时使用宽线性部分(记忆共现/手工交叉)与深网
38
38
  - 共享特征空间,减少工程开销
39
39
  """
40
40
 
41
- import torch.nn as nn
42
-
43
41
  from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
44
42
  from nextrec.basic.layers import LR, MLP, EmbeddingLayer
45
43
  from nextrec.basic.heads import TaskHead
@@ -61,40 +59,16 @@ class WideDeep(BaseModel):
61
59
  sparse_features: list[SparseFeature],
62
60
  sequence_features: list[SequenceFeature],
63
61
  mlp_params: dict,
64
- target: list[str] | str | None = None,
65
- task: str | list[str] | None = None,
66
- optimizer: str = "adam",
67
- optimizer_params: dict | None = None,
68
- loss: str | nn.Module | None = "bce",
69
- loss_params: dict | list[dict] | None = None,
70
- embedding_l1_reg=0.0,
71
- dense_l1_reg=0.0,
72
- embedding_l2_reg=0.0,
73
- dense_l2_reg=0.0,
74
62
  **kwargs,
75
63
  ):
76
64
 
77
- if target is None:
78
- target = []
79
- optimizer_params = optimizer_params or {}
80
- if loss is None:
81
- loss = "bce"
82
-
83
65
  super(WideDeep, self).__init__(
84
66
  dense_features=dense_features,
85
67
  sparse_features=sparse_features,
86
68
  sequence_features=sequence_features,
87
- target=target,
88
- task=task or self.default_task,
89
- embedding_l1_reg=embedding_l1_reg,
90
- dense_l1_reg=dense_l1_reg,
91
- embedding_l2_reg=embedding_l2_reg,
92
- dense_l2_reg=dense_l2_reg,
93
69
  **kwargs,
94
70
  )
95
71
 
96
- self.loss = loss
97
-
98
72
  # Wide part: use all features for linear model
99
73
  self.wide_features = sparse_features + sequence_features
100
74
  # Deep part: use all features
@@ -117,12 +91,6 @@ class WideDeep(BaseModel):
117
91
  self.register_regularization_weights(
118
92
  embedding_attr="embedding", include_modules=["linear", "mlp"]
119
93
  )
120
- self.compile(
121
- optimizer=optimizer,
122
- optimizer_params=optimizer_params,
123
- loss=loss,
124
- loss_params=loss_params,
125
- )
126
94
 
127
95
  def forward(self, x):
128
96
  # Deep part
@@ -121,41 +121,18 @@ class xDeepFM(BaseModel):
121
121
  mlp_params: dict,
122
122
  cin_size: list[int] | None = None,
123
123
  split_half: bool = True,
124
- target: list[str] | str | None = None,
125
- task: str | list[str] | None = None,
126
- optimizer: str = "adam",
127
- optimizer_params: dict | None = None,
128
- loss: str | nn.Module | None = "bce",
129
- loss_params: dict | list[dict] | None = None,
130
- embedding_l1_reg=0.0,
131
- dense_l1_reg=0.0,
132
- embedding_l2_reg=0.0,
133
- dense_l2_reg=0.0,
134
124
  **kwargs,
135
125
  ):
136
126
 
137
127
  cin_size = cin_size or [128, 128]
138
- if target is None:
139
- target = []
140
- optimizer_params = optimizer_params or {}
141
- if loss is None:
142
- loss = "bce"
143
128
 
144
129
  super(xDeepFM, self).__init__(
145
130
  dense_features=dense_features,
146
131
  sparse_features=sparse_features,
147
132
  sequence_features=sequence_features,
148
- target=target,
149
- task=task or self.default_task,
150
- embedding_l1_reg=embedding_l1_reg,
151
- dense_l1_reg=dense_l1_reg,
152
- embedding_l2_reg=embedding_l2_reg,
153
- dense_l2_reg=dense_l2_reg,
154
133
  **kwargs,
155
134
  )
156
135
 
157
- self.loss = loss
158
-
159
136
  # Linear part and CIN part: use sparse and sequence features
160
137
  self.linear_features = sparse_features + sequence_features
161
138
 
@@ -195,13 +172,6 @@ class xDeepFM(BaseModel):
195
172
  embedding_attr="embedding", include_modules=["linear", "cin", "mlp"]
196
173
  )
197
174
 
198
- self.compile(
199
- optimizer=optimizer,
200
- optimizer_params=optimizer_params,
201
- loss=loss,
202
- loss_params=loss_params,
203
- )
204
-
205
175
  def forward(self, x):
206
176
  # Get embeddings for linear and CIN (sparse features only)
207
177
  input_linear = self.embedding(
@@ -10,7 +10,6 @@ Reference:
10
10
  from typing import Literal
11
11
 
12
12
  import torch
13
- import torch.nn as nn
14
13
 
15
14
  from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
16
15
  from nextrec.basic.layers import MLP, EmbeddingLayer
@@ -54,17 +53,6 @@ class DSSM(BaseMatchModel):
54
53
  dense_l1_reg=0.0,
55
54
  embedding_l2_reg=0.0,
56
55
  dense_l2_reg=0.0,
57
- optimizer: str | torch.optim.Optimizer = "adam",
58
- optimizer_params: dict | None = None,
59
- scheduler: (
60
- str
61
- | torch.optim.lr_scheduler._LRScheduler
62
- | type[torch.optim.lr_scheduler._LRScheduler]
63
- | None
64
- ) = None,
65
- scheduler_params: dict | None = None,
66
- loss: str | nn.Module | list[str | nn.Module] | None = "bce",
67
- loss_params: dict | list[dict] | None = None,
68
56
  **kwargs,
69
57
  ):
70
58
 
@@ -159,18 +147,6 @@ class DSSM(BaseMatchModel):
159
147
  embedding_attr="item_embedding", include_modules=["item_dnn"]
160
148
  )
161
149
 
162
- if optimizer_params is None:
163
- optimizer_params = {"lr": 1e-3, "weight_decay": 1e-5}
164
-
165
- self.compile(
166
- optimizer=optimizer,
167
- optimizer_params=optimizer_params,
168
- scheduler=scheduler,
169
- scheduler_params=scheduler_params,
170
- loss=loss,
171
- loss_params=loss_params,
172
- )
173
-
174
150
  def user_tower(self, user_input: dict) -> torch.Tensor:
175
151
  """
176
152
  User tower encodes user features into embeddings.
@@ -9,7 +9,6 @@ DSSM v2 - DSSM with pairwise training using BPR loss
9
9
  from typing import Literal
10
10
 
11
11
  import torch
12
- import torch.nn as nn
13
12
 
14
13
  from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
15
14
  from nextrec.basic.layers import MLP, EmbeddingLayer
@@ -50,17 +49,6 @@ class DSSM_v2(BaseMatchModel):
50
49
  dense_l1_reg: float = 0.0,
51
50
  embedding_l2_reg: float = 0.0,
52
51
  dense_l2_reg: float = 0.0,
53
- optimizer: str | torch.optim.Optimizer = "adam",
54
- optimizer_params: dict | None = None,
55
- scheduler: (
56
- str
57
- | torch.optim.lr_scheduler._LRScheduler
58
- | type[torch.optim.lr_scheduler._LRScheduler]
59
- | None
60
- ) = None,
61
- scheduler_params: dict | None = None,
62
- loss: str | nn.Module | list[str | nn.Module] | None = "bce",
63
- loss_params: dict | list[dict] | None = None,
64
52
  **kwargs,
65
53
  ):
66
54
 
@@ -151,18 +139,6 @@ class DSSM_v2(BaseMatchModel):
151
139
  embedding_attr="item_embedding", include_modules=["item_dnn"]
152
140
  )
153
141
 
154
- if optimizer_params is None:
155
- optimizer_params = {"lr": 1e-3, "weight_decay": 1e-5}
156
-
157
- self.compile(
158
- optimizer=optimizer,
159
- optimizer_params=optimizer_params,
160
- scheduler=scheduler,
161
- scheduler_params=scheduler_params,
162
- loss=loss,
163
- loss_params=loss_params,
164
- )
165
-
166
142
  def user_tower(self, user_input: dict) -> torch.Tensor:
167
143
  """User tower"""
168
144
  all_user_features = (
@@ -206,17 +206,6 @@ class MIND(BaseMatchModel):
206
206
  dense_l1_reg=0.0,
207
207
  embedding_l2_reg=0.0,
208
208
  dense_l2_reg=0.0,
209
- optimizer: str | torch.optim.Optimizer = "adam",
210
- optimizer_params: dict | None = None,
211
- scheduler: (
212
- str
213
- | torch.optim.lr_scheduler._LRScheduler
214
- | type[torch.optim.lr_scheduler._LRScheduler]
215
- | None
216
- ) = None,
217
- scheduler_params: dict | None = None,
218
- loss: str | nn.Module | list[str | nn.Module] | None = "bce",
219
- loss_params: dict | list[dict] | None = None,
220
209
  **kwargs,
221
210
  ):
222
211
 
@@ -322,15 +311,6 @@ class MIND(BaseMatchModel):
322
311
  include_modules=["item_dnn"] if self.item_dnn else [],
323
312
  )
324
313
 
325
- self.compile(
326
- optimizer=optimizer,
327
- optimizer_params=optimizer_params,
328
- scheduler=scheduler,
329
- scheduler_params=scheduler_params,
330
- loss=loss,
331
- loss_params=loss_params,
332
- )
333
-
334
314
  def user_tower(self, user_input: dict) -> torch.Tensor:
335
315
  """
336
316
  User tower with multi-interest extraction
@@ -53,17 +53,6 @@ class SDM(BaseMatchModel):
53
53
  dense_l1_reg=0.0,
54
54
  embedding_l2_reg=0.0,
55
55
  dense_l2_reg=0.0,
56
- optimizer: str | torch.optim.Optimizer = "adam",
57
- optimizer_params: dict | None = None,
58
- scheduler: (
59
- str
60
- | torch.optim.lr_scheduler._LRScheduler
61
- | type[torch.optim.lr_scheduler._LRScheduler]
62
- | None
63
- ) = None,
64
- scheduler_params: dict | None = None,
65
- loss: str | nn.Module | list[str | nn.Module] | None = "bce",
66
- loss_params: dict | list[dict] | None = None,
67
56
  **kwargs,
68
57
  ):
69
58
 
@@ -189,15 +178,6 @@ class SDM(BaseMatchModel):
189
178
  include_modules=["item_dnn"] if self.item_dnn else [],
190
179
  )
191
180
 
192
- self.compile(
193
- optimizer=optimizer,
194
- optimizer_params=optimizer_params,
195
- scheduler=scheduler,
196
- scheduler_params=scheduler_params,
197
- loss=loss,
198
- loss_params=loss_params,
199
- )
200
-
201
181
  def user_tower(self, user_input: dict) -> torch.Tensor:
202
182
  seq_feature = self.user_sequence_features[0]
203
183
  seq_input = user_input[seq_feature.name]
@@ -10,7 +10,6 @@ Reference:
10
10
  from typing import Literal
11
11
 
12
12
  import torch
13
- import torch.nn as nn
14
13
 
15
14
  from nextrec.basic.features import DenseFeature, SequenceFeature, SparseFeature
16
15
  from nextrec.basic.layers import MLP, EmbeddingLayer
@@ -54,17 +53,6 @@ class YoutubeDNN(BaseMatchModel):
54
53
  dense_l1_reg=0.0,
55
54
  embedding_l2_reg=0.0,
56
55
  dense_l2_reg=0.0,
57
- optimizer: str | torch.optim.Optimizer = "adam",
58
- optimizer_params: dict | None = None,
59
- scheduler: (
60
- str
61
- | torch.optim.lr_scheduler._LRScheduler
62
- | type[torch.optim.lr_scheduler._LRScheduler]
63
- | None
64
- ) = None,
65
- scheduler_params: dict | None = None,
66
- loss: str | nn.Module | list[str | nn.Module] | None = "bce",
67
- loss_params: dict | list[dict] | None = None,
68
56
  **kwargs,
69
57
  ):
70
58
 
@@ -156,15 +144,6 @@ class YoutubeDNN(BaseMatchModel):
156
144
  embedding_attr="item_embedding", include_modules=["item_dnn"]
157
145
  )
158
146
 
159
- self.compile(
160
- optimizer=optimizer,
161
- optimizer_params=optimizer_params,
162
- scheduler=scheduler,
163
- scheduler_params=scheduler_params,
164
- loss=loss,
165
- loss_params=loss_params,
166
- )
167
-
168
147
  def user_tower(self, user_input: dict) -> torch.Tensor:
169
148
  """
170
149
  User tower to encode historical behavior sequences and user features.
@@ -323,11 +323,6 @@ class HSTU(BaseModel):
323
323
  tie_embeddings: bool = True,
324
324
  target: Optional[list[str] | str] = None,
325
325
  task: str | list[str] | None = None,
326
- optimizer: str = "adam",
327
- optimizer_params: Optional[dict] = None,
328
- scheduler: Optional[str] = None,
329
- scheduler_params: Optional[dict] = None,
330
- loss_params: Optional[dict] = None,
331
326
  embedding_l1_reg: float = 0.0,
332
327
  dense_l1_reg: float = 0.0,
333
328
  embedding_l2_reg: float = 0.0,
@@ -426,19 +421,6 @@ class HSTU(BaseModel):
426
421
  self.register_buffer("causal_mask", torch.empty(0), persistent=False)
427
422
  self.ignore_index = self.padding_idx if self.padding_idx is not None else -100
428
423
 
429
- optimizer_params = optimizer_params or {}
430
- scheduler_params = scheduler_params or {}
431
- loss_params = loss_params or {}
432
- loss_params.setdefault("ignore_index", self.ignore_index)
433
-
434
- self.compile(
435
- optimizer=optimizer,
436
- optimizer_params=optimizer_params,
437
- scheduler=scheduler,
438
- scheduler_params=scheduler_params,
439
- loss="crossentropy",
440
- loss_params=loss_params,
441
- )
442
424
  self.register_regularization_weights(
443
425
  embedding_attr="token_embedding",
444
426
  include_modules=["layers", "lm_head", "context_proj"],
nextrec/utils/model.py CHANGED
@@ -2,7 +2,7 @@
2
2
  Model-related utilities for NextRec
3
3
 
4
4
  Date: create on 03/12/2025
5
- Checkpoint: edit on 24/12/2025
5
+ Checkpoint: edit on 29/12/2025
6
6
  Author: Yang Zhou, zyaztec@gmail.com
7
7
  """
8
8
 
@@ -72,6 +72,84 @@ def compute_pair_scores(model, data, batch_size: int = 512):
72
72
  return scores.detach().cpu().numpy()
73
73
 
74
74
 
75
+ def get_training_modes(
76
+ training_mode,
77
+ nums_task: int,
78
+ valid_modes: set[str] | None = None,
79
+ ) -> list:
80
+ valid_modes = valid_modes or {"pointwise", "pairwise", "listwise"}
81
+ if isinstance(training_mode, list):
82
+ training_modes = list(training_mode)
83
+ if len(training_modes) != nums_task:
84
+ raise ValueError(
85
+ "[BaseModel-init Error] training_mode list length must match number of tasks."
86
+ )
87
+ else:
88
+ training_modes = [training_mode] * nums_task
89
+ if any(mode not in valid_modes for mode in training_modes):
90
+ raise ValueError(
91
+ "[BaseModel-init Error] training_mode must be one of {'pointwise', 'pairwise', 'listwise'}."
92
+ )
93
+ return training_modes
94
+
95
+
96
+ def get_loss_list(
97
+ loss,
98
+ training_modes: list[str],
99
+ nums_task: int,
100
+ default_losses: dict[str, str],
101
+ ):
102
+ effective_loss = loss
103
+ if effective_loss is None:
104
+ loss_list = [default_losses[mode] for mode in training_modes]
105
+ elif isinstance(effective_loss, list):
106
+ if not effective_loss:
107
+ loss_list = [default_losses[mode] for mode in training_modes]
108
+ else:
109
+ if len(effective_loss) != nums_task:
110
+ raise ValueError(
111
+ f"[BaseModel-compile Error] Number of loss functions ({len(effective_loss)}) must match number of tasks ({nums_task})."
112
+ )
113
+ loss_list = list(effective_loss)
114
+ else:
115
+ loss_list = [effective_loss] * nums_task
116
+
117
+ for idx, mode in enumerate(training_modes):
118
+ if isinstance(loss_list[idx], str) and loss_list[idx] in {
119
+ "bce",
120
+ "binary_crossentropy",
121
+ }:
122
+ if mode in {"pairwise", "listwise"}:
123
+ loss_list[idx] = default_losses[mode]
124
+ return loss_list
125
+
126
+
127
+ def resolve_loss_weights(loss_weights, nums_task: int):
128
+ if loss_weights is None:
129
+ return None
130
+ if nums_task == 1:
131
+ if isinstance(loss_weights, (list, tuple)):
132
+ if len(loss_weights) != 1:
133
+ raise ValueError(
134
+ "[BaseModel-compile Error] loss_weights list must have exactly one element for single-task setup."
135
+ )
136
+ loss_weights = loss_weights[0]
137
+ return [float(loss_weights)]
138
+ if isinstance(loss_weights, (int, float)):
139
+ weights = [float(loss_weights)] * nums_task
140
+ elif isinstance(loss_weights, (list, tuple)):
141
+ weights = [float(w) for w in loss_weights]
142
+ if len(weights) != nums_task:
143
+ raise ValueError(
144
+ f"[BaseModel-compile Error] Number of loss_weights ({len(weights)}) must match number of tasks ({nums_task})."
145
+ )
146
+ else:
147
+ raise TypeError(
148
+ f"[BaseModel-compile Error] loss_weights must be int, float, list or tuple, got {type(loss_weights)}"
149
+ )
150
+ return weights
151
+
152
+
75
153
  def prepare_ranking_targets(
76
154
  y_pred: torch.Tensor, y_true: torch.Tensor
77
155
  ) -> tuple[torch.Tensor, torch.Tensor]:
nextrec/utils/types.py CHANGED
@@ -61,3 +61,38 @@ ActivationName = Literal[
61
61
  TrainingModeName = Literal["pointwise", "pairwise", "listwise"]
62
62
 
63
63
  TaskTypeName = Literal["binary", "regression"]
64
+
65
+ MetricsName = Literal[
66
+ "auc",
67
+ "gauc",
68
+ "ks",
69
+ "logloss",
70
+ "accuracy",
71
+ "acc",
72
+ "precision",
73
+ "recall",
74
+ "f1",
75
+ "micro_f1",
76
+ "macro_f1",
77
+ "mse",
78
+ "mae",
79
+ "rmse",
80
+ "r2",
81
+ "mape",
82
+ "msle",
83
+ "auc",
84
+ "gauc",
85
+ "precision@10",
86
+ "hitrate@10",
87
+ "map@10",
88
+ "cosine",
89
+ "recall@5",
90
+ "recall@10",
91
+ "recall@20",
92
+ "ndcg@5",
93
+ "ndcg@10",
94
+ "ndcg@20",
95
+ "mrr@5",
96
+ "mrr@10",
97
+ "mrr@20",
98
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextrec
3
- Version: 0.4.22
3
+ Version: 0.4.23
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.22-orange.svg)
72
+ ![Version](https://img.shields.io/badge/Version-0.4.23-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)
@@ -191,6 +191,8 @@ model = DIN(
191
191
  dense_features=dense_features,
192
192
  sparse_features=sparse_features,
193
193
  sequence_features=sequence_features,
194
+ behavior_feature_name="sequence_0",
195
+ candidate_feature_name="item_id",
194
196
  mlp_params=mlp_params,
195
197
  attention_hidden_units=[80, 40],
196
198
  attention_activation='sigmoid',
@@ -204,7 +206,7 @@ model = DIN(
204
206
  session_id="din_tutorial", # 实验id,用于存放训练日志
205
207
  )
206
208
 
207
- # 编译模型,设置优化器和损失函数
209
+ # 编译模型,优化器/损失/学习率调度器统一在 compile 中设置
208
210
  model.compile(
209
211
  optimizer = "adam",
210
212
  optimizer_params = {"lr": 1e-3, "weight_decay": 1e-5},
@@ -247,11 +249,11 @@ nextrec --mode=predict --predict_config=path/to/predict_config.yaml
247
249
 
248
250
  预测结果固定保存到 `{checkpoint_path}/predictions/{name}.{save_data_format}`。
249
251
 
250
- > 截止当前版本0.4.22,NextRec CLI支持单机训练,分布式训练相关功能尚在开发中。
252
+ > 截止当前版本0.4.23,NextRec CLI支持单机训练,分布式训练相关功能尚在开发中。
251
253
 
252
254
  ## 兼容平台
253
255
 
254
- 当前最新版本为0.4.22,所有模型和测试代码均已在以下平台通过验证,如果开发者在使用中遇到兼容问题,请在issue区提出错误报告及系统版本:
256
+ 当前最新版本为0.4.23,所有模型和测试代码均已在以下平台通过验证,如果开发者在使用中遇到兼容问题,请在issue区提出错误报告及系统版本:
255
257
 
256
258
  | 平台 | 配置 |
257
259
  |------|------|