Skip to content

Commit 2d72040

Browse files
author
浅梦
authored
add flen
Add FLEN: Leveraging Field for Scalable CTR Prediction
1 parent 94bc0c4 commit 2d72040

26 files changed

+344
-130
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ Let's [**Get Started!**](https://deepctr-doc.readthedocs.io/en/latest/Quick-Star
4444
| FGCNN | [WWW 2019][Feature Generation by Convolutional Neural Network for Click-Through Rate Prediction ](https://arxiv.org/pdf/1904.04447) |
4545
| Deep Session Interest Network | [IJCAI 2019][Deep Session Interest Network for Click-Through Rate Prediction ](https://arxiv.org/abs/1905.06482) |
4646
| FiBiNET | [RecSys 2019][FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction](https://arxiv.org/pdf/1905.09433.pdf) |
47+
| FLEN | [arxiv 2019][FLEN: Leveraging Field for Scalable CTR Prediction](https://arxiv.org/pdf/1911.04690.pdf) |
48+
4749

4850

4951
## DisscussionGroup

deepctr/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from .utils import check_version
22

3-
__version__ = '0.7.3'
3+
__version__ = '0.7.4'
44
check_version(__version__)

deepctr/inputs.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,17 @@ def create_embedding_matrix(feature_columns, l2_reg, init_std, seed, prefix="",
177177

178178
def get_linear_logit(features, feature_columns, units=1, use_bias=False, init_std=0.0001, seed=1024, prefix='linear',
179179
l2_reg=0):
180-
for i in range(len(feature_columns)):
181-
if isinstance(feature_columns[i], SparseFeat):
182-
feature_columns[i] = feature_columns[i]._replace(embedding_dim=1)
183-
if isinstance(feature_columns[i], VarLenSparseFeat):
184-
feature_columns[i] = feature_columns[i]._replace(
185-
sparsefeat=feature_columns[i].sparsefeat._replace(embedding_dim=1))
186-
187-
linear_emb_list = [input_from_feature_columns(features, feature_columns, l2_reg, init_std, seed,
180+
linear_feature_columns = feature_columns.copy()
181+
for i in range(len(linear_feature_columns)):
182+
if isinstance(linear_feature_columns[i], SparseFeat):
183+
linear_feature_columns[i] = linear_feature_columns[i]._replace(embedding_dim=1)
184+
if isinstance(linear_feature_columns[i], VarLenSparseFeat):
185+
linear_feature_columns[i] = linear_feature_columns[i]._replace(
186+
sparsefeat=linear_feature_columns[i].sparsefeat._replace(embedding_dim=1))
187+
188+
linear_emb_list = [input_from_feature_columns(features, linear_feature_columns, l2_reg, init_std, seed,
188189
prefix=prefix + str(i))[0] for i in range(units)]
189-
_, dense_input_list = input_from_feature_columns(features, feature_columns, l2_reg, init_std, seed, prefix=prefix)
190+
_, dense_input_list = input_from_feature_columns(features, linear_feature_columns, l2_reg, init_std, seed, prefix=prefix)
190191

191192
linear_logit_list = []
192193
for i in range(units):

deepctr/layers/interaction.py

+49-44
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from tensorflow.python.layers import utils
1818

1919
from .activation import activation_layer
20-
from .utils import concat_func,reduce_sum,softmax,reduce_mean
20+
from .utils import concat_func, reduce_sum, softmax, reduce_mean
2121

2222

2323
class AFMLayer(Layer):
@@ -235,7 +235,7 @@ def build(self, input_shape):
235235
shape=[1, self.field_nums[-1]
236236
* self.field_nums[0], size],
237237
dtype=tf.float32, initializer=glorot_uniform(
238-
seed=self.seed + i),
238+
seed=self.seed + i),
239239
regularizer=l2(self.l2_reg)))
240240

241241
self.bias.append(self.add_weight(name='bias' + str(i), shape=[size], dtype=tf.float32,
@@ -906,11 +906,10 @@ class SENETLayer(Layer):
906906
- **seed** : A Python integer to use as random seed.
907907
908908
References
909-
- [FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction
910-
Tongwen](https://arxiv.org/pdf/1905.09433.pdf)
909+
- [FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction](https://arxiv.org/pdf/1905.09433.pdf)
911910
"""
912911

913-
def __init__(self, reduction_ratio=3, seed=1024, **kwargs):
912+
def __init__(self, reduction_ratio=3, seed=1024, **kwargs):
914913
self.reduction_ratio = reduction_ratio
915914

916915
self.seed = seed
@@ -924,7 +923,7 @@ def build(self, input_shape):
924923

925924
self.filed_size = len(input_shape)
926925
self.embedding_size = input_shape[0][-1]
927-
reduction_size = max(1, self.filed_size//self.reduction_ratio)
926+
reduction_size = max(1, self.filed_size // self.reduction_ratio)
928927

929928
self.W_1 = self.add_weight(shape=(
930929
self.filed_size, reduction_size), initializer=glorot_normal(seed=self.seed), name="W_1")
@@ -944,7 +943,7 @@ def call(self, inputs, training=None, **kwargs):
944943
"Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs)))
945944

946945
inputs = concat_func(inputs, axis=1)
947-
Z = reduce_mean(inputs, axis=-1,)
946+
Z = reduce_mean(inputs, axis=-1, )
948947

949948
A_1 = tf.nn.relu(self.tensordot([Z, self.W_1]))
950949
A_2 = tf.nn.relu(self.tensordot([A_1, self.W_2]))
@@ -957,7 +956,7 @@ def compute_output_shape(self, input_shape):
957956
return input_shape
958957

959958
def compute_mask(self, inputs, mask=None):
960-
return [None]*self.filed_size
959+
return [None] * self.filed_size
961960

962961
def get_config(self, ):
963962
config = {'reduction_ratio': self.reduction_ratio, 'seed': self.seed}
@@ -980,8 +979,7 @@ class BilinearInteraction(Layer):
980979
- **seed** : A Python integer to use as random seed.
981980
982981
References
983-
- [FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction
984-
Tongwen](https://arxiv.org/pdf/1905.09433.pdf)
982+
- [FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction](https://arxiv.org/pdf/1905.09433.pdf)
985983
986984
"""
987985

@@ -1003,10 +1001,11 @@ def build(self, input_shape):
10031001
seed=self.seed), name="bilinear_weight")
10041002
elif self.bilinear_type == "each":
10051003
self.W_list = [self.add_weight(shape=(embedding_size, embedding_size), initializer=glorot_normal(
1006-
seed=self.seed), name="bilinear_weight"+str(i)) for i in range(len(input_shape)-1)]
1004+
seed=self.seed), name="bilinear_weight" + str(i)) for i in range(len(input_shape) - 1)]
10071005
elif self.bilinear_type == "interaction":
10081006
self.W_list = [self.add_weight(shape=(embedding_size, embedding_size), initializer=glorot_normal(
1009-
seed=self.seed), name="bilinear_weight"+str(i)+'_'+str(j)) for i, j in itertools.combinations(range(len(input_shape)), 2)]
1007+
seed=self.seed), name="bilinear_weight" + str(i) + '_' + str(j)) for i, j in
1008+
itertools.combinations(range(len(input_shape)), 2)]
10101009
else:
10111010
raise NotImplementedError
10121011

