Skip to content

Commit b787cdf

Browse files
author
浅梦
authored
pull dev for v0.4.1
add DSIN refactor layers
1 parent 6713b8c commit b787cdf

26 files changed

+446
-127
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ Let's [**Get Started!**](https://deepctr-doc.readthedocs.io/en/latest/Quick-Star
3636
| Deep Interest Network | [KDD 2018][Deep Interest Network for Click-Through Rate Prediction](https://arxiv.org/pdf/1706.06978.pdf) |
3737
| Deep Interest Evolution Network | [AAAI 2019][Deep Interest Evolution Network for Click-Through Rate Prediction](https://arxiv.org/pdf/1809.03672.pdf) |
3838
| AutoInt | [arxiv 2018][AutoInt: Automatic Feature Interaction Learning via Self-Attentive Neural Networks](https://arxiv.org/abs/1810.11921) |
39-
| NFFM | [arxiv 2019][Field-aware Neural Factorization Machine for Click-Through Rate Prediction ](https://arxiv.org/pdf/1902.09096.pdf) (The original NFFM was first used by Yi Yang([email protected]) in TSA competition in 2017.) |
40-
| FGCNN | [WWW 2019][Feature Generation by Convolutional Neural Network for Click-Through Rate Prediction ](https://arxiv.org/pdf/1904.04447))
39+
| NFFM | [arxiv 2019][Field-aware Neural Factorization Machine for Click-Through Rate Prediction ](https://arxiv.org/pdf/1902.09096.pdf) (The original NFFM was used by Yi Yang([email protected]) in TSA competition.) |
40+
| FGCNN | [WWW 2019][Feature Generation by Convolutional Neural Network for Click-Through Rate Prediction ](https://arxiv.org/pdf/1904.04447) |
41+
| Deep Session Interest Network | [IJCAI 2019][Deep Session Interest Network for Click-Through Rate Prediction ](https://arxiv.org/abs/1905.06482) |
4142

4243

4344

deepctr/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
from . import models
33
from .utils import check_version
44

5-
__version__ = '0.4.0'
5+
__version__ = '0.4.1'
66
check_version(__version__)

deepctr/input_embedding.py

+16-18
Original file line numberDiff line numberDiff line change
@@ -13,62 +13,60 @@
1313
from tensorflow.python.keras.layers import Concatenate, Dense, Embedding, Input, Reshape, add
1414
from tensorflow.python.keras.regularizers import l2
1515

16-
from deepctr.layers import Hash
1716
from .layers.sequence import SequencePoolingLayer
1817
from .layers.utils import Hash
1918

2019

2120
def create_singlefeat_inputdict(feature_dim_dict, prefix=''):
2221
sparse_input = OrderedDict()
23-
for i, feat in enumerate(feature_dim_dict["sparse"]):
22+
for feat in feature_dim_dict["sparse"]:
2423
sparse_input[feat.name] = Input(
25-
shape=(1,), name=feat.name, dtype=feat.dtype) # prefix+'sparse_' + str(i) + '-' + feat.name)
24+
shape=(1,), name=prefix+feat.name, dtype=feat.dtype)
2625

2726
dense_input = OrderedDict()
2827

29-
for i, feat in enumerate(feature_dim_dict["dense"]):
28+
for feat in feature_dim_dict["dense"]:
3029
dense_input[feat.name] = Input(
31-
shape=(1,), name=feat.name) # prefix+'dense_' + str(i) + '-' + feat.name)
30+
shape=(1,), name=prefix+feat.name,dtype=feat.dtype)
3231

3332
return sparse_input, dense_input
3433

3534

36-
def create_varlenfeat_inputdict(feature_dim_dict, mask_zero=True):
35+
def create_varlenfeat_inputdict(feature_dim_dict, mask_zero=True,prefix=''):
3736
sequence_dim_dict = feature_dim_dict.get('sequence', [])
3837
sequence_input_dict = OrderedDict()
39-
for i, feat in enumerate(sequence_dim_dict):
40-
sequence_input_dict[feat.name] = Input(shape=(feat.maxlen,), name='seq_' + str(
41-
i) + '-' + feat.name, dtype=feat.dtype)
38+
for feat in sequence_dim_dict:
39+
sequence_input_dict[feat.name] = Input(shape=(feat.maxlen,), name=prefix+'seq_' + feat.name, dtype=feat.dtype)
4240

4341
if mask_zero:
4442
sequence_len_dict, sequence_max_len_dict = None, None
4543
else:
4644
sequence_len_dict = {feat.name: Input(shape=(
47-
1,), name='seq_length' + str(i) + '-' + feat.name) for i, feat in enumerate(sequence_dim_dict)}
45+
1,), name=prefix+'seq_length_' + feat.name) for feat in sequence_dim_dict}
4846
sequence_max_len_dict = {feat.name: feat.maxlen
49-
for i, feat in enumerate(sequence_dim_dict)}
47+
for feat in sequence_dim_dict}
5048
return sequence_input_dict, sequence_len_dict, sequence_max_len_dict
5149

5250

53-
def create_embedding_dict(feature_dim_dict, embedding_size, init_std, seed, l2_reg, prefix='sparse',
51+
def create_embedding_dict(feature_dim_dict, embedding_size, init_std, seed, l2_reg, prefix='sparse_',
5452
seq_mask_zero=True):
5553
if embedding_size == 'auto':
5654
print("Notice:Do not use auto embedding in models other than DCN")
5755
sparse_embedding = {feat.name: Embedding(feat.dimension, 6 * int(pow(feat.dimension, 0.25)),
5856
embeddings_initializer=RandomNormal(
5957
mean=0.0, stddev=init_std, seed=seed),
6058
embeddings_regularizer=l2(l2_reg),
61-
name=prefix + '_emb_' + str(i) + '-' + feat.name) for i, feat in
62-
enumerate(feature_dim_dict["sparse"])}
59+
name=prefix + 'emb_' + feat.name) for feat in
60+
feature_dim_dict["sparse"]}
6361
else:
6462

6563
sparse_embedding = {feat.name: Embedding(feat.dimension, embedding_size,
6664
embeddings_initializer=RandomNormal(
6765
mean=0.0, stddev=init_std, seed=seed),
6866
embeddings_regularizer=l2(
6967
l2_reg),
70-
name=prefix + '_emb_' + str(i) + '-' + feat.name) for i, feat in
71-
enumerate(feature_dim_dict["sparse"])}
68+
name=prefix + 'emb_' + feat.name) for feat in
69+
feature_dim_dict["sparse"]}
7270

