Skip to content

Commit f685425

Browse files
shenweichenzanshuxunxuyxu
authored
Add multi-task models: SharedBottom, ESMM, MMOE, PLE
* add multitask mdoels 1. Add multi-task models: SharedBottom, ESMM, MMOE, PLE 2. Bugfix: #240 #232 * support python 3.9/3.10 (#259) * fix: variable name typo (#257) Co-authored-by: Jason Zan <zanshuxun@aliyun.com> Co-authored-by: Yi-Xuan Xu <xuyx@lamda.nju.edu.cn>
2 parents 2cd84f3 + 70aa7ab commit f685425

41 files changed

Lines changed: 1322 additions & 48 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ Steps to reproduce the behavior:
1818
4. See error
1919

2020
**Operating environment(运行环境):**
21-
- python version [e.g. 3.5, 3.6]
22-
- torch version [e.g. 1.6.0, 1.7.0]
23-
- deepctr-torch version [e.g. 0.2.7,]
21+
- python version [e.g. 3.6, 3.7]
22+
- torch version [e.g. 1.9.0, 1.10.0]
23+
- deepctr-torch version [e.g. 0.2.9,]
2424

2525
**Additional context**
2626
Add any other context about the problem here.

.github/ISSUE_TEMPLATE/question.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ Add any other context about the problem here.
1616

1717
**Operating environment(运行环境):**
1818
- python version [e.g. 3.6]
19-
- torch version [e.g. 1.7.0,]
20-
- deepctr-torch version [e.g. 0.2.7,]
19+
- torch version [e.g. 1.10.0,]
20+
- deepctr-torch version [e.g. 0.2.9,]

.github/workflows/ci.yml

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,48 @@ jobs:
1717
timeout-minutes: 120
1818
strategy:
1919
matrix:
20-
python-version: [3.6,3.7,3.8]
21-
torch-version: [1.1.0,1.2.0,1.3.0,1.4.0,1.5.0,1.6.0,1.7.1,1.8.1,1.9.0,1.10.2,1.11.0]
20+
python-version: [3.6,3.7,3.8,3.9,3.10.7]
21+
torch-version: [1.2.0,1.3.0,1.4.0,1.5.0,1.6.0,1.7.1,1.8.1,1.9.0,1.10.2,1.11.0,1.12.1]
2222

2323
exclude:
2424
- python-version: 3.6
2525
torch-version: 1.11.0
26-
- python-version: 3.8
27-
torch-version: 1.1.0
26+
- python-version: 3.6
27+
torch-version: 1.12.1
2828
- python-version: 3.8
2929
torch-version: 1.2.0
3030
- python-version: 3.8
3131
torch-version: 1.3.0
32-
32+
- python-version: 3.9
33+
torch-version: 1.2.0
34+
- python-version: 3.9
35+
torch-version: 1.3.0
36+
- python-version: 3.9
37+
torch-version: 1.4.0
38+
- python-version: 3.9
39+
torch-version: 1.5.0
40+
- python-version: 3.9
41+
torch-version: 1.6.0
42+
- python-version: 3.9
43+
torch-version: 1.7.1
44+
- python-version: 3.10.7
45+
torch-version: 1.2.0
46+
- python-version: 3.10.7
47+
torch-version: 1.3.0
48+
- python-version: 3.10.7
49+
torch-version: 1.4.0
50+
- python-version: 3.10.7
51+
torch-version: 1.5.0
52+
- python-version: 3.10.7
53+
torch-version: 1.6.0
54+
- python-version: 3.10.7
55+
torch-version: 1.7.1
56+
- python-version: 3.10.7
57+
torch-version: 1.8.1
58+
- python-version: 3.10.7
59+
torch-version: 1.9.0
60+
- python-version: 3.10.7
61+
torch-version: 1.10.2
3362
steps:
3463