@@ -1036,7 +1035,7 @@ def compute_output_shape(self, input_shape):
10361035
filed_size = len(input_shape)
10371036
embedding_size = input_shape[0][-1]
10381037

1039-
return (None, 1, filed_size*(filed_size-1)//2 * embedding_size)
1038+
return (None, 1, filed_size * (filed_size - 1) // 2 * embedding_size)
10401039

10411040
def get_config(self, ):
10421041
config = {'bilinear_type': self.bilinear_type, 'seed': self.seed}
@@ -1056,15 +1055,15 @@ class FieldWiseBiInteraction(Layer):
10561055
10571056
Arguments
10581057
- **use_bias** : Boolean, if use bias.
1059-
- **l2_reg** : Float, l2 regularization coefficient.
10601058
- **seed** : A Python integer to use as random seed.
1061-
1059+
10621060
References
1063-
[1] hen W, Zhan L, Ci Y, Lin C https://arxiv.org/pdf/1911.04690
1061+
- [FLEN: Leveraging Field for Scalable CTR Prediction](https://arxiv.org/pdf/1911.04690)
1062+
10641063
"""
1065-
def __init__(self, l2_reg=1e-5, seed=1024, **kwargs):
10661064

1067-
self.l2_reg = l2_reg
1065+
def __init__(self,use_bias=True, seed=1024, **kwargs):
1066+
self.use_bias = use_bias
10681067
self.seed = seed
10691068

10701069
super(FieldWiseBiInteraction, self).__init__(**kwargs)
@@ -1079,26 +1078,26 @@ def build(self, input_shape):
10791078
self.num_fields = len(input_shape)
10801079
embedding_size = input_shape[0][-1]
10811080

1082-
self.kernel_inter = self.add_weight(
1083-
name='kernel_inter',
1081+
self.kernel_mf = self.add_weight(
1082+
name='kernel_mf',
10841083
shape=(int(self.num_fields * (self.num_fields - 1) / 2), 1),
1085-
initializer=glorot_normal(seed=self.seed),
1086-
regularizer=l2(self.l2_reg),
1084+
initializer=tf.keras.initializers.Ones(),
1085+
regularizer=None,
10871086
trainable=True)
1088-
self.bias_inter = self.add_weight(name='bias_inter',
1089-
shape=(embedding_size),
1090-
initializer=Zeros(),
1091-
trainable=True)
1092-
self.kernel_intra = self.add_weight(
1093-
name='kernel_intra',
1087+
1088+
self.kernel_fm = self.add_weight(
1089+
name='kernel_fm',
10941090
shape=(self.num_fields, 1),
1095-
initializer=glorot_normal(seed=self.seed),
1096-
regularizer=l2(self.l2_reg),
1091+
initializer=tf.keras.initializers.Constant(value=0.5),
1092+
regularizer=None,
10971093
trainable=True)
1098-
self.bias_intra = self.add_weight(name='bias_intra',
1099-
shape=(embedding_size),
1100-
initializer=Zeros(),
1101-
trainable=True)
1094+
if self.use_bias:
1095+
self.bias_mf = self.add_weight(name='bias_mf',
1096+
shape=(embedding_size),
1097+
initializer=Zeros())
1098+
self.bias_fm = self.add_weight(name='bias_fm',
1099+
shape=(embedding_size),
1100+
initializer=Zeros())
11021101

11031102
super(FieldWiseBiInteraction,
11041103
self).build(input_shape) # Be sure to call this somewhere!
@@ -1120,10 +1119,10 @@ def call(self, inputs, **kwargs):
11201119

11211120
left = []
11221121
right = []
1123-
for i in range(self.num_fields):
1124-
for j in range(i + 1, self.num_fields):
1125-
left.append(i)
1126-
right.append(j)
1122+
1123+
for i, j in itertools.combinations(list(range(self.num_fields)), 2):
1124+
left.append(i)
1125+
right.append(j)
11271126

11281127
embeddings_left = tf.gather(params=field_wise_vectors,
11291128
indices=left,
@@ -1133,9 +1132,10 @@ def call(self, inputs, **kwargs):
11331132
axis=1)
11341133

11351134
embeddings_prod = embeddings_left * embeddings_right
1136-
field_weighted_embedding = embeddings_prod * self.kernel_inter
1135+
field_weighted_embedding = embeddings_prod * self.kernel_mf
11371136
h_mf = reduce_sum(field_weighted_embedding, axis=1)
1138-
h_mf = tf.nn.bias_add(h_mf, self.bias_inter)
1137+
if self.use_bias:
1138+
h_mf = tf.nn.bias_add(h_mf, self.bias_mf)
11391139

11401140
# FM module
11411141
square_of_sum_list = [
@@ -1154,11 +1154,16 @@ def call(self, inputs, **kwargs):
11541154
zip(square_of_sum_list, sum_of_square_list)
11551155
], 1)
11561156

1157-
h_fm = reduce_sum(field_fm * self.kernel_intra, axis=1)
1158-
1159-
h_fm = tf.nn.bias_add(h_fm, self.bias_intra)
1157+
h_fm = reduce_sum(field_fm * self.kernel_fm, axis=1)
1158+
if self.use_bias:
1159+
h_fm = tf.nn.bias_add(h_fm, self.bias_fm)
11601160

11611161
return h_mf + h_fm
11621162

11631163
def compute_output_shape(self, input_shape):
1164-
return (None, input_shape[0][-1])
1164+
return (None, input_shape[0][-1])
1165+
1166+
def get_config(self, ):
1167+
config = {'use_bias': self.use_bias, 'seed': self.seed}
1168+
base_config = super(FieldWiseBiInteraction, self).get_config()
1169+
return dict(list(base_config.items()) + list(config.items()))

deepctr/models/flen.py

+25-35
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,40 @@
44
Tingyi Tan,[email protected]
55
66
Reference:
7-
[1] hen W, Zhan L, Ci Y, Lin C https://arxiv.org/pdf/1911.04690
7+
[1] Chen W, Zhan L, Ci Y, Lin C. FLEN: Leveraging Field for Scalable CTR Prediction . arXiv preprint arXiv:1911.04690, 2019.(https://arxiv.org/pdf/1911.04690)
88
99
"""
1010

11-
1211
from itertools import chain
12+
1313
import tensorflow as tf
14-
from tensorflow.python.keras.layers import Flatten
1514

1615
from ..inputs import input_from_feature_columns, get_linear_logit, build_input_features, combined_dnn_input
1716
from ..layers.core import PredictionLayer, DNN
18-
from ..layers.utils import concat_func, add_func
1917
from ..layers.interaction import FieldWiseBiInteraction
18+
from ..layers.utils import concat_func, add_func
2019

2120

2221
def FLEN(linear_feature_columns,
23-
dnn_feature_columns,
24-
l2_reg_linear=0.00001,
25-
l2_reg_embedding=0.00001,
26-
l2_reg_dnn=0.00001,
27-
l2_reg_fw=0.00001,
28-
init_std=0.0001,
29-
seed=1024,
30-
dnn_dropout=0.2,
31-
dnn_activation='relu',
32-
dnn_use_bn=True,
33-
task='binary'):
34-
"""Instantiates the DeepFM Network architecture.
22+
dnn_feature_columns,
23+
dnn_hidden_units=(128, 128),
24+
l2_reg_linear=0.00001,
25+
l2_reg_embedding=0.00001,
26+
l2_reg_dnn=0,
27+
init_std=0.0001,
28+
seed=1024,
29+
dnn_dropout=0.0,
30+
dnn_activation='relu',
31+
dnn_use_bn=False,
32+
task='binary'):
33+
"""Instantiates the FLEN Network architecture.
3534
3635
:param linear_feature_columns: An iterable containing all the features used by linear part of the model.
3736
:param dnn_feature_columns: An iterable containing all the features used by deep part of the model.
37+
:param dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of deep net
3838
:param l2_reg_linear: float. L2 regularizer strength applied to linear part
3939
:param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
4040
:param l2_reg_dnn: float. L2 regularizer strength applied to DNN
41-
:param l2_reg_fw: float. L2 regularizer strength applied to fwfm
4241
:param init_std: float,to use as the initialize std of embedding vector
4342
:param seed: integer ,to use as random seed.
4443
:param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate.
@@ -61,35 +60,26 @@ def FLEN(linear_feature_columns,
6160
seed,
6261
support_group=True)
6362

64-
# S
6563
linear_logit = get_linear_logit(features,
6664
linear_feature_columns,
6765
init_std=init_std,
6866
seed=seed,
6967
prefix='linear',
7068
l2_reg=l2_reg_linear)
71-
linear_logit = Flatten()(linear_logit)
7269

73-
# FM + MF
74-
fm_mf_out = FieldWiseBiInteraction(l2_reg=l2_reg_fw, seed=seed)(
70+
fm_mf_out = FieldWiseBiInteraction(seed=seed)(
7571
[concat_func(v, axis=1) for k, v in group_embedding_dict.items()])
76-
fm_mf_out = DNN((32,), dnn_activation, l2_reg_dnn, dnn_dropout,
77-
dnn_use_bn, seed)(fm_mf_out)
7872

79-
# MLP
80-
mlp_input = combined_dnn_input(
73+
dnn_input = combined_dnn_input(
8174
list(chain.from_iterable(group_embedding_dict.values())),
8275
dense_value_list)
83-
mlp_output = DNN((64,), dnn_activation, l2_reg_dnn, dnn_dropout,
84-
dnn_use_bn, seed)(mlp_input)
85-
mlp_output = DNN((32,), dnn_activation, l2_reg_dnn, dnn_dropout,
86-
dnn_use_bn, seed)(mlp_output)
76+
dnn_output = DNN(dnn_hidden_units, dnn_activation, l2_reg_dnn, dnn_dropout,
77+
dnn_use_bn, seed)(dnn_input)
78+
79+
dnn_logit = tf.keras.layers.Dense(1, use_bias=False, activation=None)(concat_func([fm_mf_out, dnn_output]))
8780

88-
# DNN
89-
dnn_input = combined_dnn_input([fm_mf_out, mlp_output, linear_logit], dense_value_list)
90-
dnn_output = dnn_input
91-
dnn_logit = tf.keras.layers.Dense(1, use_bias=False, activation=None)(dnn_output)
92-
output = PredictionLayer(task)(dnn_logit)
81+
final_logit = add_func([linear_logit, dnn_logit])
82+
output = PredictionLayer(task)(final_logit)
9383

9484
model = tf.keras.models.Model(inputs=inputs_list, outputs=output)
95-
return model
85+
return model

docs/pics/FLEN.jpg

135 KB
Loading

docs/source/Features.md

+11
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,17 @@ Feature Importance and Bilinear feature Interaction NETwork is proposed to dynam
264264

265265
[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.](https://arxiv.org/pdf/1905.09433.pdf)
266266

267+
### FLEN(Field-Leveraged Embedding Network)
268+
269+
A large-scale CTR prediction model with efficient usage of field information to alleviate gradient coupling problem.
270+
271+
[**FLEN Model API**](./deepctr.models.flen.html)
272+
273+
[FLEN example](https://github.com/shenweichen/DeepCTR/tree/master/examples/run_flen.py)
274+
275+
![FLEN](../pics/FLEN.jpg)
276+
277+
[Chen W, Zhan L, Ci Y, Lin C. FLEN: Leveraging Field for Scalable CTR Prediction[J]. arXiv preprint arXiv:1911.04690, 2019.](https://arxiv.org/pdf/1911.04690.pdf)
267278

268279
## Layers
269280

docs/source/History.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# History
2+
- 03/15/2020 : [v0.7.4](https://github.com/shenweichen/DeepCTR/releases/tag/v0.7.4) released.Add [FLEN](./Features.html#flen-field-leveraged-embedding-network) and `FieldWiseBiInteraction`.
23
- 03/04/2020 : [v0.7.3](https://github.com/shenweichen/DeepCTR/releases/tag/v0.7.3) released.Fix the inconsistency of prediction results when the model is loaded with trained weights.
34
- 02/08/2020 : [v0.7.2](https://github.com/shenweichen/DeepCTR/releases/tag/v0.7.2) released.Fix some bugs.
45
- 01/28/2020 : [v0.7.1](https://github.com/shenweichen/DeepCTR/releases/tag/v0.7.1) released.Simplify [VarLenSparseFeat](./Features.html#varlensparsefeat),support setting weight_normalization.Fix problem of embedding size of `SparseFeat` in `linear_feature_columns`.

docs/source/Models.rst

+1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ DeepCTR Models API
2020
ONN<deepctr.models.onn>
2121
FGCNN<deepctr.models.fgcnn>
2222
FiBiNET<deepctr.models.fibinet>
23+
FLEN<deepctr.models.flen>
2324

docs/source/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
# The short X.Y version
2727
version = ''
2828
# The full version, including alpha/beta/rc tags
29-
release = '0.7.3'
29+
release = '0.7.4'
3030

3131

3232
# -- General configuration ---------------------------------------------------

docs/source/deepctr.models.flen.rst

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
deepctr.models.flen module
2+
=============================
3+
4+
.. automodule:: deepctr.models.flen
5+
:members:
6+
:no-undoc-members:
7+
:no-show-inheritance:

0 commit comments

Comments
 (0)