7371
if 'sequence' in feature_dim_dict:
7472
count = len(sparse_embedding)
@@ -81,7 +79,7 @@ def create_embedding_dict(feature_dim_dict, embedding_size, init_std, seed, l2_r
8179
mean=0.0, stddev=init_std, seed=seed),
8280
embeddings_regularizer=l2(
8381
l2_reg),
84-
name=prefix + '_emb_' + str(count) + '-' + feat.name,
82+
name=prefix + 'seq_emb_' + feat.name,
8583
mask_zero=seq_mask_zero)
8684

8785
else:
@@ -90,7 +88,7 @@ def create_embedding_dict(feature_dim_dict, embedding_size, init_std, seed, l2_r
9088
mean=0.0, stddev=init_std, seed=seed),
9189
embeddings_regularizer=l2(
9290
l2_reg),
93-
name=prefix + '_emb_' + str(count) + '-' + feat.name,
91+
name=prefix + 'seq_emb_' + feat.name,
9492
mask_zero=seq_mask_zero)
9593

9694
count += 1

deepctr/layers/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
OutterProductLayer, FGCNNLayer)
88
from .normalization import LayerNormalization
99
from .sequence import (AttentionSequencePoolingLayer, BiasEncoding, BiLSTM,
10-
KMaxPooling, Position_Embedding, SequencePoolingLayer,
10+
KMaxPooling, SequencePoolingLayer,
1111
Transformer, DynamicGRU)
1212
from .utils import NoMask, Hash
1313

deepctr/layers/activation.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ def get_config(self, ):
5959
base_config = super(Dice, self).get_config()
6060
return dict(list(base_config.items()) + list(config.items()))
6161

62-
def activation_fun(activation, fc):
62+
def activation_layer(activation):
6363
if activation == "dice" or activation == "Dice":
64-
fc = Dice()(fc)
64+
act_layer = Dice()
6565
elif (isinstance(activation, str)) or (sys.version_info.major == 2 and isinstance(activation, (str, unicode))):
66-
fc = tf.keras.layers.Activation(activation)(fc)
66+
act_layer = tf.keras.layers.Activation(activation)
6767
elif issubclass(activation, Layer):
68-
fc = activation()(fc)
68+
act_layer = activation()
6969
else:
7070
raise ValueError(
7171
"Invalid activation,found %s.You should use a str or a Activation Layer Class." % (activation))
72-
return fc
72+
return act_layer

deepctr/layers/core.py

+20-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from tensorflow.python.keras.layers import Layer
1313
from tensorflow.python.keras.regularizers import l2
1414

15-
from .activation import activation_fun
15+
from .activation import activation_layer
1616

1717

