├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── deepctr_torch ├── __init__.py ├── callbacks.py ├── inputs.py ├── layers │ ├── __init__.py │ ├── activation.py │ ├── core.py │ ├── interaction.py │ ├── sequence.py │ └── utils.py ├── models │ ├── __init__.py │ ├── afm.py │ ├── afn.py │ ├── autoint.py │ ├── basemodel.py │ ├── ccpm.py │ ├── dcn.py │ ├── dcnmix.py │ ├── deepfm.py │ ├── dien.py │ ├── difm.py │ ├── din.py │ ├── fibinet.py │ ├── ifm.py │ ├── mlr.py │ ├── multitask │ │ ├── __init__.py │ │ ├── esmm.py │ │ ├── mmoe.py │ │ ├── ple.py │ │ └── sharedbottom.py │ ├── nfm.py │ ├── onn.py │ ├── pnn.py │ ├── wdl.py │ └── xdeepfm.py └── utils.py ├── docs ├── Makefile ├── make.bat ├── pics │ ├── AFM.png │ ├── AFN.jpg │ ├── AutoInt.png │ ├── CCPM.png │ ├── CIN.png │ ├── DCN-M.png │ ├── DCN-Mix.png │ ├── DCN.png │ ├── DIEN.png │ ├── DIFM.png │ ├── DIN.png │ ├── DSIN.png │ ├── DeepFM.png │ ├── FGCNN.png │ ├── FNN.png │ ├── FiBiNET.png │ ├── IFM.png │ ├── InteractingLayer.png │ ├── MLR.png │ ├── NFM.png │ ├── ONN.png │ ├── PNN.png │ ├── WDL.png │ ├── code.png │ ├── code2.jpg │ ├── criteo_sample.png │ ├── deepctrbot.png │ ├── fms.png │ ├── mlr1.png │ ├── mlrvsdnn.png │ ├── movielens_sample.png │ ├── movielens_sample_with_genres.png │ ├── multitaskmodels │ │ ├── ESMM.png │ │ ├── MMOE.png │ │ ├── PLE.png │ │ └── SharedBottom.png │ ├── planet_github.png │ ├── weichennote.png │ └── xDeepFM.png ├── requirements.readthedocs.txt └── source │ ├── Examples.md │ ├── FAQ.md │ ├── Features.md │ ├── History.md │ ├── Layers.rst │ ├── Models.rst │ ├── Quick-Start.md │ ├── conf.py │ ├── deepctr_torch.callbacks.rst │ ├── deepctr_torch.inputs.rst │ ├── deepctr_torch.layers.core.rst │ ├── deepctr_torch.layers.interaction.rst │ ├── deepctr_torch.layers.rst │ ├── deepctr_torch.layers.sequence.rst │ ├── deepctr_torch.layers.utils.rst │ ├── deepctr_torch.models.afm.rst │ ├── deepctr_torch.models.afn.rst │ ├── deepctr_torch.models.autoint.rst │ ├── deepctr_torch.models.basemodel.rst │ ├── deepctr_torch.models.ccpm.rst │ ├── deepctr_torch.models.dcn.rst │ ├── deepctr_torch.models.dcnmix.rst │ ├── deepctr_torch.models.deepfm.rst │ ├── deepctr_torch.models.dien.rst │ ├── deepctr_torch.models.difm.rst │ ├── deepctr_torch.models.din.rst │ ├── deepctr_torch.models.fibinet.rst │ ├── deepctr_torch.models.ifm.rst │ ├── deepctr_torch.models.mlr.rst │ ├── deepctr_torch.models.multitask.esmm.rst │ ├── deepctr_torch.models.multitask.mmoe.rst │ ├── deepctr_torch.models.multitask.ple.rst │ ├── deepctr_torch.models.multitask.sharedbottom.rst │ ├── deepctr_torch.models.nfm.rst │ ├── deepctr_torch.models.onn.rst │ ├── deepctr_torch.models.pnn.rst │ ├── deepctr_torch.models.rst │ ├── deepctr_torch.models.wdl.rst │ ├── deepctr_torch.models.xdeepfm.rst │ ├── deepctr_torch.rst │ ├── deepctr_torch.utils.rst │ ├── index.rst │ └── modules.rst ├── examples ├── byterec_sample.txt ├── criteo_sample.txt ├── movielens_sample.txt ├── run_classification_criteo.py ├── run_dien.py ├── run_din.py ├── run_multitask_learning.py ├── run_multivalue_movielens.py └── run_regression_movielens.py ├── setup.py └── tests ├── __init__.py ├── layers ├── __init__.py └── activation_test.py ├── models ├── AFM_test.py ├── AFN_test.py ├── AutoInt_test.py ├── CCPM_test.py ├── DCNMix_test.py ├── DCN_test.py ├── DIEN_test.py ├── DIFM_test.py ├── DIN_test.py ├── DeepFM_test.py ├── FiBiNET_test.py ├── IFM_test.py ├── MLR_test.py ├── NFM_test.py ├── ONN_test.py ├── PNN_test.py ├── WDL_test.py ├── __init__.py ├── multitask │ ├── ESMM_test.py │ ├── MMOE_test.py │ ├── PLE_test.py │ ├── SharedBottom_test.py │ └── __init__.py └── xDeepFM_test.py ├── utils.py └── utils_mtl.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug(问题描述)** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce(复现步骤)** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Operating environment(运行环境):** 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,] 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement&feature request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask any question ~ 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | Please refer to the [FAQ](https://deepctr-doc.readthedocs.io/en/latest/FAQ.html) in doc and search for the [related issues](https://github.com/shenweichen/DeepCTR-PyTorch/issues) before you ask the question. 10 | 11 | **Describe the question(问题描述)** 12 | A clear and concise description of what the question is. 13 | 14 | **Additional context** 15 | Add any other context about the problem here. 16 | 17 | **Operating environment(运行环境):** 18 | - python version [e.g. 3.6] 19 | - torch version [e.g. 1.10.0,] 20 | - deepctr-torch version [e.g. 0.2.9,] 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | path: 6 | - 'deepctr_torch/*' 7 | - 'tests/*' 8 | pull_request: 9 | path: 10 | - 'deepctr_torch/*' 11 | - 'tests/*' 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 120 18 | strategy: 19 | matrix: 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] 22 | 23 | exclude: 24 | - python-version: 3.6 25 | torch-version: 1.11.0 26 | - python-version: 3.6 27 | torch-version: 1.12.1 28 | - python-version: 3.8 29 | torch-version: 1.2.0 30 | - python-version: 3.8 31 | torch-version: 1.3.0 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 62 | steps: 63 | 64 | - uses: actions/checkout@v3 65 | 66 | - name: Setup python environment 67 | uses: actions/setup-python@v4 68 | with: 69 | python-version: ${{ matrix.python-version }} 70 | 71 | - name: Install dependencies 72 | run: | 73 | pip3 install -q torch==${{ matrix.torch-version }} 74 | pip install -q requests 75 | pip install -e . 76 | - name: Test with pytest 77 | timeout-minutes: 120 78 | run: | 79 | pip install -q pytest 80 | pip install -q pytest-cov 81 | pip install -q python-coveralls 82 | pip install -q sklearn 83 | pytest --cov=deepctr_torch --cov-report=xml 84 | - name: Upload coverage to Codecov 85 | uses: codecov/codecov-action@v3.1.0 86 | with: 87 | token: ${{secrets.CODECOV_TOKEN}} 88 | file: ./coverage.xml 89 | flags: pytest 90 | name: py${{ matrix.python-version }}-torch${{ matrix.torch-version }} 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ckpt 2 | .idea/ 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # celery beat schedule file 95 | celerybeat-schedule 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | .dmypy.json 122 | dmypy.json 123 | 124 | # Pyre type checker 125 | .pyre/ 126 | .DS_Store 127 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This project is under development and we need developers to participate in. 2 | 3 | # Join us 4 | 5 | If you 6 | 7 | - familiar with and interested in CTR models 8 | - familiar with pytorch(both pytorch and tensorflow better) 9 | - have spare time to learn and develop 10 | - familiar with git 11 | 12 | please send a brief introduction of your background and experience to weichenswc@163.com, welcome to join us! 13 | 14 | # Creating a pull request 15 | 1. **Become a collaborator**: Send an email with introduction and your github account name to weichenswc@163.com and waiting for invitation to become a collaborator. 16 | 2. **Fork&Dev**: Fork your own branch(`dev_yourname`) in `DeepCTR-Torch` from the `master` branch for development.If the `master` is updated during the development process, remember to merge and update to `dev_yourname` regularly. 17 | 3. **Testing**: Test logical correctness and effect when finishing the code development of the `dev_yourname` branch. 18 | 4. **Pre-release** : After testing contact weichenswc@163.com for pre-release integration, usually your branch `dev_yourname` will be merged into `release` branch by squash merge. 19 | 5. **Release a new version**: After confirming that the change is no longer needed, `release` branch will be merged into `master` and a new python package will be released on pypi. 20 | -------------------------------------------------------------------------------- /deepctr_torch/__init__.py: -------------------------------------------------------------------------------- 1 | from . import layers 2 | from . import models 3 | from .utils import check_version 4 | 5 | __version__ = '0.2.9' 6 | check_version(__version__) -------------------------------------------------------------------------------- /deepctr_torch/callbacks.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from tensorflow.python.keras.callbacks import EarlyStopping 3 | from tensorflow.python.keras.callbacks import ModelCheckpoint 4 | from tensorflow.python.keras.callbacks import History 5 | 6 | EarlyStopping = EarlyStopping 7 | History = History 8 | 9 | class ModelCheckpoint(ModelCheckpoint): 10 | """Save the model after every epoch. 11 | 12 | `filepath` can contain named formatting options, 13 | which will be filled the value of `epoch` and 14 | keys in `logs` (passed in `on_epoch_end`). 15 | 16 | For example: if `filepath` is `weights.{epoch:02d}-{val_loss:.2f}.hdf5`, 17 | then the model checkpoints will be saved with the epoch number and 18 | the validation loss in the filename. 19 | 20 | Arguments: 21 | filepath: string, path to save the model file. 22 | monitor: quantity to monitor. 23 | verbose: verbosity mode, 0 or 1. 24 | save_best_only: if `save_best_only=True`, 25 | the latest best model according to 26 | the quantity monitored will not be overwritten. 27 | mode: one of {auto, min, max}. 28 | If `save_best_only=True`, the decision 29 | to overwrite the current save file is made 30 | based on either the maximization or the 31 | minimization of the monitored quantity. For `val_acc`, 32 | this should be `max`, for `val_loss` this should 33 | be `min`, etc. In `auto` mode, the direction is 34 | automatically inferred from the name of the monitored quantity. 35 | save_weights_only: if True, then only the model's weights will be 36 | saved (`model.save_weights(filepath)`), else the full model 37 | is saved (`model.save(filepath)`). 38 | period: Interval (number of epochs) between checkpoints. 39 | """ 40 | 41 | def on_epoch_end(self, epoch, logs=None): 42 | logs = logs or {} 43 | self.epochs_since_last_save += 1 44 | if self.epochs_since_last_save >= self.period: 45 | self.epochs_since_last_save = 0 46 | filepath = self.filepath.format(epoch=epoch + 1, **logs) 47 | if self.save_best_only: 48 | current = logs.get(self.monitor) 49 | if current is None: 50 | print('Can save best model only with %s available, skipping.' % self.monitor) 51 | else: 52 | if self.monitor_op(current, self.best): 53 | if self.verbose > 0: 54 | print('Epoch %05d: %s improved from %0.5f to %0.5f,' 55 | ' saving model to %s' % (epoch + 1, self.monitor, self.best, 56 | current, filepath)) 57 | self.best = current 58 | if self.save_weights_only: 59 | torch.save(self.model.state_dict(), filepath) 60 | else: 61 | torch.save(self.model, filepath) 62 | else: 63 | if self.verbose > 0: 64 | print('Epoch %05d: %s did not improve from %0.5f' % 65 | (epoch + 1, self.monitor, self.best)) 66 | else: 67 | if self.verbose > 0: 68 | print('Epoch %05d: saving model to %s' % 69 | (epoch + 1, filepath)) 70 | if self.save_weights_only: 71 | torch.save(self.model.state_dict(), filepath) 72 | else: 73 | torch.save(self.model, filepath) 74 | -------------------------------------------------------------------------------- /deepctr_torch/layers/__init__.py: -------------------------------------------------------------------------------- 1 | from .interaction import * 2 | from .core import * 3 | from .utils import concat_fun 4 | from .sequence import * 5 | -------------------------------------------------------------------------------- /deepctr_torch/layers/activation.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import torch 3 | import torch.nn as nn 4 | 5 | 6 | class Dice(nn.Module): 7 | """The Data Adaptive Activation Function in DIN,which can be viewed as a generalization of PReLu and can adaptively adjust the rectified point according to distribution of input data. 8 | 9 | Input shape: 10 | - 2 dims: [batch_size, embedding_size(features)] 11 | - 3 dims: [batch_size, num_features, embedding_size(features)] 12 | 13 | Output shape: 14 | - Same shape as input. 15 | 16 | References 17 | - [Zhou G, Zhu X, Song C, et al. Deep interest network for click-through rate prediction[C]//Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. ACM, 2018: 1059-1068.](https://arxiv.org/pdf/1706.06978.pdf) 18 | - https://github.com/zhougr1993/DeepInterestNetwork, https://github.com/fanoping/DIN-pytorch 19 | """ 20 | 21 | def __init__(self, emb_size, dim=2, epsilon=1e-8, device='cpu'): 22 | super(Dice, self).__init__() 23 | assert dim == 2 or dim == 3 24 | 25 | self.bn = nn.BatchNorm1d(emb_size, eps=epsilon) 26 | self.sigmoid = nn.Sigmoid() 27 | self.dim = dim 28 | 29 | # wrap alpha in nn.Parameter to make it trainable 30 | if self.dim == 2: 31 | self.alpha = nn.Parameter(torch.zeros((emb_size,)).to(device)) 32 | else: 33 | self.alpha = nn.Parameter(torch.zeros((emb_size, 1)).to(device)) 34 | 35 | def forward(self, x): 36 | assert x.dim() == self.dim 37 | if self.dim == 2: 38 | x_p = self.sigmoid(self.bn(x)) 39 | out = self.alpha * (1 - x_p) * x + x_p * x 40 | else: 41 | x = torch.transpose(x, 1, 2) 42 | x_p = self.sigmoid(self.bn(x)) 43 | out = self.alpha * (1 - x_p) * x + x_p * x 44 | out = torch.transpose(out, 1, 2) 45 | return out 46 | 47 | 48 | class Identity(nn.Module): 49 | 50 | def __init__(self, **kwargs): 51 | super(Identity, self).__init__() 52 | 53 | def forward(self, inputs): 54 | return inputs 55 | 56 | 57 | def activation_layer(act_name, hidden_size=None, dice_dim=2): 58 | """Construct activation layers 59 | 60 | Args: 61 | act_name: str or nn.Module, name of activation function 62 | hidden_size: int, used for Dice activation 63 | dice_dim: int, used for Dice activation 64 | Return: 65 | act_layer: activation layer 66 | """ 67 | if isinstance(act_name, str): 68 | if act_name.lower() == 'sigmoid': 69 | act_layer = nn.Sigmoid() 70 | elif act_name.lower() == 'linear': 71 | act_layer = Identity() 72 | elif act_name.lower() == 'relu': 73 | act_layer = nn.ReLU(inplace=True) 74 | elif act_name.lower() == 'dice': 75 | assert dice_dim 76 | act_layer = Dice(hidden_size, dice_dim) 77 | elif act_name.lower() == 'prelu': 78 | act_layer = nn.PReLU() 79 | elif issubclass(act_name, nn.Module): 80 | act_layer = act_name() 81 | else: 82 | raise NotImplementedError 83 | 84 | return act_layer 85 | 86 | 87 | if __name__ == "__main__": 88 | pass 89 | -------------------------------------------------------------------------------- /deepctr_torch/layers/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 4 | Author: 5 | Weichen Shen,weichenswc@163.com 6 | 7 | """ 8 | import numpy as np 9 | import torch 10 | 11 | 12 | def concat_fun(inputs, axis=-1): 13 | if len(inputs) == 1: 14 | return inputs[0] 15 | else: 16 | return torch.cat(inputs, dim=axis) 17 | 18 | 19 | def slice_arrays(arrays, start=None, stop=None): 20 | """Slice an array or list of arrays. 21 | 22 | This takes an array-like, or a list of 23 | array-likes, and outputs: 24 | - arrays[start:stop] if `arrays` is an array-like 25 | - [x[start:stop] for x in arrays] if `arrays` is a list 26 | 27 | Can also work on list/array of indices: `slice_arrays(x, indices)` 28 | 29 | Arguments: 30 | arrays: Single array or list of arrays. 31 | start: can be an integer index (start index) 32 | or a list/array of indices 33 | stop: integer (stop index); should be None if 34 | `start` was a list. 35 | 36 | Returns: 37 | A slice of the array(s). 38 | 39 | Raises: 40 | ValueError: If the value of start is a list and stop is not None. 41 | """ 42 | 43 | if arrays is None: 44 | return [None] 45 | 46 | if isinstance(arrays, np.ndarray): 47 | arrays = [arrays] 48 | 49 | if isinstance(start, list) and stop is not None: 50 | raise ValueError('The stop argument has to be None if the value of start ' 51 | 'is a list.') 52 | elif isinstance(arrays, list): 53 | if hasattr(start, '__len__'): 54 | # hdf5 datasets only support list objects as indices 55 | if hasattr(start, 'shape'): 56 | start = start.tolist() 57 | return [None if x is None else x[start] for x in arrays] 58 | else: 59 | if len(arrays) == 1: 60 | return arrays[0][start:stop] 61 | return [None if x is None else x[start:stop] for x in arrays] 62 | else: 63 | if hasattr(start, '__len__'): 64 | if hasattr(start, 'shape'): 65 | start = start.tolist() 66 | return arrays[start] 67 | elif hasattr(start, '__getitem__'): 68 | return arrays[start:stop] 69 | else: 70 | return [None] 71 | -------------------------------------------------------------------------------- /deepctr_torch/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .wdl import WDL 2 | from .deepfm import DeepFM 3 | from .xdeepfm import xDeepFM 4 | from .afm import AFM 5 | from .difm import DIFM 6 | from .ifm import IFM 7 | from .autoint import AutoInt 8 | from .dcn import DCN 9 | from .dcnmix import DCNMix 10 | from .fibinet import FiBiNET 11 | from .nfm import NFM 12 | from .mlr import MLR 13 | from .onn import ONN 14 | from .pnn import PNN 15 | from .ccpm import CCPM 16 | from .dien import DIEN 17 | from .din import DIN 18 | from .afn import AFN 19 | from .multitask import SharedBottom, ESMM, MMOE, PLE 20 | -------------------------------------------------------------------------------- /deepctr_torch/models/afm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | Reference: 6 | [1] Xiao J, Ye H, He X, et al. Attentional factorization machines: Learning the weight of feature interactions via attention networks[J]. arXiv preprint arXiv:1708.04617, 2017. 7 | (https://arxiv.org/abs/1708.04617) 8 | """ 9 | import torch 10 | 11 | from .basemodel import BaseModel 12 | from ..layers import FM, AFMLayer 13 | 14 | 15 | class AFM(BaseModel): 16 | """Instantiates the Attentional Factorization Machine architecture. 17 | 18 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 19 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 20 | :param use_attention: bool,whether use attention or not,if set to ``False``.it is the same as **standard Factorization Machine** 21 | :param attention_factor: positive integer,units in attention net 22 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 23 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 24 | :param l2_reg_att: float. L2 regularizer strength applied to attention net 25 | :param afm_dropout: float in [0,1), Fraction of the attention net output units to dropout. 26 | :param init_std: float,to use as the initialize std of embedding vector 27 | :param seed: integer ,to use as random seed. 28 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 29 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 30 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 31 | :return: A PyTorch model instance. 32 | 33 | """ 34 | 35 | def __init__(self, linear_feature_columns, dnn_feature_columns, use_attention=True, attention_factor=8, 36 | l2_reg_linear=1e-5, l2_reg_embedding=1e-5, l2_reg_att=1e-5, afm_dropout=0, init_std=0.0001, seed=1024, 37 | task='binary', device='cpu', gpus=None): 38 | super(AFM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 39 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 40 | device=device, gpus=gpus) 41 | 42 | self.use_attention = use_attention 43 | 44 | if use_attention: 45 | self.fm = AFMLayer(self.embedding_size, attention_factor, l2_reg_att, afm_dropout, 46 | seed, device) 47 | self.add_regularization_weight(self.fm.attention_W, l2=l2_reg_att) 48 | else: 49 | self.fm = FM() 50 | 51 | self.to(device) 52 | 53 | def forward(self, X): 54 | 55 | sparse_embedding_list, _ = self.input_from_feature_columns(X, self.dnn_feature_columns, 56 | self.embedding_dict, support_dense=False) 57 | logit = self.linear_model(X) 58 | if len(sparse_embedding_list) > 0: 59 | if self.use_attention: 60 | logit += self.fm(sparse_embedding_list) 61 | else: 62 | logit += self.fm(torch.cat(sparse_embedding_list, dim=1)) 63 | 64 | y_pred = self.out(logit) 65 | 66 | return y_pred 67 | -------------------------------------------------------------------------------- /deepctr_torch/models/afn.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weiyu Cheng, weiyu_cheng@sjtu.edu.cn 5 | 6 | Reference: 7 | [1] Cheng, W., Shen, Y. and Huang, L. 2020. Adaptive Factorization Network: Learning Adaptive-Order Feature 8 | Interactions. Proceedings of the AAAI Conference on Artificial Intelligence. 34, 04 (Apr. 2020), 3609-3616. 9 | """ 10 | import torch 11 | import torch.nn as nn 12 | 13 | from .basemodel import BaseModel 14 | from ..layers import LogTransformLayer, DNN 15 | 16 | 17 | class AFN(BaseModel): 18 | """Instantiates the Adaptive Factorization Network architecture. 19 | 20 | In DeepCTR-Torch, we only provide the non-ensembled version of AFN for the consistency of model interfaces. For the ensembled version of AFN+, please refer to https://github.com/WeiyuCheng/DeepCTR-Torch (Pytorch Version) or https://github.com/WeiyuCheng/AFN-AAAI-20 (Tensorflow Version). 21 | 22 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 23 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 24 | :param ltl_hidden_size: integer, the number of logarithmic neurons in AFN 25 | :param afn_dnn_hidden_units: list, list of positive integer or empty list, the layer number and units in each layer of DNN layers in AFN 26 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 27 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 28 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 29 | :param init_std: float,to use as the initialize std of embedding vector 30 | :param seed: integer ,to use as random seed. 31 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 32 | :param dnn_activation: Activation function to use in DNN 33 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 34 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 35 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 36 | :return: A PyTorch model instance. 37 | 38 | """ 39 | 40 | def __init__(self, 41 | linear_feature_columns, dnn_feature_columns, 42 | ltl_hidden_size=256, afn_dnn_hidden_units=(256, 128), 43 | l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_dnn=0, 44 | init_std=0.0001, seed=1024, dnn_dropout=0, dnn_activation='relu', 45 | task='binary', device='cpu', gpus=None): 46 | 47 | super(AFN, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 48 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 49 | device=device, gpus=gpus) 50 | 51 | self.ltl = LogTransformLayer(len(self.embedding_dict), self.embedding_size, ltl_hidden_size) 52 | self.afn_dnn = DNN(self.embedding_size * ltl_hidden_size, afn_dnn_hidden_units, 53 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=True, 54 | init_std=init_std, device=device) 55 | self.afn_dnn_linear = nn.Linear(afn_dnn_hidden_units[-1], 1) 56 | self.to(device) 57 | 58 | def forward(self, X): 59 | 60 | sparse_embedding_list, _ = self.input_from_feature_columns(X, self.dnn_feature_columns, 61 | self.embedding_dict) 62 | logit = self.linear_model(X) 63 | if len(sparse_embedding_list) == 0: 64 | raise ValueError('Sparse embeddings not provided. AFN only accepts sparse embeddings as input.') 65 | 66 | afn_input = torch.cat(sparse_embedding_list, dim=1) 67 | ltl_result = self.ltl(afn_input) 68 | afn_logit = self.afn_dnn(ltl_result) 69 | afn_logit = self.afn_dnn_linear(afn_logit) 70 | 71 | logit += afn_logit 72 | y_pred = self.out(logit) 73 | 74 | return y_pred 75 | -------------------------------------------------------------------------------- /deepctr_torch/models/autoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | Reference: 6 | [1] Song W, Shi C, Xiao Z, et al. AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks[J]. arXiv preprint arXiv:1810.11921, 2018.(https://arxiv.org/abs/1810.11921) 7 | """ 8 | import torch 9 | import torch.nn as nn 10 | 11 | from .basemodel import BaseModel 12 | from ..inputs import combined_dnn_input 13 | from ..layers import DNN, concat_fun, InteractingLayer 14 | 15 | 16 | class AutoInt(BaseModel): 17 | """Instantiates the AutoInt Network architecture. 18 | 19 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param att_layer_num: int.The InteractingLayer number to be used. 22 | :param att_head_num: int.The head number in multi-head self-attention network. 23 | :param att_res: bool.Whether or not use standard residual connections before output. 24 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 25 | :param dnn_activation: Activation function to use in DNN 26 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 27 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 28 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in DNN 29 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 30 | :param init_std: float,to use as the initialize std of embedding vector 31 | :param seed: integer ,to use as random seed. 32 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 33 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 34 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 35 | :return: A PyTorch model instance. 36 | 37 | """ 38 | 39 | def __init__(self, linear_feature_columns, dnn_feature_columns, att_layer_num=3, 40 | att_head_num=2, att_res=True, dnn_hidden_units=(256, 128), dnn_activation='relu', 41 | l2_reg_dnn=0, l2_reg_embedding=1e-5, dnn_use_bn=False, dnn_dropout=0, init_std=0.0001, seed=1024, 42 | task='binary', device='cpu', gpus=None): 43 | 44 | super(AutoInt, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=0, 45 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 46 | device=device, gpus=gpus) 47 | if len(dnn_hidden_units) <= 0 and att_layer_num <= 0: 48 | raise ValueError("Either hidden_layer or att_layer_num must > 0") 49 | self.use_dnn = len(dnn_feature_columns) > 0 and len(dnn_hidden_units) > 0 50 | field_num = len(self.embedding_dict) 51 | 52 | embedding_size = self.embedding_size 53 | 54 | if len(dnn_hidden_units) and att_layer_num > 0: 55 | dnn_linear_in_feature = dnn_hidden_units[-1] + field_num * embedding_size 56 | elif len(dnn_hidden_units) > 0: 57 | dnn_linear_in_feature = dnn_hidden_units[-1] 58 | elif att_layer_num > 0: 59 | dnn_linear_in_feature = field_num * embedding_size 60 | else: 61 | raise NotImplementedError 62 | 63 | self.dnn_linear = nn.Linear(dnn_linear_in_feature, 1, bias=False).to(device) 64 | self.dnn_hidden_units = dnn_hidden_units 65 | self.att_layer_num = att_layer_num 66 | if self.use_dnn: 67 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 68 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 69 | init_std=init_std, device=device) 70 | self.add_regularization_weight( 71 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 72 | self.int_layers = nn.ModuleList( 73 | [InteractingLayer(embedding_size, att_head_num, att_res, device=device) for _ in range(att_layer_num)]) 74 | 75 | self.to(device) 76 | 77 | def forward(self, X): 78 | 79 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 80 | self.embedding_dict) 81 | logit = self.linear_model(X) 82 | 83 | att_input = concat_fun(sparse_embedding_list, axis=1) 84 | 85 | for layer in self.int_layers: 86 | att_input = layer(att_input) 87 | 88 | att_output = torch.flatten(att_input, start_dim=1) 89 | 90 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 91 | 92 | if len(self.dnn_hidden_units) > 0 and self.att_layer_num > 0: # Deep & Interacting Layer 93 | deep_out = self.dnn(dnn_input) 94 | stack_out = concat_fun([att_output, deep_out]) 95 | logit += self.dnn_linear(stack_out) 96 | elif len(self.dnn_hidden_units) > 0: # Only Deep 97 | deep_out = self.dnn(dnn_input) 98 | logit += self.dnn_linear(deep_out) 99 | elif self.att_layer_num > 0: # Only Interacting Layer 100 | logit += self.dnn_linear(att_output) 101 | else: # Error 102 | pass 103 | 104 | y_pred = self.out(logit) 105 | 106 | return y_pred 107 | -------------------------------------------------------------------------------- /deepctr_torch/models/ccpm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | 4 | Author: 5 | Zeng Kai,kk163mail@126.com 6 | 7 | Reference: 8 | [1] Liu Q, Yu F, Wu S, et al. A convolutional click prediction model[C]//Proceedings of the 24th ACM International on Conference on Information and Knowledge Management. ACM, 2015: 1743-1746. 9 | (http://ir.ia.ac.cn/bitstream/173211/12337/1/A%20Convolutional%20Click%20Prediction%20Model.pdf) 10 | 11 | """ 12 | import torch 13 | import torch.nn as nn 14 | 15 | from .basemodel import BaseModel 16 | from ..layers.core import DNN 17 | from ..layers.interaction import ConvLayer 18 | from ..layers.utils import concat_fun 19 | 20 | 21 | class CCPM(BaseModel): 22 | """Instantiates the Convolutional Click Prediction Model architecture. 23 | 24 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 25 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 26 | :param conv_kernel_width: list,list of positive integer or empty list,the width of filter in each conv layer. 27 | :param conv_filters: list,list of positive integer or empty list,the number of filters in each conv layer. 28 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN. 29 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 30 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 31 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 32 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 33 | :param init_std: float,to use as the initialize std of embedding vector 34 | :param seed: integer ,to use as random seed. 35 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 36 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 37 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 38 | :return: A PyTorch model instance. 39 | 40 | """ 41 | 42 | def __init__(self, linear_feature_columns, dnn_feature_columns, conv_kernel_width=(6, 5), 43 | conv_filters=(4, 4), 44 | dnn_hidden_units=(256,), l2_reg_linear=1e-5, l2_reg_embedding=1e-5, l2_reg_dnn=0, dnn_dropout=0, 45 | init_std=0.0001, seed=1024, task='binary', device='cpu', dnn_use_bn=False, dnn_activation='relu', gpus=None): 46 | 47 | super(CCPM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 48 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 49 | device=device, gpus=gpus) 50 | 51 | if len(conv_kernel_width) != len(conv_filters): 52 | raise ValueError( 53 | "conv_kernel_width must have same element with conv_filters") 54 | 55 | filed_size = self.compute_input_dim(dnn_feature_columns, include_dense=False, feature_group=True) 56 | self.conv_layer = ConvLayer(field_size=filed_size, conv_kernel_width=conv_kernel_width, 57 | conv_filters=conv_filters, device=device) 58 | self.dnn_input_dim = self.conv_layer.filed_shape * self.embedding_size * conv_filters[-1] 59 | self.dnn = DNN(self.dnn_input_dim, dnn_hidden_units, 60 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 61 | init_std=init_std, device=device) 62 | self.dnn_linear = nn.Linear(dnn_hidden_units[-1], 1, bias=False).to(device) 63 | self.add_regularization_weight( 64 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 65 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_dnn) 66 | 67 | self.to(device) 68 | 69 | def forward(self, X): 70 | linear_logit = self.linear_model(X) 71 | sparse_embedding_list, _ = self.input_from_feature_columns(X, self.dnn_feature_columns, 72 | self.embedding_dict, support_dense=False) 73 | if len(sparse_embedding_list) == 0: 74 | raise ValueError("must have the embedding feature,now the embedding feature is None!") 75 | conv_input = concat_fun(sparse_embedding_list, axis=1) 76 | conv_input_concact = torch.unsqueeze(conv_input, 1) 77 | pooling_result = self.conv_layer(conv_input_concact) 78 | flatten_result = pooling_result.view(pooling_result.size(0), -1) 79 | dnn_output = self.dnn(flatten_result) 80 | dnn_logit = self.dnn_linear(dnn_output) 81 | logit = linear_logit + dnn_logit 82 | y_pred = self.out(logit) 83 | return y_pred 84 | -------------------------------------------------------------------------------- /deepctr_torch/models/dcn.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | chen_kkkk, bgasdo36977@gmail.com 5 | 6 | zanshuxun, zanshuxun@aliyun.com 7 | Reference: 8 | [1] Wang R, Fu B, Fu G, et al. Deep & cross network for ad click predictions[C]//Proceedings of the ADKDD'17. ACM, 2017: 12. (https://arxiv.org/abs/1708.05123) 9 | 10 | [2] Wang R, Shivanna R, Cheng D Z, et al. DCN-M: Improved Deep & Cross Network for Feature Cross Learning in Web-scale Learning to Rank Systems[J]. 2020. (https://arxiv.org/abs/2008.13535) 11 | """ 12 | import torch 13 | import torch.nn as nn 14 | 15 | from .basemodel import BaseModel 16 | from ..inputs import combined_dnn_input 17 | from ..layers import CrossNet, DNN 18 | 19 | 20 | class DCN(BaseModel): 21 | """Instantiates the Deep&Cross Network architecture. Including DCN-V (parameterization='vector') 22 | and DCN-M (parameterization='matrix'). 23 | 24 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 25 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 26 | :param cross_num: positive integet,cross layer number 27 | :param cross_parameterization: str, ``"vector"`` or ``"matrix"``, how to parameterize the cross network. 28 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 29 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 30 | :param l2_reg_cross: float. L2 regularizer strength applied to cross net 31 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 32 | :param init_std: float,to use as the initialize std of embedding vector 33 | :param seed: integer ,to use as random seed. 34 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 35 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not DNN 36 | :param dnn_activation: Activation function to use in DNN 37 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 38 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 39 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 40 | :return: A PyTorch model instance. 41 | 42 | """ 43 | 44 | def __init__(self, linear_feature_columns, dnn_feature_columns, cross_num=2, cross_parameterization='vector', 45 | dnn_hidden_units=(128, 128), l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_cross=0.00001, 46 | l2_reg_dnn=0, init_std=0.0001, seed=1024, dnn_dropout=0, dnn_activation='relu', dnn_use_bn=False, 47 | task='binary', device='cpu', gpus=None): 48 | 49 | super(DCN, self).__init__(linear_feature_columns=linear_feature_columns, 50 | dnn_feature_columns=dnn_feature_columns, l2_reg_embedding=l2_reg_embedding, 51 | init_std=init_std, seed=seed, task=task, device=device, gpus=gpus) 52 | self.dnn_hidden_units = dnn_hidden_units 53 | self.cross_num = cross_num 54 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 55 | activation=dnn_activation, use_bn=dnn_use_bn, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, 56 | init_std=init_std, device=device) 57 | if len(self.dnn_hidden_units) > 0 and self.cross_num > 0: 58 | dnn_linear_in_feature = self.compute_input_dim(dnn_feature_columns) + dnn_hidden_units[-1] 59 | elif len(self.dnn_hidden_units) > 0: 60 | dnn_linear_in_feature = dnn_hidden_units[-1] 61 | elif self.cross_num > 0: 62 | dnn_linear_in_feature = self.compute_input_dim(dnn_feature_columns) 63 | 64 | self.dnn_linear = nn.Linear(dnn_linear_in_feature, 1, bias=False).to( 65 | device) 66 | self.crossnet = CrossNet(in_features=self.compute_input_dim(dnn_feature_columns), 67 | layer_num=cross_num, parameterization=cross_parameterization, device=device) 68 | self.add_regularization_weight( 69 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 70 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_linear) 71 | self.add_regularization_weight(self.crossnet.kernels, l2=l2_reg_cross) 72 | self.to(device) 73 | 74 | def forward(self, X): 75 | 76 | logit = self.linear_model(X) 77 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 78 | self.embedding_dict) 79 | 80 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 81 | 82 | if len(self.dnn_hidden_units) > 0 and self.cross_num > 0: # Deep & Cross 83 | deep_out = self.dnn(dnn_input) 84 | cross_out = self.crossnet(dnn_input) 85 | stack_out = torch.cat((cross_out, deep_out), dim=-1) 86 | logit += self.dnn_linear(stack_out) 87 | elif len(self.dnn_hidden_units) > 0: # Only Deep 88 | deep_out = self.dnn(dnn_input) 89 | logit += self.dnn_linear(deep_out) 90 | elif self.cross_num > 0: # Only Cross 91 | cross_out = self.crossnet(dnn_input) 92 | logit += self.dnn_linear(cross_out) 93 | else: # Error 94 | pass 95 | y_pred = self.out(logit) 96 | return y_pred 97 | -------------------------------------------------------------------------------- /deepctr_torch/models/dcnmix.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | chen_kkkk, bgasdo36977@gmail.com 5 | 6 | zanshuxun, zanshuxun@aliyun.com 7 | Reference: 8 | [1] Wang R, Fu B, Fu G, et al. Deep & cross network for ad click predictions[C]//Proceedings of the ADKDD'17. ACM, 2017: 12. (https://arxiv.org/abs/1708.05123) 9 | 10 | [2] Wang R, Shivanna R, Cheng D Z, et al. DCN-M: Improved Deep & Cross Network for Feature Cross Learning in Web-scale Learning to Rank Systems[J]. 2020. (https://arxiv.org/abs/2008.13535) 11 | """ 12 | import torch 13 | import torch.nn as nn 14 | 15 | from .basemodel import BaseModel 16 | from ..inputs import combined_dnn_input 17 | from ..layers import CrossNetMix, DNN 18 | 19 | 20 | class DCNMix(BaseModel): 21 | """Instantiates the DCN-Mix model. 22 | 23 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 24 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 25 | :param cross_num: positive integet,cross layer number 26 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 27 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 28 | :param l2_reg_cross: float. L2 regularizer strength applied to cross net 29 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 30 | :param init_std: float,to use as the initialize std of embedding vector 31 | :param seed: integer ,to use as random seed. 32 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 33 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not DNN 34 | :param dnn_activation: Activation function to use in DNN 35 | :param low_rank: Positive integer, dimensionality of low-rank sapce. 36 | :param num_experts: Positive integer, number of experts. 37 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 38 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 39 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 40 | :return: A PyTorch model instance. 41 | 42 | """ 43 | 44 | def __init__(self, linear_feature_columns, 45 | dnn_feature_columns, cross_num=2, 46 | dnn_hidden_units=(128, 128), l2_reg_linear=0.00001, 47 | l2_reg_embedding=0.00001, l2_reg_cross=0.00001, l2_reg_dnn=0, init_std=0.0001, seed=1024, 48 | dnn_dropout=0, low_rank=32, num_experts=4, 49 | dnn_activation='relu', dnn_use_bn=False, task='binary', device='cpu', gpus=None): 50 | 51 | super(DCNMix, self).__init__(linear_feature_columns=linear_feature_columns, 52 | dnn_feature_columns=dnn_feature_columns, l2_reg_embedding=l2_reg_embedding, 53 | init_std=init_std, seed=seed, task=task, device=device, gpus=gpus) 54 | self.dnn_hidden_units = dnn_hidden_units 55 | self.cross_num = cross_num 56 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 57 | activation=dnn_activation, use_bn=dnn_use_bn, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, 58 | init_std=init_std, device=device) 59 | if len(self.dnn_hidden_units) > 0 and self.cross_num > 0: 60 | dnn_linear_in_feature = self.compute_input_dim(dnn_feature_columns) + dnn_hidden_units[-1] 61 | elif len(self.dnn_hidden_units) > 0: 62 | dnn_linear_in_feature = dnn_hidden_units[-1] 63 | elif self.cross_num > 0: 64 | dnn_linear_in_feature = self.compute_input_dim(dnn_feature_columns) 65 | 66 | self.dnn_linear = nn.Linear(dnn_linear_in_feature, 1, bias=False).to( 67 | device) 68 | self.crossnet = CrossNetMix(in_features=self.compute_input_dim(dnn_feature_columns), 69 | low_rank=low_rank, num_experts=num_experts, 70 | layer_num=cross_num, device=device) 71 | self.add_regularization_weight( 72 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 73 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_linear) 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 | 78 | self.to(device) 79 | 80 | def forward(self, X): 81 | 82 | logit = self.linear_model(X) 83 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 84 | self.embedding_dict) 85 | 86 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 87 | 88 | if len(self.dnn_hidden_units) > 0 and self.cross_num > 0: # Deep & Cross 89 | deep_out = self.dnn(dnn_input) 90 | cross_out = self.crossnet(dnn_input) 91 | stack_out = torch.cat((cross_out, deep_out), dim=-1) 92 | logit += self.dnn_linear(stack_out) 93 | elif len(self.dnn_hidden_units) > 0: # Only Deep 94 | deep_out = self.dnn(dnn_input) 95 | logit += self.dnn_linear(deep_out) 96 | elif self.cross_num > 0: # Only Cross 97 | cross_out = self.crossnet(dnn_input) 98 | logit += self.dnn_linear(cross_out) 99 | else: # Error 100 | pass 101 | y_pred = self.out(logit) 102 | return y_pred 103 | -------------------------------------------------------------------------------- /deepctr_torch/models/deepfm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | Reference: 6 | [1] Guo H, Tang R, Ye Y, et al. Deepfm: a factorization-machine based neural network for ctr prediction[J]. arXiv preprint arXiv:1703.04247, 2017.(https://arxiv.org/abs/1703.04247) 7 | """ 8 | import torch 9 | import torch.nn as nn 10 | 11 | from .basemodel import BaseModel 12 | from ..inputs import combined_dnn_input 13 | from ..layers import FM, DNN 14 | 15 | 16 | class DeepFM(BaseModel): 17 | """Instantiates the DeepFM Network architecture. 18 | 19 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param use_fm: bool,use FM part or not 22 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 23 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 24 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 25 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 26 | :param init_std: float,to use as the initialize std of embedding vector 27 | :param seed: integer ,to use as random seed. 28 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 29 | :param dnn_activation: Activation function to use in DNN 30 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in DNN 31 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 32 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 33 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 34 | :return: A PyTorch model instance. 35 | 36 | """ 37 | 38 | def __init__(self, 39 | linear_feature_columns, dnn_feature_columns, use_fm=True, 40 | dnn_hidden_units=(256, 128), 41 | l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_dnn=0, init_std=0.0001, seed=1024, 42 | dnn_dropout=0, 43 | dnn_activation='relu', dnn_use_bn=False, task='binary', device='cpu', gpus=None): 44 | 45 | super(DeepFM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 46 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 47 | device=device, gpus=gpus) 48 | 49 | self.use_fm = use_fm 50 | self.use_dnn = len(dnn_feature_columns) > 0 and len( 51 | dnn_hidden_units) > 0 52 | if use_fm: 53 | self.fm = FM() 54 | 55 | if self.use_dnn: 56 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 57 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 58 | init_std=init_std, device=device) 59 | self.dnn_linear = nn.Linear( 60 | dnn_hidden_units[-1], 1, bias=False).to(device) 61 | 62 | self.add_regularization_weight( 63 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 64 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_dnn) 65 | self.to(device) 66 | 67 | def forward(self, X): 68 | 69 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 70 | self.embedding_dict) 71 | logit = self.linear_model(X) 72 | 73 | if self.use_fm and len(sparse_embedding_list) > 0: 74 | fm_input = torch.cat(sparse_embedding_list, dim=1) 75 | logit += self.fm(fm_input) 76 | 77 | if self.use_dnn: 78 | dnn_input = combined_dnn_input( 79 | sparse_embedding_list, dense_value_list) 80 | dnn_output = self.dnn(dnn_input) 81 | dnn_logit = self.dnn_linear(dnn_output) 82 | logit += dnn_logit 83 | 84 | y_pred = self.out(logit) 85 | 86 | return y_pred 87 | -------------------------------------------------------------------------------- /deepctr_torch/models/difm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | zanshuxun, zanshuxun@aliyun.com 5 | Reference: 6 | [1] Lu W, Yu Y, Chang Y, et al. A Dual Input-aware Factorization Machine for CTR Prediction[C]//IJCAI. 2020: 3139-3145.(https://www.ijcai.org/Proceedings/2020/0434.pdf) 7 | """ 8 | import torch 9 | import torch.nn as nn 10 | 11 | from .basemodel import BaseModel 12 | from ..inputs import combined_dnn_input, SparseFeat, VarLenSparseFeat 13 | from ..layers import FM, DNN, InteractingLayer, concat_fun 14 | 15 | 16 | class DIFM(BaseModel): 17 | """Instantiates the DIFM Network architecture. 18 | 19 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param att_head_num: int. The head number in multi-head self-attention network. 22 | :param att_res: bool. Whether or not use standard residual connections before output. 23 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 24 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 25 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 26 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 27 | :param init_std: float,to use as the initialize std of embedding vector 28 | :param seed: integer ,to use as random seed. 29 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 30 | :param dnn_activation: Activation function to use in DNN 31 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in DNN 32 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 33 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 34 | :param gpus: list of int or torch.device for multiple gpus. If None, run on ``device`` . ``gpus[0]`` should be the same gpu with ``device`` . 35 | :return: A PyTorch model instance. 36 | 37 | """ 38 | 39 | def __init__(self, 40 | linear_feature_columns, dnn_feature_columns, att_head_num=4, 41 | att_res=True, dnn_hidden_units=(256, 128), 42 | l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_dnn=0, init_std=0.0001, seed=1024, 43 | dnn_dropout=0, 44 | dnn_activation='relu', dnn_use_bn=False, task='binary', device='cpu', gpus=None): 45 | super(DIFM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 46 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 47 | device=device, gpus=gpus) 48 | 49 | if not len(dnn_hidden_units) > 0: 50 | raise ValueError("dnn_hidden_units is null!") 51 | 52 | self.fm = FM() 53 | 54 | # InteractingLayer (used in AutoInt) = multi-head self-attention + Residual Network 55 | self.vector_wise_net = InteractingLayer(self.embedding_size, att_head_num, 56 | att_res, scaling=True, device=device) 57 | 58 | self.bit_wise_net = DNN(self.compute_input_dim(dnn_feature_columns, include_dense=False), 59 | dnn_hidden_units, activation=dnn_activation, l2_reg=l2_reg_dnn, 60 | dropout_rate=dnn_dropout, 61 | use_bn=dnn_use_bn, init_std=init_std, device=device) 62 | self.sparse_feat_num = len(list(filter(lambda x: isinstance(x, SparseFeat) or isinstance(x, VarLenSparseFeat), 63 | dnn_feature_columns))) 64 | 65 | self.transform_matrix_P_vec = nn.Linear( 66 | self.sparse_feat_num * self.embedding_size, self.sparse_feat_num, bias=False).to(device) 67 | self.transform_matrix_P_bit = nn.Linear( 68 | dnn_hidden_units[-1], self.sparse_feat_num, bias=False).to(device) 69 | 70 | self.add_regularization_weight( 71 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.vector_wise_net.named_parameters()), 72 | l2=l2_reg_dnn) 73 | self.add_regularization_weight( 74 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.bit_wise_net.named_parameters()), 75 | l2=l2_reg_dnn) 76 | self.add_regularization_weight(self.transform_matrix_P_vec.weight, l2=l2_reg_dnn) 77 | self.add_regularization_weight(self.transform_matrix_P_bit.weight, l2=l2_reg_dnn) 78 | 79 | self.to(device) 80 | 81 | def forward(self, X): 82 | sparse_embedding_list, _ = self.input_from_feature_columns(X, self.dnn_feature_columns, 83 | self.embedding_dict) 84 | if not len(sparse_embedding_list) > 0: 85 | raise ValueError("there are no sparse features") 86 | 87 | att_input = concat_fun(sparse_embedding_list, axis=1) 88 | att_out = self.vector_wise_net(att_input) 89 | att_out = att_out.reshape(att_out.shape[0], -1) 90 | m_vec = self.transform_matrix_P_vec(att_out) 91 | 92 | dnn_input = combined_dnn_input(sparse_embedding_list, []) 93 | dnn_output = self.bit_wise_net(dnn_input) 94 | m_bit = self.transform_matrix_P_bit(dnn_output) 95 | 96 | m_x = m_vec + m_bit # m_x is the complete input-aware factor 97 | 98 | logit = self.linear_model(X, sparse_feat_refine_weight=m_x) 99 | 100 | fm_input = torch.cat(sparse_embedding_list, dim=1) 101 | refined_fm_input = fm_input * m_x.unsqueeze(-1) # \textbf{v}_{x,i}=m_{x,i} * \textbf{v}_i 102 | logit += self.fm(refined_fm_input) 103 | 104 | y_pred = self.out(logit) 105 | 106 | return y_pred 107 | -------------------------------------------------------------------------------- /deepctr_torch/models/din.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Yuef Zhang 5 | Reference: 6 | [1] Zhou G, Zhu X, Song C, et al. Deep interest network for click-through rate prediction[C]//Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. ACM, 2018: 1059-1068. (https://arxiv.org/pdf/1706.06978.pdf) 7 | """ 8 | 9 | from .basemodel import BaseModel 10 | from ..inputs import * 11 | from ..layers import * 12 | from ..layers.sequence import AttentionSequencePoolingLayer 13 | 14 | 15 | class DIN(BaseModel): 16 | """Instantiates the Deep Interest Network architecture. 17 | 18 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 19 | :param history_feature_list: list,to indicate sequence sparse field 20 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in deep net 21 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of deep net 22 | :param dnn_activation: Activation function to use in deep net 23 | :param att_hidden_size: list,list of positive integer , the layer number and units in each layer of attention net 24 | :param att_activation: Activation function to use in attention net 25 | :param att_weight_normalization: bool. Whether normalize the attention score of local activation unit. 26 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 27 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 28 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 29 | :param init_std: float,to use as the initialize std of embedding vector 30 | :param seed: integer ,to use as random seed. 31 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 32 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 33 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 34 | :return: A PyTorch model instance. 35 | 36 | """ 37 | 38 | def __init__(self, dnn_feature_columns, history_feature_list, dnn_use_bn=False, 39 | dnn_hidden_units=(256, 128), dnn_activation='relu', att_hidden_size=(64, 16), 40 | att_activation='Dice', att_weight_normalization=False, l2_reg_dnn=0.0, 41 | l2_reg_embedding=1e-6, dnn_dropout=0, init_std=0.0001, 42 | seed=1024, task='binary', device='cpu', gpus=None): 43 | super(DIN, self).__init__([], dnn_feature_columns, l2_reg_linear=0, l2_reg_embedding=l2_reg_embedding, 44 | init_std=init_std, seed=seed, task=task, device=device, gpus=gpus) 45 | 46 | self.sparse_feature_columns = list( 47 | filter(lambda x: isinstance(x, SparseFeat), dnn_feature_columns)) if dnn_feature_columns else [] 48 | self.varlen_sparse_feature_columns = list( 49 | filter(lambda x: isinstance(x, VarLenSparseFeat), dnn_feature_columns)) if dnn_feature_columns else [] 50 | 51 | self.history_feature_list = history_feature_list 52 | 53 | self.history_feature_columns = [] 54 | self.sparse_varlen_feature_columns = [] 55 | self.history_fc_names = list(map(lambda x: "hist_" + x, history_feature_list)) 56 | 57 | for fc in self.varlen_sparse_feature_columns: 58 | feature_name = fc.name 59 | if feature_name in self.history_fc_names: 60 | self.history_feature_columns.append(fc) 61 | else: 62 | self.sparse_varlen_feature_columns.append(fc) 63 | 64 | att_emb_dim = self._compute_interest_dim() 65 | 66 | self.attention = AttentionSequencePoolingLayer(att_hidden_units=att_hidden_size, 67 | embedding_dim=att_emb_dim, 68 | att_activation=att_activation, 69 | return_score=False, 70 | supports_masking=False, 71 | weight_normalization=att_weight_normalization) 72 | 73 | self.dnn = DNN(inputs_dim=self.compute_input_dim(dnn_feature_columns), 74 | hidden_units=dnn_hidden_units, 75 | activation=dnn_activation, 76 | dropout_rate=dnn_dropout, 77 | l2_reg=l2_reg_dnn, 78 | use_bn=dnn_use_bn) 79 | self.dnn_linear = nn.Linear(dnn_hidden_units[-1], 1, bias=False).to(device) 80 | self.to(device) 81 | 82 | 83 | def forward(self, X): 84 | _, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, self.embedding_dict) 85 | 86 | # sequence pooling part 87 | query_emb_list = embedding_lookup(X, self.embedding_dict, self.feature_index, self.sparse_feature_columns, 88 | return_feat_list=self.history_feature_list, to_list=True) 89 | keys_emb_list = embedding_lookup(X, self.embedding_dict, self.feature_index, self.history_feature_columns, 90 | return_feat_list=self.history_fc_names, to_list=True) 91 | dnn_input_emb_list = embedding_lookup(X, self.embedding_dict, self.feature_index, self.sparse_feature_columns, 92 | to_list=True) 93 | 94 | sequence_embed_dict = varlen_embedding_lookup(X, self.embedding_dict, self.feature_index, 95 | self.sparse_varlen_feature_columns) 96 | 97 | sequence_embed_list = get_varlen_pooling_list(sequence_embed_dict, X, self.feature_index, 98 | self.sparse_varlen_feature_columns, self.device) 99 | 100 | dnn_input_emb_list += sequence_embed_list 101 | deep_input_emb = torch.cat(dnn_input_emb_list, dim=-1) 102 | 103 | # concatenate 104 | query_emb = torch.cat(query_emb_list, dim=-1) # [B, 1, E] 105 | keys_emb = torch.cat(keys_emb_list, dim=-1) # [B, T, E] 106 | 107 | keys_length_feature_name = [feat.length_name for feat in self.varlen_sparse_feature_columns if 108 | feat.length_name is not None] 109 | keys_length = torch.squeeze(maxlen_lookup(X, self.feature_index, keys_length_feature_name), 1) # [B, 1] 110 | 111 | hist = self.attention(query_emb, keys_emb, keys_length) # [B, 1, E] 112 | 113 | # deep part 114 | deep_input_emb = torch.cat((deep_input_emb, hist), dim=-1) 115 | deep_input_emb = deep_input_emb.view(deep_input_emb.size(0), -1) 116 | 117 | dnn_input = combined_dnn_input([deep_input_emb], dense_value_list) 118 | dnn_output = self.dnn(dnn_input) 119 | dnn_logit = self.dnn_linear(dnn_output) 120 | 121 | y_pred = self.out(dnn_logit) 122 | 123 | return y_pred 124 | 125 | def _compute_interest_dim(self): 126 | interest_dim = 0 127 | for feat in self.sparse_feature_columns: 128 | if feat.name in self.history_feature_list: 129 | interest_dim += feat.embedding_dim 130 | return interest_dim 131 | 132 | 133 | if __name__ == '__main__': 134 | pass 135 | -------------------------------------------------------------------------------- /deepctr_torch/models/fibinet.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Wutong Zhang 5 | Reference: 6 | [1] Huang T, Zhang Z, Zhang J. FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction[J]. arXiv preprint arXiv:1905.09433, 2019. 7 | """ 8 | 9 | import torch 10 | import torch.nn as nn 11 | 12 | from .basemodel import BaseModel 13 | from ..inputs import combined_dnn_input, SparseFeat, DenseFeat, VarLenSparseFeat 14 | from ..layers import SENETLayer, BilinearInteraction, DNN 15 | 16 | 17 | class FiBiNET(BaseModel): 18 | """Instantiates the Feature Importance and Bilinear feature Interaction NETwork architecture. 19 | 20 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 21 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 22 | :param bilinear_type: str,bilinear function type used in Bilinear Interaction Layer,can be ``'all'`` , ``'each'`` or ``'interaction'`` 23 | :param reduction_ratio: integer in [1,inf), reduction ratio used in SENET Layer 24 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 25 | :param l2_reg_linear: float. L2 regularizer strength applied to wide part 26 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 27 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 28 | :param init_std: float,to use as the initialize std of embedding vector 29 | :param seed: integer ,to use as random seed. 30 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 31 | :param dnn_activation: Activation function to use in DNN 32 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 33 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 34 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 35 | :return: A PyTorch model instance. 36 | 37 | """ 38 | 39 | def __init__(self, linear_feature_columns, dnn_feature_columns, bilinear_type='interaction', 40 | reduction_ratio=3, dnn_hidden_units=(128, 128), l2_reg_linear=1e-5, 41 | l2_reg_embedding=1e-5, l2_reg_dnn=0, init_std=0.0001, seed=1024, dnn_dropout=0, dnn_activation='relu', 42 | task='binary', device='cpu', gpus=None): 43 | super(FiBiNET, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 44 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 45 | device=device, gpus=gpus) 46 | self.linear_feature_columns = linear_feature_columns 47 | self.dnn_feature_columns = dnn_feature_columns 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) 51 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 52 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=False, 53 | init_std=init_std, device=device) 54 | self.dnn_linear = nn.Linear(dnn_hidden_units[-1], 1, bias=False).to(device) 55 | 56 | def compute_input_dim(self, feature_columns, include_sparse=True, include_dense=True): 57 | sparse_feature_columns = list( 58 | filter(lambda x: isinstance(x, (SparseFeat, VarLenSparseFeat)), feature_columns)) if len( 59 | feature_columns) else [] 60 | dense_feature_columns = list( 61 | filter(lambda x: isinstance(x, DenseFeat), feature_columns)) if len(feature_columns) else [] 62 | field_size = len(sparse_feature_columns) 63 | 64 | dense_input_dim = sum(map(lambda x: x.dimension, dense_feature_columns)) 65 | embedding_size = sparse_feature_columns[0].embedding_dim 66 | sparse_input_dim = field_size * (field_size - 1) * embedding_size 67 | input_dim = 0 68 | 69 | if include_sparse: 70 | input_dim += sparse_input_dim 71 | if include_dense: 72 | input_dim += dense_input_dim 73 | 74 | return input_dim 75 | 76 | def forward(self, X): 77 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 78 | self.embedding_dict) 79 | sparse_embedding_input = torch.cat(sparse_embedding_list, dim=1) 80 | 81 | senet_output = self.SE(sparse_embedding_input) 82 | senet_bilinear_out = self.Bilinear(senet_output) 83 | bilinear_out = self.Bilinear(sparse_embedding_input) 84 | 85 | linear_logit = self.linear_model(X) 86 | temp = torch.split(torch.cat((senet_bilinear_out, bilinear_out), dim=1), 1, dim=1) 87 | dnn_input = combined_dnn_input(temp, dense_value_list) 88 | dnn_output = self.dnn(dnn_input) 89 | dnn_logit = self.dnn_linear(dnn_output) 90 | 91 | if len(self.linear_feature_columns) > 0 and len(self.dnn_feature_columns) > 0: # linear + dnn 92 | final_logit = linear_logit + dnn_logit 93 | elif len(self.linear_feature_columns) == 0: 94 | final_logit = dnn_logit 95 | elif len(self.dnn_feature_columns) == 0: 96 | final_logit = linear_logit 97 | else: 98 | raise NotImplementedError 99 | 100 | y_pred = self.out(final_logit) 101 | 102 | return y_pred 103 | -------------------------------------------------------------------------------- /deepctr_torch/models/ifm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | zanshuxun, zanshuxun@aliyun.com 5 | Reference: 6 | [1] Yu Y, Wang Z, Yuan B. An Input-aware Factorization Machine for Sparse Prediction[C]//IJCAI. 2019: 1466-1472.(https://www.ijcai.org/Proceedings/2019/0203.pdf) 7 | """ 8 | import torch 9 | import torch.nn as nn 10 | 11 | from .basemodel import BaseModel 12 | from ..inputs import combined_dnn_input, SparseFeat, VarLenSparseFeat 13 | from ..layers import FM, DNN 14 | 15 | 16 | class IFM(BaseModel): 17 | """Instantiates the IFM Network architecture. 18 | 19 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 22 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 23 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 24 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 25 | :param init_std: float,to use as the initialize std of embedding vector 26 | :param seed: integer ,to use as random seed. 27 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 28 | :param dnn_activation: Activation function to use in DNN 29 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in DNN 30 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 31 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 32 | :param gpus: list of int or torch.device for multiple gpus. If None, run on ``device`` . ``gpus[0]`` should be the same gpu with ``device`` . 33 | :return: A PyTorch model instance. 34 | 35 | """ 36 | 37 | def __init__(self, 38 | linear_feature_columns, dnn_feature_columns, 39 | dnn_hidden_units=(256, 128), 40 | l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_dnn=0, init_std=0.0001, seed=1024, 41 | dnn_dropout=0, 42 | dnn_activation='relu', dnn_use_bn=False, task='binary', device='cpu', gpus=None): 43 | super(IFM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 44 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 45 | device=device, gpus=gpus) 46 | 47 | if not len(dnn_hidden_units) > 0: 48 | raise ValueError("dnn_hidden_units is null!") 49 | 50 | self.fm = FM() 51 | 52 | self.factor_estimating_net = DNN(self.compute_input_dim(dnn_feature_columns, include_dense=False), 53 | dnn_hidden_units, activation=dnn_activation, l2_reg=l2_reg_dnn, 54 | dropout_rate=dnn_dropout, 55 | use_bn=dnn_use_bn, init_std=init_std, device=device) 56 | self.sparse_feat_num = len(list(filter(lambda x: isinstance(x, SparseFeat) or isinstance(x, VarLenSparseFeat), 57 | dnn_feature_columns))) 58 | self.transform_weight_matrix_P = nn.Linear( 59 | dnn_hidden_units[-1], self.sparse_feat_num, bias=False).to(device) 60 | 61 | self.add_regularization_weight( 62 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.factor_estimating_net.named_parameters()), 63 | l2=l2_reg_dnn) 64 | self.add_regularization_weight(self.transform_weight_matrix_P.weight, l2=l2_reg_dnn) 65 | 66 | self.to(device) 67 | 68 | def forward(self, X): 69 | sparse_embedding_list, _ = self.input_from_feature_columns(X, self.dnn_feature_columns, 70 | self.embedding_dict) 71 | if not len(sparse_embedding_list) > 0: 72 | raise ValueError("there are no sparse features") 73 | 74 | dnn_input = combined_dnn_input(sparse_embedding_list, []) # (batch_size, feat_num * embedding_size) 75 | dnn_output = self.factor_estimating_net(dnn_input) 76 | dnn_output = self.transform_weight_matrix_P(dnn_output) # m'_{x} 77 | input_aware_factor = self.sparse_feat_num * dnn_output.softmax(1) # input_aware_factor m_{x,i} 78 | 79 | logit = self.linear_model(X, sparse_feat_refine_weight=input_aware_factor) 80 | 81 | fm_input = torch.cat(sparse_embedding_list, dim=1) 82 | refined_fm_input = fm_input * input_aware_factor.unsqueeze(-1) # \textbf{v}_{x,i}=m_{x,i}\textbf{v}_i 83 | logit += self.fm(refined_fm_input) 84 | 85 | y_pred = self.out(logit) 86 | 87 | return y_pred 88 | -------------------------------------------------------------------------------- /deepctr_torch/models/mlr.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Wutong Zhang 5 | Weichen Shen,weichenswc@163.com 6 | Reference: 7 | [1] Gai K, Zhu X, Li H, et al. Learning Piece-wise Linear Models from Large Scale Data for Ad Click Prediction[J]. arXiv preprint arXiv:1704.05194, 2017.(https://arxiv.org/abs/1704.05194) 8 | """ 9 | import torch 10 | import torch.nn as nn 11 | 12 | from .basemodel import Linear, BaseModel 13 | from ..inputs import build_input_features 14 | from ..layers import PredictionLayer 15 | 16 | 17 | class MLR(BaseModel): 18 | """Instantiates the Mixed Logistic Regression/Piece-wise Linear Model. 19 | 20 | :param region_feature_columns: An iterable containing all the features used by region part of the model. 21 | :param base_feature_columns: An iterable containing all the features used by base part of the model. 22 | :param region_num: integer > 1,indicate the piece number 23 | :param l2_reg_linear: float. L2 regularizer strength applied to weight 24 | :param init_std: float,to use as the initialize std of embedding vector 25 | :param seed: integer ,to use as random seed. 26 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 27 | :param bias_feature_columns: An iterable containing all the features used by bias part of the model. 28 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 29 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 30 | :return: A PyTorch model instance. 31 | 32 | """ 33 | 34 | def __init__(self, region_feature_columns, base_feature_columns=None, bias_feature_columns=None, 35 | region_num=4, l2_reg_linear=1e-5, init_std=0.0001, seed=1024, task='binary', device='cpu', gpus=None 36 | ): 37 | super(MLR, self).__init__(region_feature_columns, region_feature_columns, task=task, device=device, gpus=gpus) 38 | 39 | if region_num <= 1: 40 | raise ValueError("region_num must > 1") 41 | 42 | self.l2_reg_linear = l2_reg_linear 43 | self.init_std = init_std 44 | self.seed = seed 45 | self.device = device 46 | 47 | self.region_num = region_num 48 | self.region_feature_columns = region_feature_columns 49 | self.base_feature_columns = base_feature_columns 50 | self.bias_feature_columns = bias_feature_columns 51 | 52 | if base_feature_columns is None or len(base_feature_columns) == 0: 53 | self.base_feature_columns = region_feature_columns 54 | 55 | if bias_feature_columns is None: 56 | self.bias_feature_columns = [] 57 | 58 | self.feature_index = build_input_features( 59 | self.region_feature_columns + self.base_feature_columns + self.bias_feature_columns) 60 | 61 | self.region_linear_model = nn.ModuleList([Linear( 62 | self.region_feature_columns, self.feature_index, self.init_std, self.device) for i in 63 | range(self.region_num)]) 64 | 65 | self.base_linear_model = nn.ModuleList([Linear( 66 | self.base_feature_columns, self.feature_index, self.init_std, self.device) for i in range(self.region_num)]) 67 | 68 | if self.bias_feature_columns is not None and len(self.bias_feature_columns) > 0: 69 | self.bias_model = nn.Sequential( 70 | Linear(self.bias_feature_columns, self.feature_index, 71 | self.init_std, self.device), 72 | PredictionLayer(task='binary', use_bias=False)) 73 | 74 | self.prediction_layer = PredictionLayer(task=task, use_bias=False) 75 | 76 | self.to(self.device) 77 | 78 | def get_region_score(self, inputs, region_number): 79 | region_logit = torch.cat([self.region_linear_model[i]( 80 | inputs) for i in range(region_number)], dim=-1) 81 | region_score = nn.Softmax(dim=-1)(region_logit) 82 | return region_score 83 | 84 | def get_learner_score(self, inputs, region_number): 85 | learner_score = self.prediction_layer(torch.cat( 86 | [self.region_linear_model[i](inputs) for i in range(region_number)], dim=-1)) 87 | return learner_score 88 | 89 | def forward(self, X): 90 | 91 | region_score = self.get_region_score(X, self.region_num) 92 | learner_score = self.get_learner_score(X, self.region_num) 93 | 94 | final_logit = torch.sum( 95 | region_score * learner_score, dim=-1, keepdim=True) 96 | 97 | if self.bias_feature_columns is not None and len(self.bias_feature_columns) > 0: 98 | bias_score = self.bias_model(X) 99 | final_logit = final_logit * bias_score 100 | return final_logit 101 | -------------------------------------------------------------------------------- /deepctr_torch/models/multitask/__init__.py: -------------------------------------------------------------------------------- 1 | from .sharedbottom import SharedBottom 2 | from .esmm import ESMM 3 | from .mmoe import MMOE 4 | from .ple import PLE 5 | -------------------------------------------------------------------------------- /deepctr_torch/models/multitask/esmm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | zanshuxun, zanshuxun@aliyun.com 5 | 6 | Reference: 7 | [1] Ma X, Zhao L, Huang G, et al. Entire space multi-task model: An effective approach for estimating post-click conversion rate[C]//The 41st International ACM SIGIR Conference on Research & Development in Information Retrieval. 2018.(https://dl.acm.org/doi/10.1145/3209978.3210104) 8 | """ 9 | import torch 10 | import torch.nn as nn 11 | 12 | from ..basemodel import BaseModel 13 | from ...inputs import combined_dnn_input 14 | from ...layers import DNN 15 | 16 | 17 | class ESMM(BaseModel): 18 | """Instantiates the Entire Space Multi-Task Model architecture. 19 | 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param tower_dnn_hidden_units: list, list of positive integer or empty list, the layer number and units in each layer of task-specific DNN. 22 | :param l2_reg_linear: float, L2 regularizer strength applied to linear part. 23 | :param l2_reg_embedding: float, L2 regularizer strength applied to embedding vector. 24 | :param l2_reg_dnn: float, L2 regularizer strength applied to DNN. 25 | :param init_std: float, to use as the initialize std of embedding vector. 26 | :param seed: integer, to use as random seed. 27 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 28 | :param dnn_activation: Activation function to use in DNN. 29 | :param dnn_use_bn: bool, Whether use BatchNormalization before activation or not in DNN. 30 | :param task_types: list of str, indicating the loss of each tasks, ``"binary"`` for binary logloss or ``"regression"`` for regression loss. e.g. ['binary', 'regression']. 31 | :param task_names: list of str, indicating the predict target of each tasks. 32 | :param device: str, ``"cpu"`` or ``"cuda:0"``. 33 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 34 | 35 | :return: A PyTorch model instance. 36 | """ 37 | 38 | def __init__(self, dnn_feature_columns, tower_dnn_hidden_units=(256, 128), 39 | l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_dnn=0, init_std=0.0001, seed=1024, 40 | dnn_dropout=0, dnn_activation='relu', dnn_use_bn=False, task_types=('binary', 'binary'), 41 | task_names=('ctr', 'ctcvr'), device='cpu', gpus=None): 42 | super(ESMM, self).__init__(linear_feature_columns=[], dnn_feature_columns=dnn_feature_columns, 43 | l2_reg_linear=l2_reg_linear, l2_reg_embedding=l2_reg_embedding, init_std=init_std, 44 | seed=seed, task='binary', device=device, gpus=gpus) 45 | self.num_tasks = len(task_names) 46 | if self.num_tasks != 2: 47 | raise ValueError("the length of task_names must be equal to 2") 48 | if len(dnn_feature_columns) == 0: 49 | raise ValueError("dnn_feature_columns is null!") 50 | if len(task_types) != self.num_tasks: 51 | raise ValueError("num_tasks must be equal to the length of task_types") 52 | 53 | for task_type in task_types: 54 | if task_type != 'binary': 55 | raise ValueError("task must be binary in ESMM, {} is illegal".format(task_type)) 56 | 57 | input_dim = self.compute_input_dim(dnn_feature_columns) 58 | 59 | self.ctr_dnn = DNN(input_dim, tower_dnn_hidden_units, activation=dnn_activation, 60 | dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 61 | init_std=init_std, device=device) 62 | self.cvr_dnn = DNN(input_dim, tower_dnn_hidden_units, activation=dnn_activation, 63 | dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 64 | init_std=init_std, device=device) 65 | 66 | self.ctr_dnn_final_layer = nn.Linear(tower_dnn_hidden_units[-1], 1, bias=False) 67 | self.cvr_dnn_final_layer = nn.Linear(tower_dnn_hidden_units[-1], 1, bias=False) 68 | 69 | self.add_regularization_weight( 70 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.ctr_dnn.named_parameters()), l2=l2_reg_dnn) 71 | self.add_regularization_weight( 72 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.cvr_dnn.named_parameters()), l2=l2_reg_dnn) 73 | self.add_regularization_weight(self.ctr_dnn_final_layer.weight, l2=l2_reg_dnn) 74 | self.add_regularization_weight(self.cvr_dnn_final_layer.weight, l2=l2_reg_dnn) 75 | self.to(device) 76 | 77 | def forward(self, X): 78 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 79 | self.embedding_dict) 80 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 81 | 82 | ctr_output = self.ctr_dnn(dnn_input) 83 | cvr_output = self.cvr_dnn(dnn_input) 84 | 85 | ctr_logit = self.ctr_dnn_final_layer(ctr_output) 86 | cvr_logit = self.cvr_dnn_final_layer(cvr_output) 87 | 88 | ctr_pred = self.out(ctr_logit) 89 | cvr_pred = self.out(cvr_logit) 90 | 91 | ctcvr_pred = ctr_pred * cvr_pred # CTCVR = CTR * CVR 92 | 93 | task_outs = torch.cat([ctr_pred, ctcvr_pred], -1) 94 | return task_outs 95 | -------------------------------------------------------------------------------- /deepctr_torch/models/multitask/sharedbottom.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | zanshuxun, zanshuxun@aliyun.com 5 | 6 | Reference: 7 | [1] Ruder S. An overview of multi-task learning in deep neural networks[J]. arXiv preprint arXiv:1706.05098, 2017.(https://arxiv.org/pdf/1706.05098.pdf) 8 | """ 9 | import torch 10 | import torch.nn as nn 11 | 12 | from ..basemodel import BaseModel 13 | from ...inputs import combined_dnn_input 14 | from ...layers import DNN, PredictionLayer 15 | 16 | 17 | class SharedBottom(BaseModel): 18 | """Instantiates the SharedBottom multi-task learning Network architecture. 19 | 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param bottom_dnn_hidden_units: list, list of positive integer or empty list, the layer number and units in each layer of shared bottom DNN. 22 | :param tower_dnn_hidden_units: list, list of positive integer or empty list, the layer number and units in each layer of task-specific DNN. 23 | :param l2_reg_linear: float, L2 regularizer strength applied to linear part 24 | :param l2_reg_embedding: float, L2 regularizer strength applied to embedding vector 25 | :param l2_reg_dnn: float, L2 regularizer strength applied to DNN 26 | :param init_std: float, to use as the initialize std of embedding vector 27 | :param seed: integer, to use as random seed. 28 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 29 | :param dnn_activation: Activation function to use in DNN 30 | :param dnn_use_bn: bool, Whether use BatchNormalization before activation or not in DNN 31 | :param task_types: list of str, indicating the loss of each tasks, ``"binary"`` for binary logloss or ``"regression"`` for regression loss. e.g. ['binary', 'regression'] 32 | :param task_names: list of str, indicating the predict target of each tasks 33 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 34 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 35 | 36 | :return: A PyTorch model instance. 37 | """ 38 | 39 | def __init__(self, dnn_feature_columns, bottom_dnn_hidden_units=(256, 128), tower_dnn_hidden_units=(64,), 40 | l2_reg_linear=0.00001, l2_reg_embedding=0.00001, l2_reg_dnn=0, init_std=0.0001, seed=1024, 41 | dnn_dropout=0, dnn_activation='relu', dnn_use_bn=False, task_types=('binary', 'binary'), 42 | task_names=('ctr', 'ctcvr'), device='cpu', gpus=None): 43 | super(SharedBottom, self).__init__(linear_feature_columns=[], dnn_feature_columns=dnn_feature_columns, 44 | l2_reg_linear=l2_reg_linear, l2_reg_embedding=l2_reg_embedding, 45 | init_std=init_std, seed=seed, device=device, gpus=gpus) 46 | self.num_tasks = len(task_names) 47 | if self.num_tasks <= 1: 48 | raise ValueError("num_tasks must be greater than 1") 49 | if len(dnn_feature_columns) == 0: 50 | raise ValueError("dnn_feature_columns is null!") 51 | if len(task_types) != self.num_tasks: 52 | raise ValueError("num_tasks must be equal to the length of task_types") 53 | 54 | for task_type in task_types: 55 | if task_type not in ['binary', 'regression']: 56 | raise ValueError("task must be binary or regression, {} is illegal".format(task_type)) 57 | 58 | self.task_names = task_names 59 | self.input_dim = self.compute_input_dim(dnn_feature_columns) 60 | self.bottom_dnn_hidden_units = bottom_dnn_hidden_units 61 | self.tower_dnn_hidden_units = tower_dnn_hidden_units 62 | 63 | self.bottom_dnn = DNN(self.input_dim, bottom_dnn_hidden_units, activation=dnn_activation, 64 | dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 65 | init_std=init_std, device=device) 66 | if len(self.tower_dnn_hidden_units) > 0: 67 | self.tower_dnn = nn.ModuleList( 68 | [DNN(bottom_dnn_hidden_units[-1], tower_dnn_hidden_units, activation=dnn_activation, 69 | dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 70 | init_std=init_std, device=device) for _ in range(self.num_tasks)]) 71 | self.add_regularization_weight( 72 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.tower_dnn.named_parameters()), 73 | l2=l2_reg_dnn) 74 | self.tower_dnn_final_layer = nn.ModuleList([nn.Linear( 75 | tower_dnn_hidden_units[-1] if len(self.tower_dnn_hidden_units) > 0 else bottom_dnn_hidden_units[-1], 1, 76 | bias=False) for _ in range(self.num_tasks)]) 77 | 78 | self.out = nn.ModuleList([PredictionLayer(task) for task in task_types]) 79 | 80 | self.add_regularization_weight( 81 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.bottom_dnn.named_parameters()), l2=l2_reg_dnn) 82 | self.add_regularization_weight( 83 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.tower_dnn_final_layer.named_parameters()), 84 | l2=l2_reg_dnn) 85 | self.to(device) 86 | 87 | def forward(self, X): 88 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 89 | self.embedding_dict) 90 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 91 | shared_bottom_output = self.bottom_dnn(dnn_input) 92 | 93 | # tower dnn (task-specific) 94 | task_outs = [] 95 | for i in range(self.num_tasks): 96 | if len(self.tower_dnn_hidden_units) > 0: 97 | tower_dnn_out = self.tower_dnn[i](shared_bottom_output) 98 | tower_dnn_logit = self.tower_dnn_final_layer[i](tower_dnn_out) 99 | else: 100 | tower_dnn_logit = self.tower_dnn_final_layer[i](shared_bottom_output) 101 | output = self.out[i](tower_dnn_logit) 102 | task_outs.append(output) 103 | task_outs = torch.cat(task_outs, -1) 104 | return task_outs 105 | -------------------------------------------------------------------------------- /deepctr_torch/models/nfm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | Reference: 6 | [1] He X, Chua T S. Neural factorization machines for sparse predictive analytics[C]//Proceedings of the 40th International ACM SIGIR conference on Research and Development in Information Retrieval. ACM, 2017: 355-364. (https://arxiv.org/abs/1708.05027) 7 | """ 8 | import torch 9 | import torch.nn as nn 10 | 11 | from .basemodel import BaseModel 12 | from ..inputs import combined_dnn_input 13 | from ..layers import DNN, BiInteractionPooling 14 | 15 | 16 | class NFM(BaseModel): 17 | """Instantiates the NFM Network architecture. 18 | 19 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of deep net 22 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 23 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part. 24 | :param l2_reg_dnn: float . L2 regularizer strength applied to DNN 25 | :param init_std: float,to use as the initialize std of embedding vector 26 | :param seed: integer ,to use as random seed. 27 | :param biout_dropout: When not ``None``, the probability we will drop out the output of BiInteractionPooling Layer. 28 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 29 | :param dnn_activation: Activation function to use in deep net 30 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 31 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 32 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 33 | :return: A PyTorch model instance. 34 | 35 | """ 36 | 37 | def __init__(self, 38 | linear_feature_columns, dnn_feature_columns, dnn_hidden_units=(128, 128), 39 | l2_reg_embedding=1e-5, l2_reg_linear=1e-5, l2_reg_dnn=0, init_std=0.0001, seed=1024, bi_dropout=0, 40 | dnn_dropout=0, dnn_activation='relu', task='binary', device='cpu', gpus=None): 41 | super(NFM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 42 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 43 | device=device, gpus=gpus) 44 | 45 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns, include_sparse=False) + self.embedding_size, 46 | dnn_hidden_units, 47 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=False, 48 | init_std=init_std, device=device) 49 | self.dnn_linear = nn.Linear( 50 | dnn_hidden_units[-1], 1, bias=False).to(device) 51 | self.add_regularization_weight( 52 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 53 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_dnn) 54 | self.bi_pooling = BiInteractionPooling() 55 | self.bi_dropout = bi_dropout 56 | if self.bi_dropout > 0: 57 | self.dropout = nn.Dropout(bi_dropout) 58 | self.to(device) 59 | 60 | def forward(self, X): 61 | 62 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 63 | self.embedding_dict) 64 | linear_logit = self.linear_model(X) 65 | fm_input = torch.cat(sparse_embedding_list, dim=1) 66 | bi_out = self.bi_pooling(fm_input) 67 | if self.bi_dropout: 68 | bi_out = self.dropout(bi_out) 69 | 70 | dnn_input = combined_dnn_input([bi_out], dense_value_list) 71 | dnn_output = self.dnn(dnn_input) 72 | dnn_logit = self.dnn_linear(dnn_output) 73 | 74 | logit = linear_logit + dnn_logit 75 | 76 | y_pred = self.out(logit) 77 | 78 | return y_pred 79 | -------------------------------------------------------------------------------- /deepctr_torch/models/pnn.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | Reference: 6 | [1] Qu Y, Cai H, Ren K, et al. Product-based neural networks for user response prediction[C]//Data Mining (ICDM), 2016 IEEE 16th International Conference on. IEEE, 2016: 1149-1154.(https://arxiv.org/pdf/1611.00144.pdf) 7 | """ 8 | 9 | import torch 10 | import torch.nn as nn 11 | 12 | from .basemodel import BaseModel 13 | from ..inputs import combined_dnn_input 14 | from ..layers import DNN, concat_fun, InnerProductLayer, OutterProductLayer 15 | 16 | 17 | class PNN(BaseModel): 18 | """Instantiates the Product-based Neural Network architecture. 19 | 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of deep net 22 | :param l2_reg_embedding: float . L2 regularizer strength applied to embedding vector 23 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 24 | :param init_std: float,to use as the initialize std of embedding vector 25 | :param seed: integer ,to use as random seed. 26 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 27 | :param dnn_activation: Activation function to use in DNN 28 | :param use_inner: bool,whether use inner-product or not. 29 | :param use_outter: bool,whether use outter-product or not. 30 | :param kernel_type: str,kernel_type used in outter-product,can be ``'mat'`` , ``'vec'`` or ``'num'`` 31 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 32 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 33 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 34 | :return: A PyTorch model instance. 35 | 36 | """ 37 | 38 | def __init__(self, dnn_feature_columns, dnn_hidden_units=(128, 128), l2_reg_embedding=1e-5, l2_reg_dnn=0, 39 | init_std=0.0001, seed=1024, dnn_dropout=0, dnn_activation='relu', use_inner=True, use_outter=False, 40 | kernel_type='mat', task='binary', device='cpu', gpus=None): 41 | 42 | super(PNN, self).__init__([], dnn_feature_columns, l2_reg_linear=0, l2_reg_embedding=l2_reg_embedding, 43 | init_std=init_std, seed=seed, task=task, device=device, gpus=gpus) 44 | 45 | if kernel_type not in ['mat', 'vec', 'num']: 46 | raise ValueError("kernel_type must be mat,vec or num") 47 | 48 | self.use_inner = use_inner 49 | self.use_outter = use_outter 50 | self.kernel_type = kernel_type 51 | self.task = task 52 | 53 | product_out_dim = 0 54 | num_inputs = self.compute_input_dim(dnn_feature_columns, include_dense=False, feature_group=True) 55 | num_pairs = int(num_inputs * (num_inputs - 1) / 2) 56 | 57 | if self.use_inner: 58 | product_out_dim += num_pairs 59 | self.innerproduct = InnerProductLayer(device=device) 60 | 61 | if self.use_outter: 62 | product_out_dim += num_pairs 63 | self.outterproduct = OutterProductLayer( 64 | num_inputs, self.embedding_size, kernel_type=kernel_type, device=device) 65 | 66 | self.dnn = DNN(product_out_dim + self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 67 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=False, 68 | init_std=init_std, device=device) 69 | 70 | self.dnn_linear = nn.Linear( 71 | dnn_hidden_units[-1], 1, bias=False).to(device) 72 | self.add_regularization_weight( 73 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 74 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_dnn) 75 | 76 | self.to(device) 77 | 78 | def forward(self, X): 79 | 80 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 81 | self.embedding_dict) 82 | linear_signal = torch.flatten( 83 | concat_fun(sparse_embedding_list), start_dim=1) 84 | 85 | if self.use_inner: 86 | inner_product = torch.flatten( 87 | self.innerproduct(sparse_embedding_list), start_dim=1) 88 | 89 | if self.use_outter: 90 | outer_product = self.outterproduct(sparse_embedding_list) 91 | 92 | if self.use_outter and self.use_inner: 93 | product_layer = torch.cat( 94 | [linear_signal, inner_product, outer_product], dim=1) 95 | elif self.use_outter: 96 | product_layer = torch.cat([linear_signal, outer_product], dim=1) 97 | elif self.use_inner: 98 | product_layer = torch.cat([linear_signal, inner_product], dim=1) 99 | else: 100 | product_layer = linear_signal 101 | 102 | dnn_input = combined_dnn_input([product_layer], dense_value_list) 103 | dnn_output = self.dnn(dnn_input) 104 | dnn_logit = self.dnn_linear(dnn_output) 105 | logit = dnn_logit 106 | 107 | y_pred = self.out(logit) 108 | 109 | return y_pred 110 | -------------------------------------------------------------------------------- /deepctr_torch/models/wdl.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | Reference: 6 | [1] Cheng H T, Koc L, Harmsen J, et al. Wide & deep learning for recommender systems[C]//Proceedings of the 1st Workshop on Deep Learning for Recommender Systems. ACM, 2016: 7-10.(https://arxiv.org/pdf/1606.07792.pdf) 7 | """ 8 | 9 | import torch.nn as nn 10 | 11 | from .basemodel import BaseModel 12 | from ..inputs import combined_dnn_input 13 | from ..layers import DNN 14 | 15 | 16 | class WDL(BaseModel): 17 | """Instantiates the Wide&Deep Learning architecture. 18 | 19 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 20 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 21 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of DNN 22 | :param l2_reg_linear: float. L2 regularizer strength applied to wide part 23 | :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector 24 | :param l2_reg_dnn: float. L2 regularizer strength applied to DNN 25 | :param init_std: float,to use as the initialize std of embedding vector 26 | :param seed: integer ,to use as random seed. 27 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 28 | :param dnn_activation: Activation function to use in DNN 29 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 30 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 31 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 32 | :return: A PyTorch model instance. 33 | 34 | """ 35 | 36 | def __init__(self, 37 | linear_feature_columns, dnn_feature_columns, dnn_hidden_units=(256, 128), 38 | l2_reg_linear=1e-5, 39 | l2_reg_embedding=1e-5, l2_reg_dnn=0, init_std=0.0001, seed=1024, dnn_dropout=0, dnn_activation='relu', 40 | dnn_use_bn=False, 41 | task='binary', device='cpu', gpus=None): 42 | 43 | super(WDL, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 44 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 45 | device=device, gpus=gpus) 46 | 47 | self.use_dnn = len(dnn_feature_columns) > 0 and len( 48 | dnn_hidden_units) > 0 49 | if self.use_dnn: 50 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 51 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 52 | init_std=init_std, device=device) 53 | self.dnn_linear = nn.Linear(dnn_hidden_units[-1], 1, bias=False).to(device) 54 | self.add_regularization_weight( 55 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 56 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_dnn) 57 | 58 | self.to(device) 59 | 60 | def forward(self, X): 61 | 62 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 63 | self.embedding_dict) 64 | logit = self.linear_model(X) 65 | 66 | if self.use_dnn: 67 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 68 | 69 | dnn_output = self.dnn(dnn_input) 70 | dnn_logit = self.dnn_linear(dnn_output) 71 | logit += dnn_logit 72 | 73 | y_pred = self.out(logit) 74 | 75 | return y_pred 76 | -------------------------------------------------------------------------------- /deepctr_torch/models/xdeepfm.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Wutong Zhang 5 | Reference: 6 | [1] Guo H, Tang R, Ye Y, et al. Deepfm: a factorization-machine based neural network for ctr prediction[J]. arXiv preprint arXiv:1703.04247, 2017.(https://arxiv.org/abs/1703.04247) 7 | """ 8 | 9 | import torch 10 | import torch.nn as nn 11 | 12 | from .basemodel import BaseModel 13 | from ..inputs import combined_dnn_input 14 | from ..layers import DNN, CIN 15 | 16 | 17 | class xDeepFM(BaseModel): 18 | """Instantiates the xDeepFM architecture. 19 | 20 | :param linear_feature_columns: An iterable containing all the features used by linear part of the model. 21 | :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. 22 | :param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of deep net 23 | :param cin_layer_size: list,list of positive integer or empty list, the feature maps in each hidden layer of Compressed Interaction Network 24 | :param cin_split_half: bool.if set to True, half of the feature maps in each hidden will connect to output unit 25 | :param cin_activation: activation function used on feature maps 26 | :param l2_reg_linear: float. L2 regularizer strength applied to linear part 27 | :param l2_reg_embedding: L2 regularizer strength applied to embedding vector 28 | :param l2_reg_dnn: L2 regularizer strength applied to deep net 29 | :param l2_reg_cin: L2 regularizer strength applied to CIN. 30 | :param init_std: float,to use as the initialize std of embedding vector 31 | :param seed: integer ,to use as random seed. 32 | :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. 33 | :param dnn_activation: Activation function to use in DNN 34 | :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in DNN 35 | :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss 36 | :param device: str, ``"cpu"`` or ``"cuda:0"`` 37 | :param gpus: list of int or torch.device for multiple gpus. If None, run on `device`. `gpus[0]` should be the same gpu with `device`. 38 | :return: A PyTorch model instance. 39 | 40 | """ 41 | 42 | def __init__(self, linear_feature_columns, dnn_feature_columns, dnn_hidden_units=(256, 256), 43 | cin_layer_size=(256, 128,), cin_split_half=True, cin_activation='relu', l2_reg_linear=0.00001, 44 | l2_reg_embedding=0.00001, l2_reg_dnn=0, l2_reg_cin=0, init_std=0.0001, seed=1024, dnn_dropout=0, 45 | dnn_activation='relu', dnn_use_bn=False, task='binary', device='cpu', gpus=None): 46 | 47 | super(xDeepFM, self).__init__(linear_feature_columns, dnn_feature_columns, l2_reg_linear=l2_reg_linear, 48 | l2_reg_embedding=l2_reg_embedding, init_std=init_std, seed=seed, task=task, 49 | device=device, gpus=gpus) 50 | self.dnn_hidden_units = dnn_hidden_units 51 | self.use_dnn = len(dnn_feature_columns) > 0 and len(dnn_hidden_units) > 0 52 | if self.use_dnn: 53 | self.dnn = DNN(self.compute_input_dim(dnn_feature_columns), dnn_hidden_units, 54 | activation=dnn_activation, l2_reg=l2_reg_dnn, dropout_rate=dnn_dropout, use_bn=dnn_use_bn, 55 | init_std=init_std, device=device) 56 | self.dnn_linear = nn.Linear(dnn_hidden_units[-1], 1, bias=False).to(device) 57 | self.add_regularization_weight( 58 | filter(lambda x: 'weight' in x[0] and 'bn' not in x[0], self.dnn.named_parameters()), l2=l2_reg_dnn) 59 | 60 | self.add_regularization_weight(self.dnn_linear.weight, l2=l2_reg_dnn) 61 | 62 | self.cin_layer_size = cin_layer_size 63 | self.use_cin = len(self.cin_layer_size) > 0 and len(dnn_feature_columns) > 0 64 | if self.use_cin: 65 | field_num = len(self.embedding_dict) 66 | if cin_split_half == True: 67 | self.featuremap_num = sum( 68 | cin_layer_size[:-1]) // 2 + cin_layer_size[-1] 69 | else: 70 | self.featuremap_num = sum(cin_layer_size) 71 | self.cin = CIN(field_num, cin_layer_size, 72 | cin_activation, cin_split_half, l2_reg_cin, seed, device=device) 73 | self.cin_linear = nn.Linear(self.featuremap_num, 1, bias=False).to(device) 74 | self.add_regularization_weight(filter(lambda x: 'weight' in x[0], self.cin.named_parameters()), 75 | l2=l2_reg_cin) 76 | 77 | self.to(device) 78 | 79 | def forward(self, X): 80 | 81 | sparse_embedding_list, dense_value_list = self.input_from_feature_columns(X, self.dnn_feature_columns, 82 | self.embedding_dict) 83 | 84 | linear_logit = self.linear_model(X) 85 | if self.use_cin: 86 | cin_input = torch.cat(sparse_embedding_list, dim=1) 87 | cin_output = self.cin(cin_input) 88 | cin_logit = self.cin_linear(cin_output) 89 | if self.use_dnn: 90 | dnn_input = combined_dnn_input(sparse_embedding_list, dense_value_list) 91 | dnn_output = self.dnn(dnn_input) 92 | dnn_logit = self.dnn_linear(dnn_output) 93 | 94 | if len(self.dnn_hidden_units) == 0 and len(self.cin_layer_size) == 0: # only linear 95 | final_logit = linear_logit 96 | elif len(self.dnn_hidden_units) == 0 and len(self.cin_layer_size) > 0: # linear + CIN 97 | final_logit = linear_logit + cin_logit 98 | elif len(self.dnn_hidden_units) > 0 and len(self.cin_layer_size) == 0: # linear + Deep 99 | final_logit = linear_logit + dnn_logit 100 | elif len(self.dnn_hidden_units) > 0 and len(self.cin_layer_size) > 0: # linear + CIN + Deep 101 | final_logit = linear_logit + dnn_logit + cin_logit 102 | else: 103 | raise NotImplementedError 104 | 105 | y_pred = self.out(final_logit) 106 | 107 | return y_pred 108 | -------------------------------------------------------------------------------- /deepctr_torch/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | Author: 4 | Weichen Shen,weichenswc@163.com 5 | """ 6 | 7 | import json 8 | import logging 9 | from threading import Thread 10 | 11 | import requests 12 | 13 | try: 14 | from packaging.version import parse 15 | except ImportError: 16 | from pip._vendor.packaging.version import parse 17 | 18 | 19 | def check_version(version): 20 | """Return version of package on pypi.python.org using json.""" 21 | 22 | def check(version): 23 | try: 24 | url_pattern = 'https://pypi.python.org/pypi/deepctr-torch/json' 25 | req = requests.get(url_pattern) 26 | latest_version = parse('0') 27 | version = parse(version) 28 | if req.status_code == requests.codes.ok: 29 | j = json.loads(req.text.encode('utf-8')) 30 | releases = j.get('releases', []) 31 | for release in releases: 32 | ver = parse(release) 33 | if ver.is_prerelease or ver.is_postrelease: 34 | continue 35 | latest_version = max(latest_version, ver) 36 | if latest_version > version: 37 | logging.warning( 38 | '\nDeepCTR-PyTorch version {0} detected. Your version is {1}.\nUse `pip install -U deepctr-torch` to upgrade.Changelog: https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v{0}'.format( 39 | latest_version, version)) 40 | except : 41 | print("Please check the latest version manually on https://pypi.org/project/deepctr-torch/#history") 42 | return 43 | 44 | Thread(target=check, args=(version,)).start() 45 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = DeepCTR 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=DeepCTR 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/pics/AFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/AFM.png -------------------------------------------------------------------------------- /docs/pics/AFN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/AFN.jpg -------------------------------------------------------------------------------- /docs/pics/AutoInt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/AutoInt.png -------------------------------------------------------------------------------- /docs/pics/CCPM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/CCPM.png -------------------------------------------------------------------------------- /docs/pics/CIN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/CIN.png -------------------------------------------------------------------------------- /docs/pics/DCN-M.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DCN-M.png -------------------------------------------------------------------------------- /docs/pics/DCN-Mix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DCN-Mix.png -------------------------------------------------------------------------------- /docs/pics/DCN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DCN.png -------------------------------------------------------------------------------- /docs/pics/DIEN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DIEN.png -------------------------------------------------------------------------------- /docs/pics/DIFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DIFM.png -------------------------------------------------------------------------------- /docs/pics/DIN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DIN.png -------------------------------------------------------------------------------- /docs/pics/DSIN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DSIN.png -------------------------------------------------------------------------------- /docs/pics/DeepFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/DeepFM.png -------------------------------------------------------------------------------- /docs/pics/FGCNN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/FGCNN.png -------------------------------------------------------------------------------- /docs/pics/FNN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/FNN.png -------------------------------------------------------------------------------- /docs/pics/FiBiNET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/FiBiNET.png -------------------------------------------------------------------------------- /docs/pics/IFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/IFM.png -------------------------------------------------------------------------------- /docs/pics/InteractingLayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/InteractingLayer.png -------------------------------------------------------------------------------- /docs/pics/MLR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/MLR.png -------------------------------------------------------------------------------- /docs/pics/NFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/NFM.png -------------------------------------------------------------------------------- /docs/pics/ONN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/ONN.png -------------------------------------------------------------------------------- /docs/pics/PNN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/PNN.png -------------------------------------------------------------------------------- /docs/pics/WDL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/WDL.png -------------------------------------------------------------------------------- /docs/pics/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/code.png -------------------------------------------------------------------------------- /docs/pics/code2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/code2.jpg -------------------------------------------------------------------------------- /docs/pics/criteo_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/criteo_sample.png -------------------------------------------------------------------------------- /docs/pics/deepctrbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/deepctrbot.png -------------------------------------------------------------------------------- /docs/pics/fms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/fms.png -------------------------------------------------------------------------------- /docs/pics/mlr1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/mlr1.png -------------------------------------------------------------------------------- /docs/pics/mlrvsdnn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/mlrvsdnn.png -------------------------------------------------------------------------------- /docs/pics/movielens_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/movielens_sample.png -------------------------------------------------------------------------------- /docs/pics/movielens_sample_with_genres.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/movielens_sample_with_genres.png -------------------------------------------------------------------------------- /docs/pics/multitaskmodels/ESMM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/multitaskmodels/ESMM.png -------------------------------------------------------------------------------- /docs/pics/multitaskmodels/MMOE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/multitaskmodels/MMOE.png -------------------------------------------------------------------------------- /docs/pics/multitaskmodels/PLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/multitaskmodels/PLE.png -------------------------------------------------------------------------------- /docs/pics/multitaskmodels/SharedBottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/multitaskmodels/SharedBottom.png -------------------------------------------------------------------------------- /docs/pics/planet_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/planet_github.png -------------------------------------------------------------------------------- /docs/pics/weichennote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/weichennote.png -------------------------------------------------------------------------------- /docs/pics/xDeepFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/docs/pics/xDeepFM.png -------------------------------------------------------------------------------- /docs/requirements.readthedocs.txt: -------------------------------------------------------------------------------- 1 | Cython>=0.28.5 2 | tensorflow==2.7.2 3 | scikit-learn==1.0 4 | -------------------------------------------------------------------------------- /docs/source/FAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ## 1. Save or load weights/models 4 | ---------------------------------------- 5 | To save/load weights: 6 | 7 | ```python 8 | import torch 9 | model = DeepFM(...) 10 | torch.save(model.state_dict(), 'DeepFM_weights.h5') 11 | model.load_state_dict(torch.load('DeepFM_weights.h5')) 12 | ``` 13 | 14 | To save/load models: 15 | 16 | ```python 17 | import torch 18 | model = DeepFM(...) 19 | torch.save(model, 'DeepFM.h5') 20 | model = torch.load('DeepFM.h5') 21 | ``` 22 | 23 | ## 2. Set learning rate and use earlystopping 24 | --------------------------------------------------- 25 | Here is a example of how to set learning rate and earlystopping: 26 | 27 | ```python 28 | from torch.optim import Adagrad 29 | from deepctr_torch.models import DeepFM 30 | from deepctr_torch.callbacks import EarlyStopping, ModelCheckpoint 31 | 32 | model = DeepFM(linear_feature_columns,dnn_feature_columns) 33 | model.compile(Adagrad(model.parameters(),0.1024),'binary_crossentropy',metrics=['binary_crossentropy']) 34 | 35 | es = EarlyStopping(monitor='val_binary_crossentropy', min_delta=0, verbose=1, patience=0, mode='min') 36 | mdckpt = ModelCheckpoint(filepath='model.ckpt', monitor='val_binary_crossentropy', verbose=1, save_best_only=True, mode='min') 37 | history = model.fit(model_input,data[target].values,batch_size=256,epochs=10,verbose=2,validation_split=0.2,callbacks=[es,mdckpt]) 38 | print(history) 39 | ``` 40 | 41 | ## 3. How to add a long dense feature vector as a input to the model? 42 | ```python 43 | from deepctr_torch.models import DeepFM 44 | from deepctr_torch.inputs import DenseFeat,SparseFeat,get_feature_names 45 | import numpy as np 46 | 47 | feature_columns = [SparseFeat('user_id',120,),SparseFeat('item_id',60,),DenseFeat("pic_vec",5)] 48 | fixlen_feature_names = get_feature_names(feature_columns) 49 | 50 | user_id = np.array([[1],[0],[1]]) 51 | item_id = np.array([[30],[20],[10]]) 52 | pic_vec = np.array([[0.1,0.5,0.4,0.3,0.2],[0.1,0.5,0.4,0.3,0.2],[0.1,0.5,0.4,0.3,0.2]]) 53 | label = np.array([1,0,1]) 54 | 55 | model_input = {'user_id':user_id,'item_id':item_id,'pic_vec':pic_vec} 56 | 57 | model = DeepFM(feature_columns,feature_columns) 58 | model.compile('adagrad','binary_crossentropy') 59 | model.fit(model_input,label) 60 | ``` 61 | 62 | ## 4. How to run the demo with GPU ? 63 | 64 | ```python 65 | import torch 66 | device = 'cpu' 67 | use_cuda = True 68 | if use_cuda and torch.cuda.is_available(): 69 | print('cuda ready...') 70 | device = 'cuda:0' 71 | 72 | model = DeepFM(...,device=device) 73 | ``` 74 | 75 | ## 5. How to run the demo with multiple GPUs ? 76 | 77 | ```python 78 | model = DeepFM(..., device=device, gpus=[0, 1]) 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/source/History.md: -------------------------------------------------------------------------------- 1 | # History 2 | - 10/22/2022 : [v0.2.9](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.9) released.Add multi-task models: SharedBottom, ESMM, MMOE, PLE. 3 | - 06/19/2022 : [v0.2.8](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.8) released.Fix some bugs. 4 | - 06/14/2021 : [v0.2.7](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.7) released.Add [AFN](./Features.html#afn-adaptive-factorization-network-learning-adaptive-order-feature-interactions) and fix some bugs. 5 | - 04/04/2021 : [v0.2.6](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.6) released.Add [IFM](./Features.html#ifm-input-aware-factorization-machine) and [DIFM](./Features.html#difm-dual-input-aware-factorization-machine);Support multi-gpus running([example](./FAQ.html#how-to-run-the-demo-with-multiple-gpus)). 6 | - 02/12/2021 : [v0.2.5](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.5) released.Fix bug in DCN-M. 7 | - 12/05/2020 : [v0.2.4](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.4) released.Imporve compatibility & fix issues.Add History callback.([example](https://deepctr-torch.readthedocs.io/en/latest/FAQ.html#set-learning-rate-and-use-earlystopping)). 8 | - 10/18/2020 : [v0.2.3](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.3) released.Add [DCN-M](./Features.html#dcn-deep-cross-network)&[DCN-Mix](./Features.html#dcn-mix-improved-deep-cross-network-with-mix-of-experts-and-matrix-kernel).Add EarlyStopping and ModelCheckpoint callbacks([example](https://deepctr-torch.readthedocs.io/en/latest/FAQ.html#set-learning-rate-and-use-earlystopping)). 9 | - 10/09/2020 : [v0.2.2](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.2) released.Improve the reproducibility & fix some bugs. 10 | - 03/27/2020 : [v0.2.1](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.1) released.Add [DIN](./Features.html#din-deep-interest-network) and [DIEN](./Features.html#dien-deep-interest-evolution-network) . 11 | - 01/31/2020 : [v0.2.0](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.2.0) released.Refactor [feature columns](./Features.html#feature-columns).Support to use double precision in metric calculation. 12 | - 10/03/2019 : [v0.1.3](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.1.3) released.Simplify the input logic. 13 | - 09/28/2019 : [v0.1.2](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.1.2) released.Add [sequence(multi-value) input support](./Examples.html#multi-value-input-movielens). 14 | - 09/24/2019 : [v0.1.1](https://github.com/shenweichen/DeepCTR-Torch/releases/tag/v0.1.1) released. Add [CCPM](./Features.html#ccpm-convolutional-click-prediction-model). 15 | - 09/22/2019 : DeepCTR-Torch first version v0.1.0 is released on [PyPi](https://pypi.org/project/deepctr-torch/) -------------------------------------------------------------------------------- /docs/source/Layers.rst: -------------------------------------------------------------------------------- 1 | DeepCTR-Torch Layers API 2 | ====================== 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 3 7 | :caption: API: 8 | 9 | Core Layers 10 | Interaction Layers 11 | Sequence Layers -------------------------------------------------------------------------------- /docs/source/Models.rst: -------------------------------------------------------------------------------- 1 | DeepCTR-Torch Models API 2 | ====================== 3 | 4 | .. toctree:: 5 | BaseModel 6 | CCPM 7 | FNN 8 | PNN 9 | WDL 10 | DeepFM 11 | MLR 12 | NFM 13 | AFM 14 | DCN 15 | DCN-Mix 16 | DIN 17 | DIEN 18 | DSIN 19 | xDeepFM 20 | AutoInt 21 | ONN 22 | FGCNN 23 | FiBiNET 24 | IFM 25 | DIFM 26 | SharedBottom 27 | ESMM 28 | MMOE 29 | PLE -------------------------------------------------------------------------------- /docs/source/Quick-Start.md: -------------------------------------------------------------------------------- 1 | # Quick-Start 2 | 3 | ## Installation Guide 4 | `deepctr-torch` depends on torch>=1.2.0, you can specify to install it through `pip`. 5 | 6 | ```bash 7 | $ pip install -U deepctr-torch 8 | ``` 9 | ## Getting started: 4 steps to DeepCTR-Torch 10 | 11 | 12 | ### Step 1: Import model 13 | 14 | 15 | ```python 16 | import pandas as pd 17 | import torch 18 | from sklearn.metrics import log_loss, roc_auc_score 19 | from sklearn.model_selection import train_test_split 20 | from sklearn.preprocessing import LabelEncoder, MinMaxScaler 21 | 22 | from deepctr_torch.inputs import SparseFeat, DenseFeat, get_feature_names 23 | 24 | data = pd.read_csv('./criteo_sample.txt') 25 | 26 | sparse_features = ['C' + str(i) for i in range(1, 27)] 27 | dense_features = ['I' + str(i) for i in range(1, 14)] 28 | 29 | data[sparse_features] = data[sparse_features].fillna('-1', ) 30 | data[dense_features] = data[dense_features].fillna(0, ) 31 | target = ['label'] 32 | ``` 33 | 34 | 35 | 36 | ### Step 2: Simple preprocessing 37 | 38 | 39 | Usually there are two simple way to encode the sparse categorical feature for embedding 40 | 41 | - Label Encoding: map the features to integer value from 0 ~ len(#unique) - 1 42 | ```python 43 | for feat in sparse_features: 44 | lbe = LabelEncoder() 45 | data[feat] = lbe.fit_transform(data[feat]) 46 | ``` 47 | - Hash Encoding: 【Currently not supported】. 48 | 49 | And for dense numerical features,they are usually discretized to buckets,here we use normalization. 50 | 51 | ```python 52 | mms = MinMaxScaler(feature_range=(0,1)) 53 | data[dense_features] = mms.fit_transform(data[dense_features]) 54 | ``` 55 | 56 | 57 | ### Step 3: Generate feature columns 58 | 59 | For sparse features, we transform them into dense vectors by embedding techniques. 60 | For dense numerical features, we concatenate them to the input tensors of fully connected layer. 61 | 62 | - Label Encoding 63 | ```python 64 | fixlen_feature_columns = [SparseFeat(feat, vocabulary_size=data[feat].nunique(),embedding_dim=4) 65 | for i,feat in enumerate(sparse_features)] + [DenseFeat(feat, 1,) 66 | for feat in dense_features] 67 | ``` 68 | - Feature Hashing on the fly【currently not supported】 69 | ```python 70 | fixlen_feature_columns = [SparseFeat(feat, vocabulary_size=1e6,embedding_dim=4, use_hash=True, dtype='string') # since the input is string 71 | for feat in sparse_features] + [DenseFeat(feat, 1, ) 72 | for feat in dense_features] 73 | ``` 74 | - generate feature columns 75 | ```python 76 | dnn_feature_columns = sparse_feature_columns + dense_feature_columns 77 | linear_feature_columns = sparse_feature_columns + dense_feature_columns 78 | 79 | feature_names = get_feature_names(linear_feature_columns + dnn_feature_columns) 80 | 81 | ``` 82 | ### Step 4: Generate the training samples and train the model 83 | 84 | ```python 85 | train, test = train_test_split(data, test_size=0.2) 86 | train_model_input = {name:train[name] for name in feature_names} 87 | 88 | test_model_input = {name:test[name] for name in feature_names} 89 | 90 | 91 | device = 'cpu' 92 | use_cuda = True 93 | if use_cuda and torch.cuda.is_available(): 94 | print('cuda ready...') 95 | device = 'cuda:0' 96 | 97 | model = DeepFM(linear_feature_columns,dnn_feature_columns,task='binary',device=device) 98 | model.compile("adam", "binary_crossentropy", 99 | metrics=['binary_crossentropy'], ) 100 | 101 | history = model.fit(train_model_input,train[target].values,batch_size=256,epochs=10,verbose=2,validation_split=0.2) 102 | pred_ans = model.predict(test_model_input, batch_size=256) 103 | 104 | ``` 105 | You can check the full code [here](./Examples.html#classification-criteo). 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | import os 16 | import sys 17 | sys.path.insert(0, os.path.abspath('../../')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'DeepCTR-Torch' 23 | copyright = '2019-present, Weichen Shen' 24 | author = 'Weichen Shen' 25 | 26 | # The short X.Y version 27 | version = '' 28 | # The full version, including alpha/beta/rc tags 29 | release = '0.2.9' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.autodoc', 43 | 'sphinx.ext.mathjax', 44 | 'sphinx.ext.ifconfig', 45 | 'sphinx.ext.viewcode', 46 | 'sphinx.ext.githubpages', 47 | ] 48 | 49 | # Add any paths that contain templates here, relative to this directory. 50 | templates_path = ['_templates'] 51 | 52 | # The suffix(es) of source filenames. 53 | # You can specify multiple suffix as a list of string: 54 | # 55 | source_suffix = ['.rst', '.md'] 56 | #source_suffix = '.rst' 57 | 58 | # The master toctree document. 59 | master_doc = 'index' 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | # 64 | # This is also used if you do content translation via gettext catalogs. 65 | # Usually you set "language" from the command line for these cases. 66 | language = None 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | # This pattern also affects html_static_path and html_extra_path . 71 | exclude_patterns = [] 72 | 73 | # The name of the Pygments (syntax highlighting) style to use. 74 | pygments_style = 'sphinx' 75 | 76 | 77 | # -- Options for HTML output ------------------------------------------------- 78 | 79 | # The theme to use for HTML and HTML Help pages. See the documentation for 80 | # a list of builtin themes. 81 | # 82 | html_theme = 'alabaster' 83 | 84 | # Theme options are theme-specific and customize the look and feel of a theme 85 | # further. For a list of options available for each theme, see the 86 | # documentation. 87 | # 88 | # html_theme_options = {} 89 | 90 | # Add any paths that contain custom static files (such as style sheets) here, 91 | # relative to this directory. They are copied after the builtin static files, 92 | # so a file named "default.css" will overwrite the builtin "default.css". 93 | html_static_path = ['_static'] 94 | 95 | # Custom sidebar templates, must be a dictionary that maps document names 96 | # to template names. 97 | # 98 | # The default sidebars (for documents that don't match any pattern) are 99 | # defined by theme itself. Builtin themes are using these templates by 100 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 101 | # 'searchbox.html']``. 102 | # 103 | # html_sidebars = {} 104 | 105 | 106 | # -- Options for HTMLHelp output --------------------------------------------- 107 | 108 | # Output file base name for HTML help builder. 109 | htmlhelp_basename = 'DeepCTR-Torch doc' 110 | 111 | 112 | # -- Options for LaTeX output ------------------------------------------------ 113 | 114 | latex_elements = { 115 | # The paper size ('letterpaper' or 'a4paper'). 116 | # 117 | # 'papersize': 'letterpaper', 118 | 119 | # The font size ('10pt', '11pt' or '12pt'). 120 | # 121 | # 'pointsize': '10pt', 122 | 123 | # Additional stuff for the LaTeX preamble. 124 | # 125 | # 'preamble': '', 126 | 127 | # Latex figure (float) alignment 128 | # 129 | # 'figure_align': 'htbp', 130 | } 131 | 132 | # Grouping the document tree into LaTeX files. List of tuples 133 | # (source start file, target name, title, 134 | # author, documentclass [howto, manual, or own class]). 135 | latex_documents = [ 136 | (master_doc, 'DeepCTR-Torch.tex', 'DeepCTR-Torch Documentation', 137 | 'Weichen Shen', 'manual'), 138 | ] 139 | 140 | 141 | # -- Options for manual page output ------------------------------------------ 142 | 143 | # One entry per manual page. List of tuples 144 | # (source start file, name, description, authors, manual section). 145 | man_pages = [ 146 | (master_doc, 'deepctr-torch', 'DeepCTR-Torch Documentation', 147 | [author], 1) 148 | ] 149 | 150 | 151 | # -- Options for Texinfo output ---------------------------------------------- 152 | 153 | # Grouping the document tree into Texinfo files. List of tuples 154 | # (source start file, target name, title, author, 155 | # dir menu entry, description, category) 156 | texinfo_documents = [ 157 | (master_doc, 'DeepCTR-Torch', 'DeepCTR-Torch Documentation', 158 | author, 'DeepCTR-Torch', 'One line description of project.', 159 | 'Miscellaneous'), 160 | ] 161 | 162 | 163 | # -- Extension configuration ------------------------------------------------- 164 | todo_include_todos = False 165 | html_theme = 'sphinx_rtd_theme' 166 | 167 | source_parsers = { 168 | '.md': 'recommonmark.parser.CommonMarkParser', 169 | } 170 | 171 | autodoc_mock_imports = [ 172 | ] -------------------------------------------------------------------------------- /docs/source/deepctr_torch.callbacks.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.callbacks module 2 | ======================================== 3 | 4 | .. automodule:: deepctr_torch.callbacks 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.inputs.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.inputs module 2 | ============================ 3 | 4 | .. automodule:: deepctr_torch.inputs 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.layers.core.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.layers.core module 2 | ================================= 3 | 4 | .. automodule:: deepctr_torch.layers.core 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.layers.interaction.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.layers.interaction module 2 | ======================================== 3 | 4 | .. automodule:: deepctr_torch.layers.interaction 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.layers.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.layers package 2 | ============================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | deepctr_torch.layers.core 10 | deepctr_torch.layers.interaction 11 | deepctr_torch.layers.utils 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: deepctr_torch.layers 17 | :members: 18 | :no-undoc-members: 19 | :no-show-inheritance: 20 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.layers.sequence.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.layers.sequence module 2 | ======================================== 3 | 4 | .. automodule:: deepctr_torch.layers.sequence 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.layers.utils.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.layers.utils module 2 | ================================== 3 | 4 | .. automodule:: deepctr_torch.layers.utils 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.afm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.afm module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.afm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.afn.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.afn module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.afn 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.autoint.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.autoint module 2 | ==================================== 3 | 4 | .. automodule:: deepctr_torch.models.autoint 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.basemodel.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.basemodel module 2 | ====================================== 3 | 4 | .. automodule:: deepctr_torch.models.basemodel 5 | :members: BaseModel 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.ccpm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.ccpm module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.ccpm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.dcn.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.dcn module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.dcn 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.dcnmix.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.dcnmix module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.dcnmix 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.deepfm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.deepfm module 2 | =================================== 3 | 4 | .. automodule:: deepctr_torch.models.deepfm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.dien.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.dien module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.dien 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.difm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.difm module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.difm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.din.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.din module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.din 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.fibinet.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.fibinet module 2 | ==================================== 3 | 4 | .. automodule:: deepctr_torch.models.fibinet 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.ifm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.ifm module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.ifm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.mlr.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.mlr module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.mlr 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.multitask.esmm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.multitask.esmm module 2 | ============================= 3 | 4 | .. automodule:: deepctr_torch.models.multitask.esmm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.multitask.mmoe.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.multitask.mmoe module 2 | ============================= 3 | 4 | .. automodule:: deepctr_torch.models.multitask.mmoe 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.multitask.ple.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.multitask.ple module 2 | ============================= 3 | 4 | .. automodule:: deepctr_torch.models.multitask.ple 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.multitask.sharedbottom.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.multitask.sharedbottom module 2 | ============================= 3 | 4 | .. automodule:: deepctr_torch.models.multitask.sharedbottom 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.nfm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.nfm module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.nfm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.onn.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.onn module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.onn 5 | :members: ONN 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.pnn.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.pnn module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.pnn 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models package 2 | ============================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | deepctr_torch.models.afm 10 | deepctr_torch.models.autoint 11 | deepctr_torch.models.basemodel 12 | deepctr_torch.models.dcn 13 | deepctr_torch.models.dcnmix 14 | deepctr_torch.models.deepfm 15 | deepctr_torch.models.fibinet 16 | deepctr_torch.models.mlr 17 | deepctr_torch.models.nfm 18 | deepctr_torch.models.onn 19 | deepctr_torch.models.pnn 20 | deepctr_torch.models.wdl 21 | deepctr_torch.models.xdeepfm 22 | deepctr_torch.models.din 23 | deepctr_torch.models.dien 24 | deepctr_torch.models.ifm 25 | deepctr_torch.models.difm 26 | deepctr_torch.models.afn 27 | 28 | Module contents 29 | --------------- 30 | 31 | .. automodule:: deepctr_torch.models 32 | :members: 33 | :no-undoc-members: 34 | :no-show-inheritance: 35 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.wdl.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.wdl module 2 | ================================ 3 | 4 | .. automodule:: deepctr_torch.models.wdl 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.models.xdeepfm.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.models.xdeepfm module 2 | ==================================== 3 | 4 | .. automodule:: deepctr_torch.models.xdeepfm 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch package 2 | ====================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | deepctr_torch.layers 10 | deepctr_torch.models 11 | 12 | Submodules 13 | ---------- 14 | 15 | .. toctree:: 16 | 17 | deepctr_torch.inputs 18 | deepctr_torch.utils 19 | 20 | Module contents 21 | --------------- 22 | 23 | .. automodule:: deepctr_torch 24 | :members: 25 | :no-undoc-members: 26 | :no-show-inheritance: 27 | -------------------------------------------------------------------------------- /docs/source/deepctr_torch.utils.rst: -------------------------------------------------------------------------------- 1 | deepctr\_torch.utils module 2 | =========================== 3 | 4 | .. automodule:: deepctr_torch.utils 5 | :members: 6 | :no-undoc-members: 7 | :no-show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. DeepCTR-PyTorch documentation master file, created by 2 | sphinx-quickstart on Fri Nov 23 21:08:54 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to DeepCTR-Torch's documentation! 7 | =================================== 8 | 9 | |Downloads|_ |Stars|_ |Forks|_ |PyPi|_ |Issues|_ |Chat|_ 10 | 11 | .. |Downloads| image:: https://pepy.tech/badge/deepctr-torch 12 | .. _Downloads: https://pepy.tech/project/deepctr-torch 13 | 14 | .. |Stars| image:: https://img.shields.io/github/stars/shenweichen/deepctr-torch.svg 15 | .. _Stars: https://github.com/shenweichen/DeepCTR-Torch 16 | 17 | .. |Forks| image:: https://img.shields.io/github/forks/shenweichen/deepctr-torch.svg 18 | .. _Forks: https://github.com/shenweichen/DeepCTR-Torch/fork 19 | 20 | .. |PyPi| image:: https://img.shields.io/pypi/v/deepctr-torch.svg 21 | .. _PyPi: https://pypi.org/project/deepctr-torch/ 22 | 23 | .. |Issues| image:: https://img.shields.io/github/issues/shenweichen/deepctr-torch.svg 24 | .. _Issues: https://github.com/shenweichen/deepctr-torch/issues 25 | 26 | .. |Chat| image:: https://img.shields.io/badge/chat-wechat-brightgreen?style=flat 27 | .. _Chat: ./#disscussiongroup 28 | 29 | DeepCTR-Torch is a **Easy-to-use** , **Modular** and **Extendible** package of deep-learning based CTR models along with lots of core components layer which can be used to build your own custom model easily.It is compatible with **PyTorch**.You can use any complex model with ``model.fit()`` and ``model.predict()``. 30 | 31 | Let's `Get Started! <./Quick-Start.html>`_ (`Chinese Introduction `_) 32 | 33 | You can read the latest code at https://github.com/shenweichen/DeepCTR-Torch and `DeepCTR `_ for tensorflow version. 34 | 35 | News 36 | ----- 37 | 10/22/2022 : Add multi-task models: SharedBottom, ESMM, MMOE, PLE. `Changelog `_ 38 | 39 | 06/19/2022 : Fix some bugs. `Changelog `_ 40 | 41 | 06/14/2021 : Add `AFN <./Features.html#afn-adaptive-factorization-network-learning-adaptive-order-feature-interactions>`_ and fix some bugs. `Changelog `_ 42 | 43 | 44 | DisscussionGroup 45 | ----------------------- 46 | 47 | 公众号:**浅梦学习笔记** wechat ID: **deepctrbot** 48 | 49 | `Discussions `_ `学习小组主题集合 `_ 50 | 51 | .. image:: ../pics/code2.jpg 52 | 53 | .. toctree:: 54 | :maxdepth: 2 55 | :caption: Home: 56 | 57 | Quick-Start 58 | Features 59 | Examples 60 | FAQ 61 | History 62 | 63 | .. toctree:: 64 | :maxdepth: 3 65 | :caption: API: 66 | 67 | Models 68 | Layers 69 | Callbacks 70 | 71 | 72 | 73 | Indices and tables 74 | ================== 75 | 76 | * :ref:`genindex` 77 | * :ref:`modindex` 78 | * :ref:`search` 79 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | deepctr_torch 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | deepctr_torch 8 | -------------------------------------------------------------------------------- /examples/run_classification_criteo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pandas as pd 3 | import torch 4 | from sklearn.metrics import log_loss, roc_auc_score 5 | from sklearn.model_selection import train_test_split 6 | from sklearn.preprocessing import LabelEncoder, MinMaxScaler 7 | 8 | from deepctr_torch.inputs import SparseFeat, DenseFeat, get_feature_names 9 | from deepctr_torch.models import * 10 | 11 | if __name__ == "__main__": 12 | data = pd.read_csv('./criteo_sample.txt') 13 | 14 | sparse_features = ['C' + str(i) for i in range(1, 27)] 15 | dense_features = ['I' + str(i) for i in range(1, 14)] 16 | 17 | data[sparse_features] = data[sparse_features].fillna('-1', ) 18 | data[dense_features] = data[dense_features].fillna(0, ) 19 | target = ['label'] 20 | 21 | # 1.Label Encoding for sparse features,and do simple Transformation for dense features 22 | for feat in sparse_features: 23 | lbe = LabelEncoder() 24 | data[feat] = lbe.fit_transform(data[feat]) 25 | mms = MinMaxScaler(feature_range=(0, 1)) 26 | data[dense_features] = mms.fit_transform(data[dense_features]) 27 | 28 | # 2.count #unique features for each sparse field,and record dense feature field name 29 | 30 | fixlen_feature_columns = [SparseFeat(feat, vocabulary_size=data[feat].max() + 1, embedding_dim=4) 31 | for feat in sparse_features] + [DenseFeat(feat, 1, ) 32 | for feat in dense_features] 33 | 34 | dnn_feature_columns = fixlen_feature_columns 35 | linear_feature_columns = fixlen_feature_columns 36 | 37 | feature_names = get_feature_names( 38 | linear_feature_columns + dnn_feature_columns) 39 | 40 | # 3.generate input data for model 41 | 42 | train, test = train_test_split(data, test_size=0.2, random_state=2020) 43 | train_model_input = {name: train[name] for name in feature_names} 44 | test_model_input = {name: test[name] for name in feature_names} 45 | 46 | # 4.Define Model,train,predict and evaluate 47 | 48 | device = 'cpu' 49 | use_cuda = True 50 | if use_cuda and torch.cuda.is_available(): 51 | print('cuda ready...') 52 | device = 'cuda:0' 53 | 54 | model = DeepFM(linear_feature_columns=linear_feature_columns, dnn_feature_columns=dnn_feature_columns, 55 | task='binary', 56 | l2_reg_embedding=1e-5, device=device) 57 | 58 | model.compile("adagrad", "binary_crossentropy", 59 | metrics=["binary_crossentropy", "auc"], ) 60 | 61 | history = model.fit(train_model_input, train[target].values, batch_size=32, epochs=10, verbose=2, 62 | validation_split=0.2) 63 | pred_ans = model.predict(test_model_input, 256) 64 | print("") 65 | print("test LogLoss", round(log_loss(test[target].values, pred_ans), 4)) 66 | print("test AUC", round(roc_auc_score(test[target].values, pred_ans), 4)) 67 | -------------------------------------------------------------------------------- /examples/run_dien.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | 4 | from deepctr_torch.inputs import SparseFeat, DenseFeat, VarLenSparseFeat, get_feature_names 5 | from deepctr_torch.models import DIEN 6 | 7 | 8 | def get_xy_fd(use_neg=False, hash_flag=False): 9 | feature_columns = [SparseFeat('user', 4, embedding_dim=4, use_hash=hash_flag), 10 | SparseFeat('gender', 2, embedding_dim=4, use_hash=hash_flag), 11 | SparseFeat('item_id', 3 + 1, embedding_dim=8, use_hash=hash_flag), 12 | SparseFeat('cate_id', 2 + 1, embedding_dim=4, use_hash=hash_flag), 13 | DenseFeat('pay_score', 1)] 14 | 15 | feature_columns += [ 16 | VarLenSparseFeat(SparseFeat('hist_item_id', vocabulary_size=3 + 1, embedding_dim=8, embedding_name='item_id'), 17 | maxlen=4, length_name="seq_length"), 18 | VarLenSparseFeat(SparseFeat('hist_cate_id', vocabulary_size=2 + 1, embedding_dim=4, embedding_name='cate_id'), 19 | maxlen=4, 20 | length_name="seq_length")] 21 | 22 | behavior_feature_list = ["item_id", "cate_id"] 23 | uid = np.array([0, 1, 2, 3]) 24 | gender = np.array([0, 1, 0, 1]) 25 | item_id = np.array([1, 2, 3, 2]) # 0 is mask value 26 | cate_id = np.array([1, 2, 1, 2]) # 0 is mask value 27 | score = np.array([0.1, 0.2, 0.3, 0.2]) 28 | 29 | hist_item_id = np.array([[1, 2, 3, 0], [1, 2, 3, 0], [1, 2, 0, 0], [1, 2, 0, 0]]) 30 | hist_cate_id = np.array([[1, 1, 2, 0], [2, 1, 1, 0], [2, 1, 0, 0], [1, 2, 0, 0]]) 31 | 32 | behavior_length = np.array([3, 3, 2, 2]) 33 | 34 | feature_dict = {'user': uid, 'gender': gender, 'item_id': item_id, 'cate_id': cate_id, 35 | 'hist_item_id': hist_item_id, 'hist_cate_id': hist_cate_id, 36 | 'pay_score': score, "seq_length": behavior_length} 37 | 38 | if use_neg: 39 | feature_dict['neg_hist_item_id'] = np.array([[1, 2, 3, 0], [1, 2, 3, 0], [1, 2, 0, 0], [1, 2, 0, 0]]) 40 | feature_dict['neg_hist_cate_id'] = np.array([[1, 1, 2, 0], [2, 1, 1, 0], [2, 1, 0, 0], [1, 2, 0, 0]]) 41 | feature_columns += [ 42 | VarLenSparseFeat( 43 | SparseFeat('neg_hist_item_id', vocabulary_size=3 + 1, embedding_dim=8, embedding_name='item_id'), 44 | maxlen=4, length_name="seq_length"), 45 | VarLenSparseFeat( 46 | SparseFeat('neg_hist_cate_id', vocabulary_size=2 + 1, embedding_dim=4, embedding_name='cate_id'), 47 | maxlen=4, length_name="seq_length")] 48 | 49 | x = {name: feature_dict[name] for name in get_feature_names(feature_columns)} 50 | y = np.array([1, 0, 1, 0]) 51 | return x, y, feature_columns, behavior_feature_list 52 | 53 | 54 | if __name__ == "__main__": 55 | x, y, feature_columns, behavior_feature_list = get_xy_fd(use_neg=True) 56 | 57 | device = 'cpu' 58 | use_cuda = True 59 | if use_cuda and torch.cuda.is_available(): 60 | print('cuda ready...') 61 | device = 'cuda:0' 62 | 63 | model = DIEN(feature_columns, behavior_feature_list, 64 | dnn_hidden_units=[4, 4, 4], dnn_dropout=0.6, gru_type="AUGRU", use_negsampling=True, device=device) 65 | 66 | model.compile('adam', 'binary_crossentropy', 67 | metrics=['binary_crossentropy', 'auc']) 68 | history = model.fit(x, y, batch_size=2, epochs=10, verbose=1, validation_split=0, shuffle=False) 69 | -------------------------------------------------------------------------------- /examples/run_din.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.insert(0, '..') 4 | 5 | import numpy as np 6 | import torch 7 | from deepctr_torch.inputs import (DenseFeat, SparseFeat, VarLenSparseFeat, 8 | get_feature_names) 9 | from deepctr_torch.models.din import DIN 10 | 11 | 12 | def get_xy_fd(): 13 | feature_columns = [SparseFeat('user', 3, embedding_dim=8), SparseFeat('gender', 2, embedding_dim=8), 14 | SparseFeat('item', 3 + 1, embedding_dim=8), SparseFeat('item_gender', 2 + 1, embedding_dim=8), 15 | DenseFeat('score', 1)] 16 | 17 | feature_columns += [VarLenSparseFeat(SparseFeat('hist_item', 3 + 1, embedding_dim=8), 4, length_name="seq_length"), 18 | VarLenSparseFeat(SparseFeat('hist_item_gender', 2 + 1, embedding_dim=8), 4, length_name="seq_length")] 19 | behavior_feature_list = ["item", "item_gender"] 20 | uid = np.array([0, 1, 2]) 21 | ugender = np.array([0, 1, 0]) 22 | iid = np.array([1, 2, 3]) # 0 is mask value 23 | igender = np.array([1, 2, 1]) # 0 is mask value 24 | score = np.array([0.1, 0.2, 0.3]) 25 | 26 | hist_iid = np.array([[1, 2, 3, 0], [1, 2, 3, 0], [1, 2, 0, 0]]) 27 | hist_igender = np.array([[1, 1, 2, 0], [2, 1, 1, 0], [2, 1, 0, 0]]) 28 | behavior_length = np.array([3, 3, 2]) 29 | 30 | feature_dict = {'user': uid, 'gender': ugender, 'item': iid, 'item_gender': igender, 31 | 'hist_item': hist_iid, 'hist_item_gender': hist_igender, 'score': score, 32 | "seq_length": behavior_length} 33 | x = {name: feature_dict[name] for name in get_feature_names(feature_columns)} 34 | y = np.array([1, 0, 1]) 35 | 36 | return x, y, feature_columns, behavior_feature_list 37 | 38 | 39 | if __name__ == "__main__": 40 | x, y, feature_columns, behavior_feature_list = get_xy_fd() 41 | device = 'cpu' 42 | use_cuda = True 43 | if use_cuda and torch.cuda.is_available(): 44 | print('cuda ready...') 45 | device = 'cuda:0' 46 | 47 | model = DIN(feature_columns, behavior_feature_list, device=device, att_weight_normalization=True) 48 | model.compile('adagrad', 'binary_crossentropy', 49 | metrics=['binary_crossentropy']) 50 | history = model.fit(x, y, batch_size=3, epochs=10, verbose=2, validation_split=0.0) 51 | -------------------------------------------------------------------------------- /examples/run_multitask_learning.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pandas as pd 3 | import torch 4 | from sklearn.metrics import log_loss, roc_auc_score 5 | from sklearn.preprocessing import LabelEncoder, MinMaxScaler 6 | 7 | from deepctr_torch.inputs import SparseFeat, DenseFeat, get_feature_names 8 | from deepctr_torch.models import * 9 | 10 | if __name__ == "__main__": 11 | # data description can be found in https://www.biendata.xyz/competition/icmechallenge2019/ 12 | data = pd.read_csv('./byterec_sample.txt', sep='\t', 13 | names=["uid", "user_city", "item_id", "author_id", "item_city", "channel", "finish", "like", 14 | "music_id", "device", "time", "duration_time"]) 15 | 16 | sparse_features = ["uid", "user_city", "item_id", "author_id", "item_city", "channel", "music_id", "device"] 17 | dense_features = ["duration_time"] 18 | 19 | target = ['finish', 'like'] 20 | 21 | # 1.Label Encoding for sparse features,and do simple Transformation for dense features 22 | for feat in sparse_features: 23 | lbe = LabelEncoder() 24 | data[feat] = lbe.fit_transform(data[feat]) 25 | mms = MinMaxScaler(feature_range=(0, 1)) 26 | data[dense_features] = mms.fit_transform(data[dense_features]) 27 | 28 | # 2.count #unique features for each sparse field,and record dense feature field name 29 | 30 | fixlen_feature_columns = [SparseFeat(feat, vocabulary_size=data[feat].max() + 1, embedding_dim=4) 31 | for feat in sparse_features] + [DenseFeat(feat, 1, ) 32 | for feat in dense_features] 33 | 34 | dnn_feature_columns = fixlen_feature_columns 35 | linear_feature_columns = fixlen_feature_columns 36 | 37 | feature_names = get_feature_names( 38 | linear_feature_columns + dnn_feature_columns) 39 | 40 | # 3.generate input data for model 41 | 42 | split_boundary = int(data.shape[0] * 0.8) 43 | train, test = data[:split_boundary], data[split_boundary:] 44 | train_model_input = {name: train[name] for name in feature_names} 45 | test_model_input = {name: test[name] for name in feature_names} 46 | 47 | # 4.Define Model,train,predict and evaluate 48 | device = 'cpu' 49 | use_cuda = True 50 | if use_cuda and torch.cuda.is_available(): 51 | print('cuda ready...') 52 | device = 'cuda:0' 53 | 54 | model = MMOE(dnn_feature_columns, task_types=['binary', 'binary'], 55 | l2_reg_embedding=1e-5, task_names=target, device=device) 56 | model.compile("adagrad", loss=["binary_crossentropy", "binary_crossentropy"], 57 | metrics=['binary_crossentropy'], ) 58 | 59 | history = model.fit(train_model_input, train[target].values, batch_size=32, epochs=10, verbose=2) 60 | pred_ans = model.predict(test_model_input, 256) 61 | print("") 62 | for i, target_name in enumerate(target): 63 | print("%s test LogLoss" % target_name, round(log_loss(test[target[i]].values, pred_ans[:, i]), 4)) 64 | print("%s test AUC" % target_name, round(roc_auc_score(test[target[i]].values, pred_ans[:, i]), 4)) 65 | -------------------------------------------------------------------------------- /examples/run_multivalue_movielens.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import torch 4 | from sklearn.preprocessing import LabelEncoder 5 | from tensorflow.python.keras.preprocessing.sequence import pad_sequences 6 | 7 | from deepctr_torch.inputs import SparseFeat, VarLenSparseFeat, get_feature_names 8 | from deepctr_torch.models import DeepFM 9 | 10 | 11 | def split(x): 12 | key_ans = x.split('|') 13 | for key in key_ans: 14 | if key not in key2index: 15 | # Notice : input value 0 is a special "padding",so we do not use 0 to encode valid feature for sequence input 16 | key2index[key] = len(key2index) + 1 17 | return list(map(lambda x: key2index[x], key_ans)) 18 | 19 | 20 | if __name__ == "__main__": 21 | data = pd.read_csv("./movielens_sample.txt") 22 | sparse_features = ["movie_id", "user_id", 23 | "gender", "age", "occupation", "zip", ] 24 | target = ['rating'] 25 | 26 | # 1.Label Encoding for sparse features,and process sequence features 27 | for feat in sparse_features: 28 | lbe = LabelEncoder() 29 | data[feat] = lbe.fit_transform(data[feat]) 30 | # preprocess the sequence feature 31 | 32 | key2index = {} 33 | genres_list = list(map(split, data['genres'].values)) 34 | genres_length = np.array(list(map(len, genres_list))) 35 | max_len = max(genres_length) 36 | # Notice : padding=`post` 37 | genres_list = pad_sequences(genres_list, maxlen=max_len, padding='post', ) 38 | 39 | # 2.count #unique features for each sparse field and generate feature config for sequence feature 40 | 41 | fixlen_feature_columns = [SparseFeat(feat, data[feat].nunique(), embedding_dim=4) 42 | for feat in sparse_features] 43 | 44 | varlen_feature_columns = [VarLenSparseFeat(SparseFeat('genres', vocabulary_size=len( 45 | key2index) + 1, embedding_dim=4), maxlen=max_len, combiner='mean')] # Notice : value 0 is for padding for sequence input feature 46 | 47 | linear_feature_columns = fixlen_feature_columns + varlen_feature_columns 48 | dnn_feature_columns = fixlen_feature_columns + varlen_feature_columns 49 | 50 | feature_names = get_feature_names(linear_feature_columns + dnn_feature_columns) 51 | 52 | # 3.generate input data for model 53 | model_input = {name: data[name] for name in sparse_features} # 54 | model_input["genres"] = genres_list 55 | 56 | # 4.Define Model,compile and train 57 | 58 | device = 'cpu' 59 | use_cuda = True 60 | if use_cuda and torch.cuda.is_available(): 61 | print('cuda ready...') 62 | device = 'cuda:0' 63 | 64 | model = DeepFM(linear_feature_columns, dnn_feature_columns, task='regression', device=device) 65 | 66 | model.compile("adam", "mse", metrics=['mse'], ) 67 | history = model.fit(model_input, data[target].values, batch_size=256, epochs=10, verbose=2, validation_split=0.2) 68 | -------------------------------------------------------------------------------- /examples/run_regression_movielens.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import torch 3 | from sklearn.metrics import mean_squared_error 4 | from sklearn.model_selection import train_test_split 5 | from sklearn.preprocessing import LabelEncoder 6 | 7 | from deepctr_torch.inputs import SparseFeat, get_feature_names 8 | from deepctr_torch.models import DeepFM 9 | 10 | if __name__ == "__main__": 11 | 12 | data = pd.read_csv("./movielens_sample.txt") 13 | sparse_features = ["movie_id", "user_id", 14 | "gender", "age", "occupation", "zip"] 15 | target = ['rating'] 16 | 17 | # 1.Label Encoding for sparse features,and do simple Transformation for dense features 18 | for feat in sparse_features: 19 | lbe = LabelEncoder() 20 | data[feat] = lbe.fit_transform(data[feat]) 21 | # 2.count #unique features for each sparse field 22 | fixlen_feature_columns = [SparseFeat(feat, data[feat].nunique()) 23 | for feat in sparse_features] 24 | linear_feature_columns = fixlen_feature_columns 25 | dnn_feature_columns = fixlen_feature_columns 26 | feature_names = get_feature_names(linear_feature_columns + dnn_feature_columns) 27 | 28 | # 3.generate input data for model 29 | train, test = train_test_split(data, test_size=0.2) 30 | train_model_input = {name: train[name] for name in feature_names} 31 | test_model_input = {name: test[name] for name in feature_names} 32 | # 4.Define Model,train,predict and evaluate 33 | 34 | device = 'cpu' 35 | use_cuda = True 36 | if use_cuda and torch.cuda.is_available(): 37 | print('cuda ready...') 38 | device = 'cuda:0' 39 | 40 | model = DeepFM(linear_feature_columns, dnn_feature_columns, task='regression', device=device) 41 | model.compile("adam", "mse", metrics=['mse'], ) 42 | 43 | history = model.fit(train_model_input, train[target].values, batch_size=256, epochs=10, verbose=2, 44 | validation_split=0.2) 45 | pred_ans = model.predict(test_model_input, batch_size=256) 46 | print("test MSE", round(mean_squared_error( 47 | test[target].values, pred_ans), 4)) 48 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | REQUIRED_PACKAGES = [ 7 | 'torch>=1.2.0', 'tqdm', 'scikit-learn', 'tensorflow' 8 | ] 9 | 10 | setuptools.setup( 11 | name="deepctr-torch", 12 | version="0.2.9", 13 | author="Weichen Shen", 14 | author_email="weichenswc@163.com", 15 | description="Easy-to-use,Modular and Extendible package of deep learning based CTR(Click Through Rate) prediction models with PyTorch", 16 | long_description=long_description, 17 | long_description_content_type="text/markdown", 18 | url="https://github.com/shenweichen/deepctr-torch", 19 | download_url='https://github.com/shenweichen/deepctr-torch/tags', 20 | packages=setuptools.find_packages( 21 | exclude=["tests", "tests.models", "tests.layers"]), 22 | python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", # '>=3.4', # 3.4.6 23 | install_requires=REQUIRED_PACKAGES, 24 | extras_require={ 25 | 26 | }, 27 | entry_points={ 28 | }, 29 | classifiers=( 30 | "License :: OSI Approved :: Apache Software License", 31 | "Operating System :: OS Independent", 32 | 'Intended Audience :: Developers', 33 | 'Intended Audience :: Education', 34 | 'Intended Audience :: Science/Research', 35 | 'Programming Language :: Python :: 3', 36 | 'Programming Language :: Python :: 2.7', 37 | 'Programming Language :: Python :: 3.6', 38 | 'Programming Language :: Python :: 3.7', 39 | 'Programming Language :: Python :: 3.8', 40 | 'Programming Language :: Python :: 3.9', 41 | 'Programming Language :: Python :: 3.10', 42 | 'Topic :: Scientific/Engineering', 43 | 'Topic :: Scientific/Engineering :: Artificial Intelligence', 44 | 'Topic :: Software Development', 45 | 'Topic :: Software Development :: Libraries', 46 | 'Topic :: Software Development :: Libraries :: Python Modules', 47 | ), 48 | license="Apache-2.0", 49 | keywords=['ctr', 'click through rate', 50 | 'deep learning', 'torch', 'tensor', 'pytorch', 'deepctr'], 51 | ) 52 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/tests/__init__.py -------------------------------------------------------------------------------- /tests/layers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/tests/layers/__init__.py -------------------------------------------------------------------------------- /tests/layers/activation_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from deepctr_torch.layers import activation 3 | from tests.utils import layer_test 4 | 5 | 6 | def test_dice(): 7 | layer_test(activation.Dice, kwargs={'emb_size': 3, 'dim': 2}, 8 | input_shape=(5, 3), expected_output_shape=(5,3)) 9 | layer_test(activation.Dice, kwargs={'emb_size': 10, 'dim': 3}, 10 | input_shape=(5, 3, 10), expected_output_shape=(5,3,10)) 11 | 12 | -------------------------------------------------------------------------------- /tests/models/AFM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.callbacks import EarlyStopping, ModelCheckpoint 5 | from deepctr_torch.models import AFM 6 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 7 | 8 | 9 | @pytest.mark.parametrize( 10 | 'use_attention, sparse_feature_num, dense_feature_num', 11 | [(True, 3, 0), ] 12 | ) 13 | def test_AFM(use_attention, sparse_feature_num, dense_feature_num): 14 | model_name = 'AFM' 15 | sample_size = SAMPLE_SIZE 16 | x, y, feature_columns = get_test_data( 17 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 18 | 19 | model = AFM(linear_feature_columns=feature_columns, dnn_feature_columns=feature_columns, 20 | use_attention=use_attention, afm_dropout=0.5, device=get_device()) 21 | 22 | check_model(model, model_name, x, y) 23 | 24 | early_stopping = EarlyStopping(monitor='val_binary_crossentropy', min_delta=0, verbose=1, patience=0, mode='min') 25 | 26 | # test callbacks 27 | model_checkpoint = ModelCheckpoint(filepath='model.ckpt', monitor='val_binary_crossentropy', verbose=1, 28 | save_best_only=True, 29 | save_weights_only=False, mode='max', period=1) 30 | model.fit(x, y, batch_size=64, epochs=3, validation_split=0.5, callbacks=[early_stopping, model_checkpoint]) 31 | 32 | model_checkpoint = ModelCheckpoint(filepath='model.ckpt', monitor='val_binary_crossentropy', verbose=1, 33 | save_best_only=False, 34 | save_weights_only=False, mode='max', period=1) 35 | 36 | model.fit(x, y, batch_size=64, epochs=3, validation_split=0.5, callbacks=[early_stopping, model_checkpoint]) 37 | 38 | 39 | 40 | if __name__ == '__main__': 41 | pass 42 | -------------------------------------------------------------------------------- /tests/models/AFN_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import AFN 5 | from tests.utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'afn_dnn_hidden_units, sparse_feature_num, dense_feature_num', 10 | [((32, 16), 3, 0), 11 | ((32, 16), 3, 3), 12 | ((32, 16), 0, 3)] 13 | ) 14 | def test_AFN(afn_dnn_hidden_units, sparse_feature_num, dense_feature_num): 15 | model_name = 'AFN' 16 | sample_size = SAMPLE_SIZE 17 | x, y, feature_columns = get_test_data( 18 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 19 | 20 | model = AFN(feature_columns, feature_columns, afn_dnn_hidden_units=afn_dnn_hidden_units, device=get_device()) 21 | 22 | check_model(model, model_name, x, y) 23 | 24 | 25 | if __name__ == '__main__': 26 | pass 27 | -------------------------------------------------------------------------------- /tests/models/AutoInt_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import AutoInt 5 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'att_layer_num,dnn_hidden_units,sparse_feature_num', 10 | [(1, (4,), 2), (0, (4,), 2), (2, (4, 4,), 2), (1, (), 1), (1, (4,), 1)] 11 | ) 12 | def test_AutoInt(att_layer_num, dnn_hidden_units, sparse_feature_num): 13 | # if version.parse(torch.__version__) >= version.parse("1.1.0") and len(dnn_hidden_units)==0:#todo check version 14 | # return 15 | model_name = "AutoInt" 16 | sample_size = SAMPLE_SIZE 17 | x, y, feature_columns = get_test_data( 18 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 19 | 20 | model = AutoInt(linear_feature_columns=feature_columns, dnn_feature_columns=feature_columns, 21 | att_layer_num=att_layer_num, 22 | dnn_hidden_units=dnn_hidden_units, dnn_dropout=0.5, device=get_device()) 23 | check_model(model, model_name, x, y) 24 | 25 | 26 | if __name__ == "__main__": 27 | pass 28 | -------------------------------------------------------------------------------- /tests/models/CCPM_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from deepctr_torch.models import CCPM 4 | from tests.utils import check_model, get_test_data, SAMPLE_SIZE, get_device 5 | 6 | 7 | @pytest.mark.parametrize( 8 | 'sparse_feature_num,dense_feature_num', 9 | [(3, 0) 10 | ] 11 | ) 12 | def test_CCPM(sparse_feature_num, dense_feature_num): 13 | model_name = "CCPM" 14 | 15 | sample_size = SAMPLE_SIZE 16 | x, y, feature_columns = get_test_data( 17 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 18 | 19 | model = CCPM(feature_columns, feature_columns, conv_kernel_width=(3, 2), conv_filters=( 20 | 2, 1), dnn_hidden_units=[32, ], dnn_dropout=0.5) 21 | check_model(model, model_name, x, y) 22 | 23 | 24 | @pytest.mark.parametrize( 25 | 'sparse_feature_num,dense_feature_num', 26 | [(2, 0), 27 | ] 28 | ) 29 | def test_CCPM_without_seq(sparse_feature_num, dense_feature_num): 30 | model_name = "CCPM" 31 | 32 | sample_size = SAMPLE_SIZE 33 | x, y, feature_columns = get_test_data( 34 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num, sequence_feature=()) 35 | 36 | model = CCPM(feature_columns, feature_columns, conv_kernel_width=(3, 2), conv_filters=( 37 | 2, 1), dnn_hidden_units=[32, ], dnn_dropout=0.5, device=get_device()) 38 | check_model(model, model_name, x, y) 39 | 40 | 41 | if __name__ == "__main__": 42 | pass 43 | -------------------------------------------------------------------------------- /tests/models/DCNMix_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import DCNMix 5 | from ..utils import check_model, get_test_data, SAMPLE_SIZE, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'embedding_size,cross_num,hidden_size,sparse_feature_num', 10 | [(8, 0, (32,), 2), (8, 1, (32,), 2) 11 | ] # ('auto', 1, (32,), 3) , ('auto', 1, (), 1), ('auto', 1, (32,), 3) 12 | ) 13 | def test_DCNMix(embedding_size, cross_num, hidden_size, sparse_feature_num): 14 | model_name = "DCN-Mix" 15 | 16 | sample_size = SAMPLE_SIZE 17 | x, y, feature_columns = get_test_data( 18 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 19 | 20 | model = DCNMix(linear_feature_columns=feature_columns, dnn_feature_columns=feature_columns, 21 | cross_num=cross_num, dnn_hidden_units=hidden_size, dnn_dropout=0.5, device=get_device()) 22 | check_model(model, model_name, x, y) 23 | 24 | 25 | if __name__ == "__main__": 26 | pass 27 | -------------------------------------------------------------------------------- /tests/models/DCN_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import DCN 5 | from ..utils import check_model, get_test_data, SAMPLE_SIZE, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'embedding_size,cross_num,hidden_size,sparse_feature_num,cross_parameterization', 10 | [(8, 2, (32,), 2, 'vector'), (8, 1, (32,), 2, 'matrix'), 11 | ] # ('auto', 1, (32,), 3) , ('auto', 1, (), 1), ('auto', 1, (32,), 3) 12 | ) 13 | def test_DCN(embedding_size, cross_num, hidden_size, sparse_feature_num, cross_parameterization): 14 | model_name = "DCN" 15 | 16 | sample_size = SAMPLE_SIZE 17 | x, y, feature_columns = get_test_data( 18 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 19 | 20 | model = DCN(linear_feature_columns=feature_columns, dnn_feature_columns=feature_columns, cross_num=cross_num, 21 | cross_parameterization=cross_parameterization, 22 | dnn_hidden_units=hidden_size, dnn_dropout=0.5, device=get_device()) 23 | check_model(model, model_name, x, y) 24 | 25 | 26 | if __name__ == "__main__": 27 | pass 28 | -------------------------------------------------------------------------------- /tests/models/DIEN_test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | import torch 4 | 5 | from deepctr_torch.inputs import SparseFeat, DenseFeat, VarLenSparseFeat, get_feature_names 6 | from deepctr_torch.models.dien import InterestEvolving, DIEN 7 | from ..utils import check_model, get_device 8 | 9 | 10 | @pytest.mark.parametrize( 11 | 'gru_type', 12 | ["AIGRU", "AUGRU", "AGRU", "GRU"] 13 | ) 14 | def test_InterestEvolving(gru_type): 15 | interest_evolution = InterestEvolving( 16 | input_size=3, 17 | gru_type=gru_type, 18 | use_neg=False) 19 | 20 | query = torch.tensor([[1, 1, 1], [0.1, 0.2, 0.3]], dtype=torch.float) 21 | 22 | keys = torch.tensor([ 23 | [[0.1, 0.2, 0.3], [1, 2, 3], [0.4, 0.2, 1], [0.0, 0.0, 0.0]], 24 | [[0.1, 0.2, 0.3], [1, 2, 3], [0.4, 0.2, 1], [0.5, 0.5, 0.5]] 25 | ], dtype=torch.float) 26 | 27 | keys_length = torch.tensor([3, 4]) 28 | 29 | output = interest_evolution(query, keys, keys_length) 30 | 31 | assert output.size()[0] == 2 32 | assert output.size()[1] == 3 33 | 34 | 35 | def get_xy_fd(use_neg=False, hash_flag=False): 36 | feature_columns = [SparseFeat('user', 4, embedding_dim=4, use_hash=hash_flag), 37 | SparseFeat('gender', 2, embedding_dim=4, use_hash=hash_flag), 38 | SparseFeat('item_id', 3 + 1, embedding_dim=8, use_hash=hash_flag), 39 | SparseFeat('cate_id', 2 + 1, embedding_dim=4, use_hash=hash_flag), 40 | DenseFeat('pay_score', 1)] 41 | 42 | feature_columns += [ 43 | VarLenSparseFeat(SparseFeat('hist_item_id', vocabulary_size=3 + 1, embedding_dim=8, embedding_name='item_id'), 44 | maxlen=4, length_name="seq_length"), 45 | VarLenSparseFeat(SparseFeat('hist_cate_id', vocabulary_size=2 + 1, embedding_dim=4, embedding_name='cate_id'), 46 | maxlen=4, 47 | length_name="seq_length")] 48 | 49 | behavior_feature_list = ["item_id", "cate_id"] 50 | uid = np.array([0, 1, 2, 3]) 51 | gender = np.array([0, 1, 0, 1]) 52 | item_id = np.array([1, 2, 3, 2]) # 0 is mask value 53 | cate_id = np.array([1, 2, 1, 2]) # 0 is mask value 54 | score = np.array([0.1, 0.2, 0.3, 0.2]) 55 | 56 | hist_item_id = np.array([[1, 2, 3, 0], [1, 2, 3, 0], [1, 2, 0, 0], [1, 2, 0, 0]]) 57 | hist_cate_id = np.array([[1, 1, 2, 0], [2, 1, 1, 0], [2, 1, 0, 0], [1, 2, 0, 0]]) 58 | 59 | behavior_length = np.array([3, 3, 2, 2]) 60 | 61 | feature_dict = {'user': uid, 'gender': gender, 'item_id': item_id, 'cate_id': cate_id, 62 | 'hist_item_id': hist_item_id, 'hist_cate_id': hist_cate_id, 63 | 'pay_score': score, "seq_length": behavior_length} 64 | 65 | if use_neg: 66 | feature_dict['neg_hist_item_id'] = np.array([[1, 2, 3, 0], [1, 2, 3, 0], [1, 2, 0, 0], [1, 2, 0, 0]]) 67 | feature_dict['neg_hist_cate_id'] = np.array([[1, 1, 2, 0], [2, 1, 1, 0], [2, 1, 0, 0], [1, 2, 0, 0]]) 68 | feature_columns += [ 69 | VarLenSparseFeat( 70 | SparseFeat('neg_hist_item_id', vocabulary_size=3 + 1, embedding_dim=8, embedding_name='item_id'), 71 | maxlen=4, length_name="seq_length"), 72 | VarLenSparseFeat( 73 | SparseFeat('neg_hist_cate_id', vocabulary_size=2 + 1, embedding_dim=4, embedding_name='cate_id'), 74 | maxlen=4, length_name="seq_length")] 75 | 76 | x = {name: feature_dict[name] for name in get_feature_names(feature_columns)} 77 | y = np.array([1, 0, 1, 0]) 78 | return x, y, feature_columns, behavior_feature_list 79 | 80 | 81 | @pytest.mark.parametrize( 82 | 'gru_type,use_neg', 83 | [("AIGRU", True), ("AIGRU", False), 84 | ("AUGRU", True), ("AUGRU", False), 85 | ("AGRU", True), ("AGRU", False), 86 | ("GRU", True), ("GRU", False)] 87 | ) 88 | def test_DIEN(gru_type, use_neg): 89 | model_name = "DIEN_" + gru_type 90 | 91 | x, y, feature_columns, behavior_feature_list = get_xy_fd(use_neg=use_neg) 92 | 93 | model = DIEN(feature_columns, behavior_feature_list, gru_type=gru_type, use_negsampling=use_neg, 94 | dnn_hidden_units=[4, 4, 4], dnn_dropout=0.5, device=get_device()) 95 | 96 | check_model(model, model_name, x, y) 97 | 98 | 99 | if __name__ == "__main__": 100 | pass 101 | -------------------------------------------------------------------------------- /tests/models/DIFM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import DIFM 5 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'att_head_num,dnn_hidden_units,sparse_feature_num', 10 | [(1, (4,), 2), (2, (4, 4,), 2), (1, (4,), 1)] 11 | ) 12 | def test_DIFM(att_head_num, dnn_hidden_units, sparse_feature_num): 13 | model_name = "DIFM" 14 | sample_size = SAMPLE_SIZE 15 | x, y, feature_columns = get_test_data( 16 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 17 | 18 | model = DIFM(linear_feature_columns=feature_columns, dnn_feature_columns=feature_columns, 19 | att_head_num=att_head_num, 20 | dnn_hidden_units=dnn_hidden_units, dnn_dropout=0.5, device=get_device()) 21 | check_model(model, model_name, x, y) 22 | 23 | 24 | if __name__ == "__main__": 25 | pass 26 | -------------------------------------------------------------------------------- /tests/models/DIN_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import numpy as np 3 | 4 | from deepctr_torch.inputs import SparseFeat, VarLenSparseFeat, DenseFeat, get_feature_names 5 | from deepctr_torch.models.din import DIN 6 | from ..utils import check_model, get_device 7 | 8 | 9 | def get_xy_fd(hash_flag=False): 10 | feature_columns = [SparseFeat('user', 4, embedding_dim=4, use_hash=hash_flag), 11 | SparseFeat('gender', 2, embedding_dim=4, use_hash=hash_flag), 12 | SparseFeat('item_id', 3 + 1, embedding_dim=8, use_hash=hash_flag), 13 | SparseFeat('cate_id', 2 + 1, embedding_dim=4, use_hash=hash_flag), 14 | DenseFeat('pay_score', 1)] 15 | 16 | feature_columns += [ 17 | VarLenSparseFeat(SparseFeat('hist_item_id', vocabulary_size=3 + 1, embedding_dim=8, embedding_name='item_id'), 18 | maxlen=4, length_name="seq_length"), 19 | VarLenSparseFeat(SparseFeat('hist_cate_id', vocabulary_size=2 + 1, embedding_dim=4, embedding_name='cate_id'), 20 | maxlen=4, 21 | length_name="seq_length")] 22 | 23 | behavior_feature_list = ["item_id", "cate_id"] 24 | uid = np.array([0, 1, 2, 3]) 25 | gender = np.array([0, 1, 0, 1]) 26 | item_id = np.array([1, 2, 3, 2]) # 0 is mask value 27 | cate_id = np.array([1, 2, 1, 2]) # 0 is mask value 28 | score = np.array([0.1, 0.2, 0.3, 0.2]) 29 | 30 | hist_item_id = np.array([[1, 2, 3, 0], [1, 2, 3, 0], [1, 2, 0, 0], [1, 2, 0, 0]]) 31 | hist_cate_id = np.array([[1, 1, 2, 0], [2, 1, 1, 0], [2, 1, 0, 0], [1, 2, 0, 0]]) 32 | 33 | behavior_length = np.array([3, 3, 2, 2]) 34 | 35 | feature_dict = {'user': uid, 'gender': gender, 'item_id': item_id, 'cate_id': cate_id, 36 | 'hist_item_id': hist_item_id, 'hist_cate_id': hist_cate_id, 37 | 'pay_score': score, "seq_length": behavior_length} 38 | 39 | x = {name: feature_dict[name] for name in get_feature_names(feature_columns)} 40 | y = np.array([1, 0, 1, 0]) 41 | return x, y, feature_columns, behavior_feature_list 42 | 43 | 44 | def test_DIN(): 45 | model_name = "DIN" 46 | 47 | x, y, feature_columns, behavior_feature_list = get_xy_fd() 48 | model = DIN(feature_columns, behavior_feature_list, dnn_dropout=0.5, device=get_device()) 49 | 50 | check_model(model, model_name, x, y) # only have 3 train data so we set validation ratio at 0 51 | 52 | 53 | if __name__ == "__main__": 54 | pass 55 | -------------------------------------------------------------------------------- /tests/models/DeepFM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import DeepFM 5 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'use_fm,hidden_size,sparse_feature_num,dense_feature_num', 10 | [(True, (32,), 3, 3), 11 | (False, (32,), 3, 3), 12 | (False, (32,), 2, 2), 13 | (False, (32,), 1, 1), 14 | (True, (), 1, 1), 15 | (False, (), 2, 2), 16 | (True, (32,), 0, 3), 17 | (True, (32,), 3, 0), 18 | (False, (32,), 0, 3), 19 | (False, (32,), 3, 0), 20 | ] 21 | ) 22 | def test_DeepFM(use_fm, hidden_size, sparse_feature_num, dense_feature_num): 23 | model_name = "DeepFM" 24 | sample_size = SAMPLE_SIZE 25 | x, y, feature_columns = get_test_data( 26 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 27 | 28 | model = DeepFM(feature_columns, feature_columns, use_fm=use_fm, 29 | dnn_hidden_units=hidden_size, dnn_dropout=0.5, device=get_device()) 30 | check_model(model, model_name, x, y) 31 | 32 | # no linear part 33 | model = DeepFM([], feature_columns, use_fm=use_fm, 34 | dnn_hidden_units=hidden_size, dnn_dropout=0.5, device=get_device()) 35 | check_model(model, model_name + '_no_linear', x, y) 36 | 37 | if __name__ == "__main__": 38 | pass 39 | -------------------------------------------------------------------------------- /tests/models/FiBiNET_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import FiBiNET 5 | from ..utils import check_model, SAMPLE_SIZE, get_test_data, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'bilinear_type', 10 | ["each", 11 | "interaction", "all"] 12 | ) 13 | def test_FiBiNET(bilinear_type): 14 | model_name = "FiBiNET" 15 | sample_size = SAMPLE_SIZE 16 | x, y, feature_columns = get_test_data(sample_size, sparse_feature_num=3, dense_feature_num=3) 17 | 18 | model = FiBiNET(feature_columns, feature_columns, 19 | bilinear_type=bilinear_type, dnn_hidden_units=[8, 8], dnn_dropout=0.5, device=get_device()) 20 | check_model(model, model_name, x, y) 21 | 22 | 23 | if __name__ == "__main__": 24 | pass 25 | -------------------------------------------------------------------------------- /tests/models/IFM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import IFM 5 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'hidden_size,sparse_feature_num', 10 | [((32,), 3), 11 | ((32,), 2), ((32,), 1), 12 | ] 13 | ) 14 | def test_IFM(hidden_size, sparse_feature_num): 15 | model_name = "IFM" 16 | sample_size = SAMPLE_SIZE 17 | x, y, feature_columns = get_test_data( 18 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 19 | 20 | model = IFM(feature_columns, feature_columns, 21 | dnn_hidden_units=hidden_size, dnn_dropout=0.5, device=get_device()) 22 | check_model(model, model_name, x, y) 23 | 24 | 25 | if __name__ == "__main__": 26 | pass 27 | -------------------------------------------------------------------------------- /tests/models/MLR_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import MLR 5 | from ..utils import check_model, SAMPLE_SIZE, get_test_data, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 10 | 'region_sparse,region_dense,base_sparse,base_dense,bias_sparse,bias_dense', 11 | 12 | [(0, 2, 0, 2, 0, 1), (0, 2, 0, 1, 0, 2), (0, 2, 0, 0, 1, 0), 13 | (0, 1, 1, 2, 1, 1,), (0, 1, 1, 1, 1, 2), (0, 1, 1, 0, 2, 0), 14 | (1, 0, 2, 2, 2, 1), (2, 0, 2, 1, 2, 2), (2, 0, 2, 0, 0, 0) 15 | ] 16 | 17 | ) 18 | def test_MLRs(region_sparse, region_dense, base_sparse, base_dense, bias_sparse, bias_dense): 19 | model_name = "MLRs" 20 | region_x, y, region_feature_columns = get_test_data( 21 | SAMPLE_SIZE, region_sparse, region_dense, prefix='region') 22 | base_x, y, base_feature_columns = get_test_data( 23 | SAMPLE_SIZE, region_sparse, region_dense, prefix='base') 24 | bias_x, y, bias_feature_columns = get_test_data( 25 | SAMPLE_SIZE, region_sparse, region_dense, prefix='bias') 26 | 27 | model = MLR(region_feature_columns, base_feature_columns, 28 | bias_feature_columns=bias_feature_columns, device=get_device()) 29 | model.compile('adam', 'binary_crossentropy', 30 | metrics=['binary_crossentropy']) 31 | print(model_name + " test pass!") 32 | 33 | 34 | def test_MLR(): 35 | model_name = "MLR" 36 | region_x, y, region_feature_columns = get_test_data( 37 | SAMPLE_SIZE, 3, 3, prefix='region') 38 | base_x, y, base_feature_columns = get_test_data( 39 | SAMPLE_SIZE, 3, 3, prefix='base') 40 | bias_x, y, bias_feature_columns = get_test_data( 41 | SAMPLE_SIZE, 3, 3, prefix='bias') 42 | 43 | model = MLR(region_feature_columns, device=get_device()) 44 | model.compile('adam', 'binary_crossentropy', 45 | metrics=['binary_crossentropy']) 46 | 47 | check_model(model, model_name, region_x, y) 48 | print(model_name + " test pass!") 49 | 50 | 51 | if __name__ == "__main__": 52 | pass 53 | -------------------------------------------------------------------------------- /tests/models/NFM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import NFM 5 | from ..utils import check_model, get_test_data, SAMPLE_SIZE, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'hidden_size,sparse_feature_num', 10 | [((8,), 2), ((8, 8,), 2), ((8,), 1)] 11 | ) 12 | def test_NFM(hidden_size, sparse_feature_num): 13 | model_name = "NFM" 14 | 15 | sample_size = SAMPLE_SIZE 16 | x, y, feature_columns = get_test_data( 17 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 18 | 19 | model = NFM(feature_columns, feature_columns, 20 | dnn_hidden_units=[32, 32], dnn_dropout=0.5, device=get_device()) 21 | check_model(model, model_name, x, y) 22 | 23 | 24 | if __name__ == "__main__": 25 | pass 26 | -------------------------------------------------------------------------------- /tests/models/ONN_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from deepctr_torch.models import ONN 4 | from ..utils import check_model, get_test_data, SAMPLE_SIZE, get_device 5 | 6 | 7 | @pytest.mark.parametrize( 8 | 'hidden_size,sparse_feature_num', 9 | [((8,), 2)] 10 | ) 11 | def test_ONN(hidden_size, sparse_feature_num): 12 | model_name = "ONN" 13 | 14 | sample_size = SAMPLE_SIZE 15 | x, y, feature_columns = get_test_data( 16 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num, hash_flag=True) 17 | 18 | model = ONN(feature_columns, feature_columns, 19 | dnn_hidden_units=[32, 32], dnn_dropout=0.5, device=get_device()) 20 | check_model(model, model_name, x, y) 21 | 22 | 23 | if __name__ == "__main__": 24 | pass 25 | -------------------------------------------------------------------------------- /tests/models/PNN_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from deepctr_torch.models import PNN 4 | from ..utils import check_model, get_test_data, SAMPLE_SIZE, get_device 5 | 6 | 7 | @pytest.mark.parametrize( 8 | 'use_inner, use_outter, kernel_type, sparse_feature_num', 9 | [(True, True, 'mat', 2), (True, False, 'mat', 2), (False, True, 'vec', 3), (False, True, 'num', 3), 10 | (False, False, 'mat', 1) 11 | ] 12 | ) 13 | def test_PNN(use_inner, use_outter, kernel_type, sparse_feature_num): 14 | model_name = "PNN" 15 | sample_size = SAMPLE_SIZE 16 | x, y, feature_columns = get_test_data(sample_size, sparse_feature_num=sparse_feature_num, 17 | dense_feature_num=sparse_feature_num) 18 | model = PNN(feature_columns, dnn_hidden_units=[32, 32], dnn_dropout=0.5, use_inner=use_inner, 19 | use_outter=use_outter, kernel_type=kernel_type, device=get_device()) 20 | check_model(model, model_name, x, y) 21 | 22 | 23 | if __name__ == "__main__": 24 | pass 25 | -------------------------------------------------------------------------------- /tests/models/WDL_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import WDL 5 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'sparse_feature_num,dense_feature_num', 10 | [(2, 0), (0, 2), (2, 2) 11 | ] 12 | ) 13 | def test_WDL(sparse_feature_num, dense_feature_num): 14 | model_name = "WDL" 15 | sample_size = SAMPLE_SIZE 16 | x, y, feature_columns = get_test_data( 17 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 18 | 19 | model = WDL(feature_columns, feature_columns, dnn_activation='prelu', 20 | dnn_hidden_units=[32, 32], dnn_dropout=0.5, device=get_device()) 21 | check_model(model, model_name, x, y) 22 | 23 | 24 | if __name__ == "__main__": 25 | pass 26 | -------------------------------------------------------------------------------- /tests/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/tests/models/__init__.py -------------------------------------------------------------------------------- /tests/models/multitask/ESMM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import ESMM 5 | from ...utils_mtl import get_mtl_test_data, SAMPLE_SIZE, check_mtl_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'num_experts, tower_dnn_hidden_units, task_types, sparse_feature_num, dense_feature_num', 10 | [ 11 | (3, (32, 16), ['binary', 'binary'], 3, 3) 12 | ] 13 | ) 14 | def test_ESMM(num_experts, tower_dnn_hidden_units, task_types, 15 | sparse_feature_num, dense_feature_num): 16 | model_name = "ESMM" 17 | sample_size = SAMPLE_SIZE 18 | x, y_list, feature_columns = get_mtl_test_data( 19 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 20 | 21 | model = ESMM(feature_columns, tower_dnn_hidden_units=tower_dnn_hidden_units, 22 | task_types=task_types, device=get_device()) 23 | check_mtl_model(model, model_name, x, y_list, task_types) 24 | 25 | 26 | if __name__ == "__main__": 27 | pass 28 | -------------------------------------------------------------------------------- /tests/models/multitask/MMOE_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import MMOE 5 | from ...utils_mtl import get_mtl_test_data, SAMPLE_SIZE, check_mtl_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'num_experts, expert_dnn_hidden_units, gate_dnn_hidden_units, tower_dnn_hidden_units, task_types, ' 10 | 'sparse_feature_num, dense_feature_num', 11 | [ 12 | (3, (32, 16), (64,), (64,), ['binary', 'binary'], 3, 3), 13 | (3, (32, 16), (), (64,), ['binary', 'binary'], 3, 3), 14 | (3, (32, 16), (64,), (), ['binary', 'binary'], 3, 3), 15 | (3, (32, 16), (), (), ['binary', 'binary'], 3, 3), 16 | (3, (32, 16), (64,), (64,), ['binary', 'regression'], 3, 3), 17 | ] 18 | ) 19 | def test_MMOE(num_experts, expert_dnn_hidden_units, gate_dnn_hidden_units, tower_dnn_hidden_units, task_types, 20 | sparse_feature_num, dense_feature_num): 21 | model_name = "MMOE" 22 | sample_size = SAMPLE_SIZE 23 | x, y_list, feature_columns = get_mtl_test_data( 24 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 25 | 26 | model = MMOE(feature_columns, num_experts=num_experts, expert_dnn_hidden_units=expert_dnn_hidden_units, 27 | gate_dnn_hidden_units=gate_dnn_hidden_units, tower_dnn_hidden_units=tower_dnn_hidden_units, 28 | task_types=task_types, device=get_device()) 29 | check_mtl_model(model, model_name, x, y_list, task_types) 30 | 31 | 32 | if __name__ == "__main__": 33 | pass 34 | -------------------------------------------------------------------------------- /tests/models/multitask/PLE_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import PLE 5 | from ...utils_mtl import get_mtl_test_data, SAMPLE_SIZE, check_mtl_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'shared_expert_num, specific_expert_num, num_levels, expert_dnn_hidden_units, gate_dnn_hidden_units, ' 10 | 'tower_dnn_hidden_units, task_types, sparse_feature_num ,dense_feature_num', 11 | [ 12 | (1, 1, 2, (32, 16), (64,), (64,), ['binary', 'binary'], 3, 3), 13 | (3, 3, 3, (32, 16), (), (64,), ['binary', 'binary'], 3, 3), 14 | (3, 3, 3, (32, 16), (64,), (), ['binary', 'binary'], 3, 3), 15 | (3, 3, 3, (32, 16), (), (), ['binary', 'binary'], 3, 3), 16 | (3, 3, 3, (32, 16), (64,), (64,), ['binary', 'regression'], 3, 3), 17 | ] 18 | ) 19 | def test_PLE(shared_expert_num, specific_expert_num, num_levels, expert_dnn_hidden_units, gate_dnn_hidden_units, 20 | tower_dnn_hidden_units, task_types, sparse_feature_num, dense_feature_num): 21 | model_name = "PLE" 22 | sample_size = SAMPLE_SIZE 23 | x, y_list, feature_columns = get_mtl_test_data( 24 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 25 | 26 | model = PLE(feature_columns, shared_expert_num=shared_expert_num, specific_expert_num=specific_expert_num, 27 | num_levels=num_levels, expert_dnn_hidden_units=expert_dnn_hidden_units, 28 | gate_dnn_hidden_units=gate_dnn_hidden_units, tower_dnn_hidden_units=tower_dnn_hidden_units, 29 | task_types=task_types, device=get_device()) 30 | check_mtl_model(model, model_name, x, y_list, task_types) 31 | 32 | 33 | if __name__ == "__main__": 34 | pass 35 | -------------------------------------------------------------------------------- /tests/models/multitask/SharedBottom_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import SharedBottom 5 | from ...utils_mtl import get_mtl_test_data, SAMPLE_SIZE, check_mtl_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'num_experts, bottom_dnn_hidden_units, tower_dnn_hidden_units, task_types, sparse_feature_num, dense_feature_num', 10 | [ 11 | (3, (32, 16), (64,), ['binary', 'binary'], 3, 3), 12 | (3, (32, 16), (), ['binary', 'binary'], 3, 3), 13 | (3, (32, 16), (64,), ['binary', 'regression'], 3, 3), 14 | ] 15 | ) 16 | def test_SharedBottom(num_experts, bottom_dnn_hidden_units, tower_dnn_hidden_units, task_types, 17 | sparse_feature_num, dense_feature_num): 18 | model_name = "SharedBottom" 19 | sample_size = SAMPLE_SIZE 20 | x, y_list, feature_columns = get_mtl_test_data( 21 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=dense_feature_num) 22 | 23 | model = SharedBottom(feature_columns, bottom_dnn_hidden_units=bottom_dnn_hidden_units, 24 | tower_dnn_hidden_units=tower_dnn_hidden_units, 25 | task_types=task_types, device=get_device()) 26 | check_mtl_model(model, model_name, x, y_list, task_types) 27 | 28 | 29 | if __name__ == "__main__": 30 | pass 31 | -------------------------------------------------------------------------------- /tests/models/multitask/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shenweichen/DeepCTR-Torch/f6854257b1fc29caab655ce72c6b5528b7432574/tests/models/multitask/__init__.py -------------------------------------------------------------------------------- /tests/models/xDeepFM_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import pytest 3 | 4 | from deepctr_torch.models import xDeepFM 5 | from ..utils import get_test_data, SAMPLE_SIZE, check_model, get_device 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'dnn_hidden_units,cin_layer_size,cin_split_half,cin_activation,sparse_feature_num,dense_feature_dim', 10 | [((), (), True, 'linear', 1, 2), 11 | ((8,), (), True, 'linear', 1, 1), 12 | ((), (8,), True, 'linear', 2, 2), 13 | ((8,), (8,), False, 'relu', 2, 0)] 14 | ) 15 | def test_xDeepFM(dnn_hidden_units, cin_layer_size, cin_split_half, cin_activation, sparse_feature_num, 16 | dense_feature_dim): 17 | model_name = 'xDeepFM' 18 | 19 | sample_size = SAMPLE_SIZE 20 | x, y, feature_columns = get_test_data( 21 | sample_size, sparse_feature_num=sparse_feature_num, dense_feature_num=sparse_feature_num) 22 | model = xDeepFM(feature_columns, feature_columns, dnn_hidden_units=dnn_hidden_units, cin_layer_size=cin_layer_size, 23 | cin_split_half=cin_split_half, cin_activation=cin_activation, dnn_dropout=0.5, device=get_device()) 24 | check_model(model, model_name, x, y) 25 | 26 | 27 | if __name__ == '__main__': 28 | pass 29 | -------------------------------------------------------------------------------- /tests/utils_mtl.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | 4 | import numpy as np 5 | import torch as torch 6 | 7 | from deepctr_torch.callbacks import EarlyStopping, ModelCheckpoint 8 | from deepctr_torch.inputs import SparseFeat, DenseFeat, VarLenSparseFeat 9 | 10 | SAMPLE_SIZE = 64 11 | 12 | 13 | def gen_sequence(dim, max_len, sample_size): 14 | return np.array([np.random.randint(0, dim, max_len) for _ in range(sample_size)]), np.random.randint(1, max_len + 1, 15 | sample_size) 16 | 17 | 18 | def get_mtl_test_data(sample_size=1000, embedding_size=4, sparse_feature_num=1, dense_feature_num=1, 19 | sequence_feature=['sum', 'mean', 'max'], include_length=False, task_types=('binary', 'binary'), 20 | hash_flag=False, prefix=''): 21 | feature_columns = [] 22 | model_input = {} 23 | 24 | if 'weight' in sequence_feature: 25 | feature_columns.append( 26 | VarLenSparseFeat(SparseFeat(prefix + "weighted_seq", vocabulary_size=2, embedding_dim=embedding_size), 27 | maxlen=3, length_name=prefix + "weighted_seq" + "_seq_length", 28 | weight_name=prefix + "weight")) 29 | s_input, s_len_input = gen_sequence( 30 | 2, 3, sample_size) 31 | 32 | model_input[prefix + "weighted_seq"] = s_input 33 | model_input[prefix + 'weight'] = np.random.randn(sample_size, 3, 1) 34 | model_input[prefix + "weighted_seq" + "_seq_length"] = s_len_input 35 | sequence_feature.pop(sequence_feature.index('weight')) 36 | 37 | for i in range(sparse_feature_num): 38 | dim = np.random.randint(1, 10) 39 | feature_columns.append(SparseFeat(prefix + 'sparse_feature_' + str(i), dim, embedding_size, dtype=torch.int32)) 40 | for i in range(dense_feature_num): 41 | feature_columns.append(DenseFeat(prefix + 'dense_feature_' + str(i), 1, dtype=torch.float32)) 42 | for i, mode in enumerate(sequence_feature): 43 | dim = np.random.randint(1, 10) 44 | maxlen = np.random.randint(1, 10) 45 | feature_columns.append( 46 | VarLenSparseFeat(SparseFeat(prefix + 'sequence_' + mode, vocabulary_size=dim, embedding_dim=embedding_size), 47 | maxlen=maxlen, combiner=mode)) 48 | 49 | for fc in feature_columns: 50 | if isinstance(fc, SparseFeat): 51 | model_input[fc.name] = np.random.randint(0, fc.vocabulary_size, sample_size) 52 | elif isinstance(fc, DenseFeat): 53 | model_input[fc.name] = np.random.random(sample_size) 54 | else: 55 | s_input, s_len_input = gen_sequence( 56 | fc.vocabulary_size, fc.maxlen, sample_size) 57 | model_input[fc.name] = s_input 58 | if include_length: 59 | fc.length_name = prefix + "sequence_" + str(i) + '_seq_length' 60 | model_input[prefix + "sequence_" + str(i) + '_seq_length'] = s_len_input 61 | 62 | y_list = [] # multi label 63 | for task in task_types: 64 | if task == 'binary': 65 | y = np.random.randint(0, 2, sample_size) 66 | y_list.append(y) 67 | else: 68 | y = np.random.random(sample_size) 69 | y_list.append(y) 70 | y_list = np.array(y_list).transpose() # (sample_size, num_tasks) 71 | 72 | return model_input, y_list, feature_columns 73 | 74 | 75 | def check_mtl_model(model, model_name, x, y_list, task_types, check_model_io=True): 76 | ''' 77 | compile model,train and evaluate it,then save/load weight and model file. 78 | :param model: 79 | :param model_name: 80 | :param x: 81 | :param y_list: mutil label of y 82 | :param task_types: 83 | :param check_model_io: 84 | :return: 85 | ''' 86 | loss_list = [] 87 | for task_type in task_types: 88 | if task_type == 'binary': 89 | loss_list.append('binary_crossentropy') 90 | elif task_type == 'regression': 91 | loss_list.append('mae') 92 | print('loss:', loss_list) 93 | 94 | early_stopping = EarlyStopping(monitor='val_acc', min_delta=0, verbose=1, patience=0, mode='max') 95 | model_checkpoint = ModelCheckpoint(filepath='model.ckpt', monitor='val_acc', verbose=1, 96 | save_best_only=True, 97 | save_weights_only=False, mode='max', period=1) 98 | 99 | model.compile('adam', loss_list, metrics=['binary_crossentropy', 'acc']) 100 | model.fit(x, y_list, batch_size=100, epochs=1, validation_split=0.5, callbacks=[early_stopping, model_checkpoint]) 101 | 102 | print(model_name + 'test, train valid pass!') 103 | torch.save(model.state_dict(), model_name + '_weights.h5') 104 | model.load_state_dict(torch.load(model_name + '_weights.h5')) 105 | os.remove(model_name + '_weights.h5') 106 | print(model_name + 'test save load weight pass!') 107 | if check_model_io: 108 | torch.save(model, model_name + '.h5') 109 | model = torch.load(model_name + '.h5') 110 | os.remove(model_name + '.h5') 111 | print(model_name + 'test save load model pass!') 112 | print(model_name + 'test pass!') 113 | 114 | 115 | def get_device(use_cuda=True): 116 | device = 'cpu' 117 | if use_cuda and torch.cuda.is_available(): 118 | print('cuda ready...') 119 | device = 'cuda:0' 120 | return device 121 | --------------------------------------------------------------------------------