Skip to content

Commit

Permalink
Merge pull request #86 from shenweichen/dev-din
Browse files Browse the repository at this point in the history
add din&dien
  • Loading branch information
浅梦 committed Mar 27, 2020
2 parents baa240b + 954c3c6 commit bb60643
Show file tree
Hide file tree
Showing 26 changed files with 1,374 additions and 239 deletions.
90 changes: 68 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ Let's [**Get Started!**](https://deepctr-torch.readthedocs.io/en/latest/Quick-St
| Attentional Factorization Machine | [IJCAI 2017][Attentional Factorization Machines: Learning the Weight of Feature Interactions via Attention Networks](http://www.ijcai.org/proceedings/2017/435) |
| Neural Factorization Machine | [SIGIR 2017][Neural Factorization Machines for Sparse Predictive Analytics](https://arxiv.org/pdf/1708.05027.pdf) |
| xDeepFM | [KDD 2018][xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems](https://arxiv.org/pdf/1803.05170.pdf) |
| AutoInt | [arxiv 2018][AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks](https://arxiv.org/abs/1810.11921) |
| Deep Interest Network | [KDD 2018][Deep Interest Network for Click-Through Rate Prediction](https://arxiv.org/pdf/1706.06978.pdf) |
| Deep Interest Evolution Network | [AAAI 2019][Deep Interest Evolution Network for Click-Through Rate Prediction](https://arxiv.org/pdf/1809.03672.pdf) |
| AutoInt | [CIKM 2019][AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks](https://arxiv.org/abs/1810.11921) |
| ONN | [arxiv 2019][Operation-aware Neural Networks for User Response Prediction](https://arxiv.org/pdf/1904.12579.pdf) |
| FiBiNET | [RecSys 2019][FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction](https://arxiv.org/pdf/1905.09433.pdf) |

Expand All @@ -45,25 +47,69 @@ Please follow our wechat to join group:
- wechat ID: **deepctrbot**
![wechat](./docs/pics/weichennote.png)


## Contributors([welcome to join us!](./CONTRIBUTING.md))
<a href="https://github.com/shenweichen">
<img src="https://avatars.githubusercontent.com/shenweichen " width=70 height="70" alt="pic" >
</a>
<a href="https://github.com/wutongzhang">
<img src="https://avatars.githubusercontent.com/wutongzhang " width=70 height="70" alt="pic" >
</a>
<a href="https://github.com/JyiHUO">
<img src="https://avatars.githubusercontent.com/JyiHUO " width=70 height="70" alt="pic" >
</a>
<a href="https://github.com/Zengai">
<img src="https://avatars.githubusercontent.com/Zengai " width=70 height="70" alt="pic" >
</a>
<a href="https://github.com/chenkkkk">
<img src="https://avatars.githubusercontent.com/chenkkkk " width=70 height="70" alt="pic" >
</a>
<a href="https://github.com/tangaqi">
<img src="https://avatars.githubusercontent.com/tangaqi " width=70 height=70" alt="pic" >
</a>
<a href="https://github.com/uestc7d">
<img src="https://avatars.githubusercontent.com/uestc7d " width=70 height="70" alt="pic" >
</a>

<table border="0">
<tbody>
<tr align="center" >
<td>
​ <a href="https://github.com/shenweichen"><img width="70" height="70" src="https://github.com/shenweichen.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/shenweichen">Shen Weichen</a> ​
<p>Founder<br>
Zhejiang Unversity <br> <br> </p>​
</td>
<td>
<a href="https://github.com/weberrr"><img width="70" height="70" src="https://github.com/weberrr.png?s=40" alt="pic"></a><br>
<a href="https://github.com/weberrr">Wang Ze</a> ​
<p>Core Dev<br> Beihang University <br> <br> </p>​
</td>
<td>
​ <a href="https://github.com/wutongzhang"><img width="70" height="70" src="https://github.com/wutongzhang.png?s=40" alt="pic"></a><br>
<a href="https://github.com/wutongzhang">Zhang Wutong</a>
<p>Core Dev<br> Beijing University <br> of Posts and <br> Telecommunications</p>​
</td>
<td>
​ <a href="https://github.com/ZhangYuef"><img width="70" height="70" src="https://github.com/ZhangYuef.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/ZhangYuef">Zhang Yuefeng</a>
<p>Core Dev<br>
Peking University <br> <br> </p>​
</td>
<td>
​ <a href="https://github.com/JyiHUO"><img width="70" height="70" src="https://github.com/JyiHUO.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/JyiHUO">Huo Junyi</a>
<p>Core Dev<br>
University of Southampton <br> <br> </p>​
</td>
</tr>
<tr align="center">
<td>
​ <a href="https://github.com/Zengai"><img width="70" height="70" src="https://github.com/Zengai.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/Zengai">Zeng Kai</a> ​
<p>Dev<br>
SenseTime <br> <br> </p>​
</td>
<td>
​ <a href="https://github.com/chenkkkk"><img width="70" height="70" src="https://github.com/chenkkkk.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/chenkkkk">Chen K</a> ​
<p>Dev<br>
NetEase <br> <br> </p>​
</td>
<td>
​ <a href="https://github.com/tangaqi"><img width="70" height="70" src="https://github.com/tangaqi.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/tangaqi">Tang</a>
<p>Test<br>
Tongji University <br> <br> </p>​
</td>
<td>
​ <a href="https://github.com/uestc7d"><img width="70" height="70" src="https://github.com/uestc7d.png?s=40" alt="pic"></a><br>
​ <a href="https://github.com/uestc7d">Xu Qidi</a> ​
<p>Dev<br>
University of <br> Electronic Science and <br> Technology of China</p>​
</td>
<td>
<a href="https://github.com/shenweichen/DeepCTR-Torch/blob/master/CONTRIBUTING.md"> Welcome you !!</a>
</td>
</tr>
</tbody>
</table>
2 changes: 1 addition & 1 deletion deepctr_torch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
from . import models
from .utils import check_version

__version__ = '0.2.0'
__version__ = '0.2.1'
check_version(__version__)
176 changes: 98 additions & 78 deletions deepctr_torch/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
Weichen Shen,wcshen1994@163.com
"""

from collections import OrderedDict, namedtuple
from collections import OrderedDict, namedtuple, defaultdict
from itertools import chain

import torch
import torch.nn as nn
import numpy as np

from .layers.sequence import SequencePoolingLayer
from .layers.utils import concat_fun
Expand All @@ -27,7 +29,8 @@ def __new__(cls, name, vocabulary_size, embedding_dim=4, use_hash=False, dtype="
if embedding_dim == "auto":
embedding_dim = 6 * int(pow(vocabulary_size, 0.25))
if use_hash:
print("Notice! Feature Hashing on the fly currently is not supported in torch version,you can use tensorflow version!")
print(
"Notice! Feature Hashing on the fly currently is not supported in torch version,you can use tensorflow version!")
return super(SparseFeat, cls).__new__(cls, name, vocabulary_size, embedding_dim, use_hash, dtype,
embedding_name, group_name)

Expand Down Expand Up @@ -108,23 +111,14 @@ def build_input_features(feature_columns):
elif isinstance(feat, VarLenSparseFeat):
features[feat_name] = (start, start + feat.maxlen)
start += feat.maxlen
if feat.length_name is not None:
if feat.length_name is not None and feat.length_name not in features:
features[feat.length_name] = (start, start + 1)
start += 1
else:
raise TypeError("Invalid feature column type,got", type(feat))
return features


# def get_dense_input(features, feature_columns):
# dense_feature_columns = list(filter(lambda x: isinstance(
# x, DenseFeat), feature_columns)) if feature_columns else []
# dense_input_list = []
# for fc in dense_feature_columns:
# dense_input_list.append(features[fc.name])
# return dense_input_list


def combined_dnn_input(sparse_embedding_list, dense_value_list):
if len(sparse_embedding_list) > 0 and len(dense_value_list) > 0:
sparse_dnn_input = torch.flatten(
Expand All @@ -139,72 +133,6 @@ def combined_dnn_input(sparse_embedding_list, dense_value_list):
else:
raise NotImplementedError

#
# def embedding_lookup(sparse_embedding_dict, sparse_input_dict, sparse_feature_columns, return_feat_list=(),
# mask_feat_list=(), to_list=False):
# """
# Args:
# sparse_embedding_dict: nn.ModuleDict, {embedding_name: nn.Embedding}
# sparse_input_dict: OrderedDict, {feature_name:(start, start+dimension)}
# sparse_feature_columns: list, sparse features
# return_feat_list: list, names of feature to be returned, defualt () -> return all features
# mask_feat_list, list, names of feature to be masked in hash transform
# Return:
# group_embedding_dict: defaultdict(list)
# """
# group_embedding_dict = defaultdict(list)
# for fc in sparse_feature_columns:
# feature_name = fc.name
# embedding_name = fc.embedding_name
# if (len(return_feat_list) == 0 or feature_name in return_feat_list):
# if fc.use_hash:
# # lookup_idx = Hash(fc.vocabulary_size, mask_zero=(feature_name in mask_feat_list))(
# # sparse_input_dict[feature_name])
# # TODO: add hash function
# lookup_idx = sparse_input_dict[feature_name]
# else:
# lookup_idx = sparse_input_dict[feature_name]
#
# group_embedding_dict[fc.group_name].append(sparse_embedding_dict[embedding_name](lookup_idx))
# if to_list:
# return list(chain.from_iterable(group_embedding_dict.values()))
# return group_embedding_dict
#
#
# def varlen_embedding_lookup(embedding_dict, sequence_input_dict, varlen_sparse_feature_columns):
# varlen_embedding_vec_dict = {}
# for fc in varlen_sparse_feature_columns:
# feature_name = fc.name
# embedding_name = fc.embedding_name
# if fc.use_hash:
# # lookup_idx = Hash(fc.vocabulary_size, mask_zero=True)(sequence_input_dict[feature_name])
# # TODO: add hash function
# lookup_idx = sequence_input_dict[feature_name]
# else:
# lookup_idx = sequence_input_dict[feature_name]
# varlen_embedding_vec_dict[feature_name] = embedding_dict[embedding_name](lookup_idx)
# return varlen_embedding_vec_dict
#
#
# def get_varlen_pooling_list(embedding_dict, features, varlen_sparse_feature_columns, to_list=False):
# pooling_vec_list = defaultdict(list)
# for fc in varlen_sparse_feature_columns:
# feature_name = fc.name
# combiner = fc.combiner
# feature_length_name = fc.length_name
# if feature_length_name is not None:
# seq_input = embedding_dict[feature_name]
# vec = SequencePoolingLayer(combiner)([seq_input, features[feature_length_name]])
# else:
# seq_input = embedding_dict[feature_name]
# vec = SequencePoolingLayer(combiner)(seq_input)
# pooling_vec_list[fc.group_name].append(vec)
#
# if to_list:
# return chain.from_iterable(pooling_vec_list.values())
#
# return pooling_vec_list


def get_varlen_pooling_list(embedding_dict, features, feature_index, varlen_sparse_feature_columns, device):
varlen_sparse_embedding_list = []
Expand Down Expand Up @@ -249,3 +177,95 @@ def create_embedding_matrix(feature_columns, init_std=0.0001, linear=False, spar
nn.init.normal_(tensor.weight, mean=0, std=init_std)

return embedding_dict.to(device)


def input_from_feature_columns(self, X, feature_columns, embedding_dict, support_dense=True):
sparse_feature_columns = list(
filter(lambda x: isinstance(x, SparseFeat), feature_columns)) if len(feature_columns) else []
dense_feature_columns = list(
filter(lambda x: isinstance(x, DenseFeat), feature_columns)) if len(feature_columns) else []

varlen_sparse_feature_columns = list(
filter(lambda x: isinstance(x, VarLenSparseFeat), feature_columns)) if feature_columns else []

if not support_dense and len(dense_feature_columns) > 0:
raise ValueError(
"DenseFeat is not supported in dnn_feature_columns")

sparse_embedding_list = [embedding_dict[feat.embedding_name](
X[:, self.feature_index[feat.name][0]:self.feature_index[feat.name][1]].long()) for
feat in sparse_feature_columns]

varlen_sparse_embedding_list = get_varlen_pooling_list(self.embedding_dict, X, self.feature_index,
varlen_sparse_feature_columns, self.device)

dense_value_list = [X[:, self.feature_index[feat.name][0]:self.feature_index[feat.name][1]] for feat in
dense_feature_columns]

return sparse_embedding_list + varlen_sparse_embedding_list, dense_value_list



def embedding_lookup(X, sparse_embedding_dict, sparse_input_dict, sparse_feature_columns, return_feat_list=(),
mask_feat_list=(), to_list=False):
"""
Args:
X: input Tensor [batch_size x hidden_dim]
sparse_embedding_dict: nn.ModuleDict, {embedding_name: nn.Embedding}
sparse_input_dict: OrderedDict, {feature_name:(start, start+dimension)}
sparse_feature_columns: list, sparse features
return_feat_list: list, names of feature to be returned, defualt () -> return all features
mask_feat_list, list, names of feature to be masked in hash transform
Return:
group_embedding_dict: defaultdict(list)
"""
group_embedding_dict = defaultdict(list)
for fc in sparse_feature_columns:
feature_name = fc.name
embedding_name = fc.embedding_name
if (len(return_feat_list) == 0 or feature_name in return_feat_list):
# TODO: add hash function
# if fc.use_hash:
# raise NotImplementedError("hash function is not implemented in this version!")
lookup_idx = np.array(sparse_input_dict[feature_name])
input_tensor = X[:, lookup_idx[0]:lookup_idx[1]].long()
emb = sparse_embedding_dict[embedding_name](input_tensor)
group_embedding_dict[fc.group_name].append(emb)
if to_list:
return list(chain.from_iterable(group_embedding_dict.values()))
return group_embedding_dict


def varlen_embedding_lookup(X, embedding_dict, sequence_input_dict, varlen_sparse_feature_columns):
varlen_embedding_vec_dict = {}
for fc in varlen_sparse_feature_columns:
feature_name = fc.name
embedding_name = fc.embedding_name
if fc.use_hash:
# lookup_idx = Hash(fc.vocabulary_size, mask_zero=True)(sequence_input_dict[feature_name])
# TODO: add hash function
lookup_idx = sequence_input_dict[feature_name]
else:
lookup_idx = sequence_input_dict[feature_name]
varlen_embedding_vec_dict[feature_name] = embedding_dict[embedding_name](
X[:, lookup_idx[0]:lookup_idx[1]].long()) # (lookup_idx)

return varlen_embedding_vec_dict


def get_dense_input(X, features, feature_columns):
dense_feature_columns = list(filter(lambda x: isinstance(
x, DenseFeat), feature_columns)) if feature_columns else []
dense_input_list = []
for fc in dense_feature_columns:
lookup_idx = np.array(features[fc.name])
input_tensor = X[:, lookup_idx[0]:lookup_idx[1]].float()
dense_input_list.append(input_tensor)
return dense_input_list


def maxlen_lookup(X, sparse_input_dict, maxlen_column):
if maxlen_column is None or len(maxlen_column)==0:
raise ValueError('please add max length column for VarLenSparseFeat of DIEN input')
lookup_idx = np.array(sparse_input_dict[maxlen_column[0]])
return X[:, lookup_idx[0]:lookup_idx[1]].long()
2 changes: 1 addition & 1 deletion deepctr_torch/layers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .interaction import *
from .core import *
from .utils import concat_fun
from .sequence import KMaxPooling, SequencePoolingLayer
from .sequence import *
Loading

0 comments on commit bb60643

Please sign in to comment.