1818
class LocalActivationUnit(Layer):
@@ -76,8 +76,12 @@ def build(self, input_shape):
7676
name="kernel")
7777
self.bias = self.add_weight(
7878
shape=(1,), initializer=Zeros(), name="bias")
79-
#self.dnn = DNN(self.hidden_units, self.activation, self.l2_reg,
80-
# self.dropout_rate, self.use_bn, seed=self.seed)
79+
self.dnn = DNN(self.hidden_units, self.activation, self.l2_reg,
80+
self.dropout_rate, self.use_bn, seed=self.seed)
81+
82+
self.dense = tf.keras.layers.Lambda(lambda x:tf.nn.bias_add(tf.tensordot(
83+
x[0], x[1], axes=(-1, 0)), x[2]))
84+
8185
super(LocalActivationUnit, self).build(
8286
input_shape) # Be sure to call this somewhere!
8387

@@ -91,10 +95,9 @@ def call(self, inputs, training=None, **kwargs):
9195
att_input = tf.concat(
9296
[queries, keys, queries - keys, queries * keys], axis=-1)
9397

94-
att_out = DNN(self.hidden_units, self.activation, self.l2_reg,
95-
self.dropout_rate, self.use_bn, seed=self.seed)(att_input, training=training)
96-
attention_score = tf.keras.layers.Lambda(lambda x:tf.nn.bias_add(tf.tensordot(
97-
x[0], x[1], axes=(-1, 0)), x[2]))([att_out,self.kernel,self.bias])
98+
att_out = self.dnn(att_input, training=training)
99+
100+
attention_score = self.dense([att_out,self.kernel,self.bias])
98101

99102
return attention_score
100103

@@ -157,6 +160,12 @@ def build(self, input_shape):
157160
shape=(self.hidden_units[i],),
158161
initializer=Zeros(),
159162
trainable=True) for i in range(len(self.hidden_units))]
163+
if self.use_bn:
164+
self.bn_layers = [tf.keras.layers.BatchNormalization() for _ in range(len(self.hidden_units))]
165+
166+
self.dropout_layers = [tf.keras.layers.Dropout(self.dropout_rate,seed=self.seed+i) for i in range(len(self.hidden_units))]
167+
168+
self.activation_layers = [activation_layer(self.activation) for _ in range(len(self.hidden_units))]
160169

161170
super(DNN, self).build(input_shape) # Be sure to call this somewhere!
162171

@@ -171,10 +180,11 @@ def call(self, inputs, training=None, **kwargs):
171180
# kernel_initializer=glorot_normal(seed=self.seed), \
172181
# kernel_regularizer=l2(self.l2_reg))(deep_input)
173182
if self.use_bn:
174-
fc = tf.keras.layers.BatchNormalization()(fc, training=training)
175-
fc = activation_fun(self.activation, fc)
183+
fc = self.bn_layers[i](fc, training=training)
184+
185+
fc = self.activation_layers[i](fc)
176186

177-
fc = tf.keras.layers.Dropout(self.dropout_rate,seed=self.seed)(fc, training=training)
187+
fc = self.dropout_layers[i](fc,training = training)
178188
deep_input = fc
179189

180190
return deep_input

deepctr/layers/interaction.py

+65-17
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
glorot_uniform)
1515
from tensorflow.python.keras.layers import Layer
1616
from tensorflow.python.keras.regularizers import l2
17+
from tensorflow.python.layers import utils
1718

18-
from .activation import activation_fun
19+
from .activation import activation_layer
1920
from .utils import concat_fun
2021

2122

@@ -87,6 +88,8 @@ def build(self, input_shape):
8788
embedding_size, 1), initializer=glorot_normal(seed=self.seed), name="projection_p")
8889
self.dropout = tf.keras.layers.Dropout(self.dropout_rate, seed=self.seed)
8990

91+
self.tensordot = tf.keras.layers.Lambda(lambda x: tf.tensordot(x[0], x[1], axes=(-1, 0)))
92+
9093
# Be sure to call this somewhere!
9194
super(AFMLayer, self).build(input_shape)
9295

@@ -119,9 +122,7 @@ def call(self, inputs, training=None, **kwargs):
119122

120123
attention_output = self.dropout(attention_output) # training
121124

122-
afm_out = tf.keras.layers.Lambda(lambda x: tf.tensordot(x[0], x[1]
123-
, axes=(-1, 0)))([attention_output, self.projection_p])
124-
125+
afm_out = self.tensordot([attention_output, self.projection_p])
125126
return afm_out
126127

127128
def compute_output_shape(self, input_shape):
@@ -246,6 +247,8 @@ def build(self, input_shape):
246247
else:
247248
self.field_nums.append(size)
248249

250+
self.activation_layers = [activation_layer(self.activation) for _ in self.layer_size]
251+
249252
super(CIN, self).build(input_shape) # Be sure to call this somewhere!
250253

251254
def call(self, inputs, **kwargs):
@@ -275,7 +278,7 @@ def call(self, inputs, **kwargs):
275278

276279
curr_out = tf.nn.bias_add(curr_out, self.bias[idx])
277280