3564
- uses: actions/checkout@v3

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ Let's [**Get Started!**](https://deepctr-torch.readthedocs.io/en/latest/Quick-St
3838
| AutoInt | [CIKM 2019][AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks](https://arxiv.org/abs/1810.11921) |
3939
| ONN | [arxiv 2019][Operation-aware Neural Networks for User Response Prediction](https://arxiv.org/pdf/1904.12579.pdf) |
4040
| FiBiNET | [RecSys 2019][FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction](https://arxiv.org/pdf/1905.09433.pdf) |
41-
| IFM | [IJCAI 2019][An Input-aware Factorization Machine for Sparse Prediction](https://www.ijcai.org/Proceedings/2019/0203.pdf) |
42-
| DCN V2 | [arxiv 2020][DCN V2: Improved Deep & Cross Network and Practical Lessons for Web-scale Learning to Rank Systems](https://arxiv.org/abs/2008.13535) |
43-
| DIFM | [IJCAI 2020][A Dual Input-aware Factorization Machine for CTR Prediction](https://www.ijcai.org/Proceedings/2020/0434.pdf) |
44-
| AFN | [AAAI 2020][Adaptive Factorization Network: Learning Adaptive-Order Feature Interactions](https://arxiv.org/pdf/1909.03276) |
41+
| IFM | [IJCAI 2019][An Input-aware Factorization Machine for Sparse Prediction](https://www.ijcai.org/Proceedings/2019/0203.pdf) |
42+
| DCN V2 | [arxiv 2020][DCN V2: Improved Deep & Cross Network and Practical Lessons for Web-scale Learning to Rank Systems](https://arxiv.org/abs/2008.13535) |
43+
| DIFM | [IJCAI 2020][A Dual Input-aware Factorization Machine for CTR Prediction](https://www.ijcai.org/Proceedings/2020/0434.pdf) |
44+
| AFN | [AAAI 2020][Adaptive Factorization Network: Learning Adaptive-Order Feature Interactions](https://arxiv.org/pdf/1909.03276) |
45+
| SharedBottom | [arxiv 2017][An Overview of Multi-Task Learning in Deep Neural Networks](https://arxiv.org/pdf/1706.05098.pdf) |
46+
| ESMM | [SIGIR 2018][Entire Space Multi-Task Model: An Effective Approach for Estimating Post-Click Conversion Rate](https://dl.acm.org/doi/10.1145/3209978.3210104) |
47+
| MMOE | [KDD 2018][Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts](https://dl.acm.org/doi/abs/10.1145/3219819.3220007) |
48+
| PLE | [RecSys 2020][Progressive Layered Extraction (PLE): A Novel Multi-Task Learning (MTL) Model for Personalized Recommendations](https://dl.acm.org/doi/10.1145/3383313.3412236) |
4549

4650

4751

deepctr_torch/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
from . import models
33
from .utils import check_version
44

5-
__version__ = '0.2.8'
5+
__version__ = '0.2.9'
66
check_version(__version__)

deepctr_torch/models/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
from .ccpm import CCPM
1616
from .dien import DIEN
1717
from .din import DIN
18-
from .afn import AFN
18+
from .afn import AFN
19+
from .multitask import SharedBottom, ESMM, MMOE, PLE

deepctr_torch/models/basemodel.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,13 @@ def fit(self, x=None, y=None, batch_size=None, epochs=1, verbose=1, initial_epoc
245245
y_pred = model(x).squeeze()
246246

247247
optim.zero_grad()
248-
loss = loss_func(y_pred, y.squeeze(), reduction='sum')
248+
if isinstance(loss_func, list):
249+
assert len(loss_func) == self.num_tasks,\
250+
"the length of `loss_func` should be equal with `self.num_tasks`"
251+
loss = sum(
252+
[loss_func[i](y_pred[:, i], y[:, i], reduction='sum') for i in range(self.num_tasks)])
253+
else:
254+
loss = loss_func(y_pred, y.squeeze(), reduction='sum')
249255
reg_loss = self.get_regularization_loss()
250256

251257
total_loss = loss + reg_loss + self.aux_loss
@@ -456,18 +462,24 @@ def _get_optim(self, optimizer):
456462

457463
def _get_loss_func(self, loss):
458464
if isinstance(loss, str):
459-
if loss == "binary_crossentropy":
460-
loss_func = F.binary_cross_entropy
461-
elif loss == "mse":
462-
loss_func = F.mse_loss
463-
elif loss == "mae":
464-
loss_func = F.l1_loss
465-
else:
466-
raise NotImplementedError
465+
loss_func = self._get_loss_func_single(loss)
466+
elif isinstance(loss, list):
467+
loss_func = [self._get_loss_func_single(loss_single) for loss_single in loss]
467468
else:
468469
loss_func = loss
469470
return loss_func
470471

472+
def _get_loss_func_single(self, loss):
473+
if loss == "binary_crossentropy":
474+
loss_func = F.binary_cross_entropy
475+
elif loss == "mse":
476+
loss_func = F.mse_loss
477+
elif loss == "mae":
478+
loss_func = F.l1_loss
479+
else:
480+
raise NotImplementedError
481+
return loss_func
482+
471483
def _log_loss(self, y_true, y_pred, eps=1e-7, normalize=True, sample_weight=None, labels=None):
472484
# change eps to improve calculation accuracy
473485
return log_loss(y_true,

deepctr_torch/models/dcnmix.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ def __init__(self, linear_feature_columns,
7171
self.add_regularization_weight(
7272
filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn)
7373
self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_linear)
74-
self.add_regularization_weight(self.crossnet.U_list, l2=l2_reg_cross)
75-
self.add_regularization_weight(self.crossnet.V_list, l2=l2_reg_cross)
76-
self.add_regularization_weight(self.crossnet.C_list, l2=l2_reg_cross)
74+
regularization_modules = [self.crossnet.U_list, self.crossnet.V_list, self.crossnet.C_list]
75+
for module in regularization_modules:
76+
self.add_regularization_weight(module, l2=l2_reg_cross)
77+
7778
self.to(device)
7879

7980
def forward(self, X):

deepctr_torch/models/dien.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def forward(self, keys, keys_length, neg_keys=None):
217217

218218
masked_keys = torch.masked_select(keys, mask.view(-1, 1, 1)).view(-1, max_length, dim)
219219

220-
packed_keys = pack_padded_sequence(masked_keys, lengths=masked_keys_length, batch_first=True,
220+
packed_keys = pack_padded_sequence(masked_keys, lengths=masked_keys_length.cpu(), batch_first=True,
221221
enforce_sorted=False)
222222
packed_interests, _ = self.gru(packed_keys)
223223
interests, _ = pad_packed_sequence(packed_interests, batch_first=True, padding_value=0.0,
@@ -353,7 +353,7 @@ def forward(self, query, keys, keys_length, mask=None):
353353
query = torch.masked_select(query, mask.view(-1, 1)).view(-1, dim).unsqueeze(1)
354354

355355
if self.gru_type == 'GRU':
356-
packed_keys = pack_padded_sequence(keys, lengths=keys_length, batch_first=True, enforce_sorted=False)
356+
packed_keys = pack_padded_sequence(keys, lengths=keys_length.cpu(), batch_first=True, enforce_sorted=False)
357357
packed_interests, _ = self.interest_evolution(packed_keys)
358358
interests, _ = pad_packed_sequence(packed_interests, batch_first=True, padding_value=0.0,
359359
total_length=max_length)
@@ -362,15 +362,15 @@ def forward(self, query, keys, keys_length, mask=None):
362362
elif self.gru_type == 'AIGRU':
363363
att_scores = self.attention(query, keys, keys_length.unsqueeze(1)) # [b, 1, T]
364364
interests = keys * att_scores.transpose(1, 2) # [b, T, H]
365-
packed_interests = pack_padded_sequence(interests, lengths=keys_length, batch_first=True,
365+
packed_interests = pack_padded_sequence(interests, lengths=keys_length.cpu(), batch_first=True,
366366
enforce_sorted=False)
367367
_, outputs = self.interest_evolution(packed_interests)
368368
outputs = outputs.squeeze(0) # [b, H]
369369
elif self.gru_type == 'AGRU' or self.gru_type == 'AUGRU':
370370
att_scores = self.attention(query, keys, keys_length.unsqueeze(1)).squeeze(1) # [b, T]
371-
packed_interests = pack_padded_sequence(keys, lengths=keys_length, batch_first=True,
371+
packed_interests = pack_padded_sequence(keys, lengths=keys_length.cpu(), batch_first=True,
372372
enforce_sorted=False)
373-
packed_scores = pack_padded_sequence(att_scores, lengths=keys_length, batch_first=True,
373+
packed_scores = pack_padded_sequence(att_scores, lengths=keys_length.cpu(), batch_first=True,
374374
enforce_sorted=False)
375375
outputs = self.interest_evolution(packed_interests, packed_scores)
376376
outputs, _ = pad_packed_sequence(outputs, batch_first=True, padding_value=0.0, total_length=max_length)

deepctr_torch/models/fibinet.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ def __init__(self, linear_feature_columns, dnn_feature_columns, bilinear_type='i
4545
device=device, gpus=gpus)
4646
self.linear_feature_columns = linear_feature_columns
4747
self.dnn_feature_columns = dnn_feature_columns
48-
self.filed_size = len(self.embedding_dict)
49-
self.SE = SENETLayer(self.filed_size, reduction_ratio, seed, device)
50-
self.Bilinear = BilinearInteraction(self.filed_size, self.embedding_size, bilinear_type, seed, device)
48+
self.field_size = len(self.embedding_dict)
49+
self.SE = SENETLayer(self.field_size, reduction_ratio, seed, device)
50+
self.Bilinear = BilinearInteraction(self.field_size, self.embedding_size, bilinear_type, seed, device)
5151
self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units,
5252
activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=False,
5353
init_std=init_std, device=device)

0 commit comments

Comments
 (0)