278-
curr_out = activation_fun(self.activation, curr_out)
281+
curr_out = self.activation_layers[idx](curr_out)
279282

280283
curr_out = tf.transpose(curr_out, perm=[0, 2, 1])
281284

@@ -783,6 +786,26 @@ def build(self, input_shape):
783786
if len(input_shape) != 3:
784787
raise ValueError(
785788
"Unexpected inputs dimensions %d, expect to be 3 dimensions" % (len(input_shape)))
789+
self.conv_layers = []
790+
self.pooling_layers = []
791+
self.dense_layers = []
792+
pooling_shape = input_shape.as_list() + [1, ]
793+
embedding_size = input_shape[-1].value
794+
for i in range(1, len(self.filters) + 1):
795+
filters = self.filters[i - 1]
796+
width = self.kernel_width[i - 1]
797+
new_filters = self.new_maps[i - 1]
798+
pooling_width = self.pooling_width[i - 1]
799+
conv_output_shape = self._conv_output_shape(pooling_shape, (width, 1))
800+
pooling_shape = self._pooling_output_shape(conv_output_shape, (pooling_width, 1))
801+
self.conv_layers.append(tf.keras.layers.Conv2D(filters=filters, kernel_size=(width, 1), strides=(1, 1),
802+
padding='same',
803+
activation='tanh', use_bias=True, ))
804+
self.pooling_layers.append(tf.keras.layers.MaxPooling2D(pool_size=(pooling_width, 1)))
805+
self.dense_layers.append(tf.keras.layers.Dense(pooling_shape[1] * embedding_size * new_filters,
806+
activation='tanh', use_bias=True))
807+
808+
self.flatten = tf.keras.layers.Flatten()
786809

787810
super(FGCNNLayer, self).build(
788811
input_shape) # Be sure to call this somewhere!
@@ -794,24 +817,24 @@ def call(self, inputs, **kwargs):
794817
"Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs)))
795818

796819
embedding_size = inputs.shape[-1].value
797-
pooling_result = tf.keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=3))(inputs)
820+
pooling_result = tf.expand_dims(inputs, axis=3)
798821

799822
new_feature_list = []
800823

801824
for i in range(1, len(self.filters) + 1):
802-
filters = self.filters[i - 1]
803-
width = self.kernel_width[i - 1]
804825
new_filters = self.new_maps[i - 1]
805-
pooling_width = self.pooling_width[i - 1]
806-
conv_result = tf.keras.layers.Conv2D(filters=filters, kernel_size=(width, 1), strides=(1, 1),
807-
padding='same',
808-
activation='tanh', use_bias=True, )(pooling_result)
809-
pooling_result = tf.keras.layers.MaxPooling2D(pool_size=(pooling_width, 1))(conv_result)
810-
flatten_result = tf.keras.layers.Flatten()(pooling_result)
811-
new_result = tf.keras.layers.Dense(pooling_result.shape[1].value * embedding_size * new_filters,
812-
activation='tanh', use_bias=True)(flatten_result)
826+
827+
conv_result = self.conv_layers[i - 1](pooling_result)
828+
829+
pooling_result = self.pooling_layers[i - 1](conv_result)
830+
831+
flatten_result = self.flatten(pooling_result)
832+
833+
new_result = self.dense_layers[i - 1](flatten_result)
834+
813835
new_feature_list.append(
814-
tf.keras.layers.Reshape((pooling_result.shape[1].value * new_filters, embedding_size))(new_result))
836+
tf.reshape(new_result, (-1, pooling_result.shape[1].value * new_filters, embedding_size)))
837+
815838
new_features = concat_fun(new_feature_list, axis=1)
816839
return new_features
817840

@@ -832,3 +855,28 @@ def get_config(self, ):
832855
'pooling_width': self.pooling_width}
833856
base_config = super(FGCNNLayer, self).get_config()
834857
return dict(list(base_config.items()) + list(config.items()))
858+
859+
def _conv_output_shape(self, input_shape, kernel_size):
860+
# channels_last
861+
space = input_shape[1:-1]
862+
new_space = []
863+
for i in range(len(space)):
864+
new_dim = utils.conv_output_length(
865+
space[i],
866+
kernel_size[i],
867+
padding='same',
868+
stride=1,
869+
dilation=1)
870+
new_space.append(new_dim)
871+
return ([input_shape[0]] + new_space + [self.filters])
872+
873+
def _pooling_output_shape(self, input_shape, pool_size):
874+
# channels_last
875+
876+
rows = input_shape[1]
877+
cols = input_shape[2]
878+
rows = utils.conv_output_length(rows, pool_size[0], 'valid',
879+
pool_size[0])
880+
cols = utils.conv_output_length(cols, pool_size[1], 'valid',
881+
pool_size[1])
882+
return [input_shape[0], rows, cols, input_shape[3]]

0 commit comments

Comments
 (0)