diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index f660b34..7a0a0a6 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -18,9 +18,9 @@ Steps to reproduce the behavior:
4. See error
**Operating environment(运行环境):**
- - python version [e.g. 3.6, 3.7]
- - tensorflow version [e.g. 1.4.0, 1.14.0, 2.3.0]
- - deepmatch version [e.g. 0.2.0,]
+ - python version [e.g. 3.6, 3.7, 3.8]
+ - tensorflow version [e.g. 1.4.0, 1.14.0, 2.5.0]
+ - deepmatch version [e.g. 0.2.1,]
**Additional context**
Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
index f6d65c0..2cabbcb 100644
--- a/.github/ISSUE_TEMPLATE/question.md
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -15,6 +15,6 @@ A clear and concise description of what the question is.
Add any other context about the problem here.
**Operating environment(运行环境):**
- - python version [e.g. 3.6]
- - tensorflow version [e.g. 1.4.0,]
- - deepmatch version [e.g. 0.2.0,]
+ - python version [e.g. 3.6, 3.7, 3.8]
+ - tensorflow version [e.g. 1.4.0, 1.14.0, 2.5.0]
+ - deepmatch version [e.g. 0.2.1,]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 275b40d..ac474c3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,25 +17,46 @@ jobs:
timeout-minutes: 120
strategy:
matrix:
- python-version: [3.5,3.6,3.7]
- tf-version: [1.4.0,1.14.0,2.1.0,2.2.0,2.3.0]
+ python-version: [3.6,3.7,3.8]
+ tf-version: [1.4.0,1.14.0,2.5.0]
exclude:
- python-version: 3.7
tf-version: 1.4.0
+ - python-version: 3.7
+ tf-version: 1.15.0
+ - python-version: 3.8
+ tf-version: 1.4.0
+ - python-version: 3.8
+ tf-version: 1.14.0
+ - python-version: 3.8
+ tf-version: 1.15.0
+ - python-version: 3.6
+ tf-version: 2.7.0
+ - python-version: 3.6
+ tf-version: 2.8.0
+ - python-version: 3.6
+ tf-version: 2.9.0
+ - python-version: 3.9
+ tf-version: 1.4.0
+ - python-version: 3.9
+ tf-version: 1.15.0
+ - python-version: 3.9
+ tf-version: 2.2.0
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v3
- name: Setup python environment
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip3 install -q tensorflow==${{ matrix.tf-version }}
+ pip install -q protobuf==3.19.0
pip install -q requests
pip install -e .
- name: Test with pytest
@@ -46,7 +67,7 @@ jobs:
pip install -q python-coveralls
pytest --cov=deepmatch --cov-report=xml
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@v1.0.2
+ uses: codecov/codecov-action@v3.1.0
with:
token: ${{secrets.CODECOV_TOKEN}}
file: ./coverage.xml
diff --git a/README.md b/README.md
index 75e184e..69dea2a 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,12 @@ Let's [**Get Started!**](https://deepmatch.readthedocs.io/en/latest/Quick-Start.
Wang Zhe
Baidu Inc.
+
+
+ Chen Leihui
+
+ Alibaba Group
+ |
LeoCai
@@ -57,6 +63,11 @@ Let's [**Get Started!**](https://deepmatch.readthedocs.io/en/latest/Quick-Start.
Yang Jieyu
Ant Group
|
+
+
+ Meng Yifan
+ DeepCTR
+ |
diff --git a/deepmatch/__init__.py b/deepmatch/__init__.py
index 0fa3e17..6ed5791 100644
--- a/deepmatch/__init__.py
+++ b/deepmatch/__init__.py
@@ -1,4 +1,4 @@
from .utils import check_version
-__version__ = '0.2.0'
+__version__ = '0.2.1'
check_version(__version__)
diff --git a/deepmatch/layers/__init__.py b/deepmatch/layers/__init__.py
index 854c596..a6053ed 100644
--- a/deepmatch/layers/__init__.py
+++ b/deepmatch/layers/__init__.py
@@ -1,7 +1,8 @@
from deepctr.layers import custom_objects
from deepctr.layers.utils import reduce_sum
-from .core import PoolingLayer, Similarity, LabelAwareAttention, CapsuleLayer, SampledSoftmaxLayer, EmbeddingIndex
+from .core import PoolingLayer, Similarity, LabelAwareAttention, CapsuleLayer, SampledSoftmaxLayer, EmbeddingIndex, \
+ MaskUserEmbedding
from .interaction import DotAttention, ConcatAttention, SoftmaxWeightedSum, AttentionSequencePoolingLayer, \
SelfAttention, \
SelfMultiHeadAttention, UserAttention
@@ -23,7 +24,8 @@
'SelfAttention': SelfAttention,
'SelfMultiHeadAttention': SelfMultiHeadAttention,
'UserAttention': UserAttention,
- 'DynamicMultiRNN': DynamicMultiRNN
+ 'DynamicMultiRNN': DynamicMultiRNN,
+ 'MaskUserEmbedding': MaskUserEmbedding
}
custom_objects = dict(custom_objects, **_custom_objects)
diff --git a/deepmatch/layers/core.py b/deepmatch/layers/core.py
index 2bdd7c2..1267653 100644
--- a/deepmatch/layers/core.py
+++ b/deepmatch/layers/core.py
@@ -1,7 +1,7 @@
import tensorflow as tf
from deepctr.layers.activation import activation_layer
from deepctr.layers.utils import reduce_max, reduce_mean, reduce_sum, concat_func, div, softmax
-from tensorflow.python.keras.initializers import RandomNormal, Zeros, glorot_normal
+from tensorflow.python.keras.initializers import RandomNormal, Zeros, TruncatedNormal
from tensorflow.python.keras.layers import Layer
from tensorflow.python.keras.regularizers import l2
@@ -103,19 +103,19 @@ def call(self, inputs, training=None, **kwargs):
weight = tf.pow(weight, self.pow_p) # [x,k_max,1]
if len(inputs) == 3:
- k_user = tf.cast(tf.maximum(
- 1.,
- tf.minimum(
- tf.cast(self.k_max, dtype="float32"), # k_max
- tf.log1p(tf.cast(inputs[2], dtype="float32")) / tf.log(2.) # hist_len
- )
- ), dtype="int64")
+ k_user = inputs[2]
seq_mask = tf.transpose(tf.sequence_mask(k_user, self.k_max), [0, 2, 1])
padding = tf.ones_like(seq_mask, dtype=tf.float32) * (-2 ** 32 + 1) # [x,k_max,1]
weight = tf.where(seq_mask, weight, padding)
- weight = softmax(weight, dim=1, name="weight")
- output = reduce_sum(keys * weight, axis=1)
+ if self.pow_p >= 100:
+ idx = tf.stack(
+ [tf.range(tf.shape(keys)[0]), tf.squeeze(tf.argmax(weight, axis=1, output_type=tf.int32), axis=1)],
+ axis=1)
+ output = tf.gather_nd(keys, idx)
+ else:
+ weight = softmax(weight, dim=1, name="weight")
+ output = tf.reduce_sum(keys * weight, axis=1)
return output
@@ -172,32 +172,59 @@ def __init__(self, input_units, out_units, max_len, k_max, iteration_times=3,
super(CapsuleLayer, self).__init__(**kwargs)
def build(self, input_shape):
- self.routing_logits = self.add_weight(shape=[1, self.k_max, self.max_len],
- initializer=RandomNormal(stddev=self.init_std),
- trainable=False, name="B", dtype=tf.float32)
self.bilinear_mapping_matrix = self.add_weight(shape=[self.input_units, self.out_units],
- initializer=RandomNormal(stddev=self.init_std),
name="S", dtype=tf.float32)
super(CapsuleLayer, self).build(input_shape)
def call(self, inputs, **kwargs):
- behavior_embddings, seq_len = inputs
- batch_size = tf.shape(behavior_embddings)[0]
- seq_len_tile = tf.tile(seq_len, [1, self.k_max])
+
+ behavior_embedding = inputs[0]
+ seq_len = inputs[1]
+ batch_size = tf.shape(behavior_embedding)[0]
+
+ mask = tf.reshape(tf.sequence_mask(seq_len, self.max_len, tf.float32), [-1, self.max_len, 1, 1])
+
+ behavior_embedding_mapping = tf.tensordot(behavior_embedding, self.bilinear_mapping_matrix, axes=1)
+ behavior_embedding_mapping = tf.expand_dims(behavior_embedding_mapping, axis=2)
+
+ behavior_embdding_mapping_ = tf.stop_gradient(behavior_embedding_mapping) # N,max_len,1,E
+ try:
+ routing_logits = tf.truncated_normal([batch_size, self.max_len, self.k_max, 1], stddev=self.init_std)
+ except AttributeError:
+ routing_logits = tf.compat.v1.truncated_normal([batch_size, self.max_len, self.k_max, 1],
+ stddev=self.init_std)
+ routing_logits = tf.stop_gradient(routing_logits)
+
+ k_user = None
+ if len(inputs) == 3:
+ k_user = inputs[2]
+ interest_mask = tf.sequence_mask(k_user, self.k_max, tf.float32)
+ interest_mask = tf.reshape(interest_mask, [batch_size, 1, self.k_max, 1])
+ interest_mask = tf.tile(interest_mask, [1, self.max_len, 1, 1])
+
+ interest_padding = tf.ones_like(interest_mask) * -2 ** 31
+ interest_mask = tf.cast(interest_mask, tf.bool)
for i in range(self.iteration_times):
- mask = tf.sequence_mask(seq_len_tile, self.max_len)
- pad = tf.ones_like(mask, dtype=tf.float32) * (-2 ** 32 + 1)
- routing_logits_with_padding = tf.where(mask, tf.tile(self.routing_logits, [batch_size, 1, 1]), pad)
- weight = tf.nn.softmax(routing_logits_with_padding)
- behavior_embdding_mapping = tf.tensordot(behavior_embddings, self.bilinear_mapping_matrix, axes=1)
- Z = tf.matmul(weight, behavior_embdding_mapping)
- interest_capsules = squash(Z)
- delta_routing_logits = reduce_sum(
- tf.matmul(interest_capsules, tf.transpose(behavior_embdding_mapping, perm=[0, 2, 1])),
- axis=0, keep_dims=True
- )
- self.routing_logits.assign_add(delta_routing_logits)
+ if k_user is not None:
+ routing_logits = tf.where(interest_mask, routing_logits, interest_padding)
+ try:
+ weight = softmax(routing_logits, 2) * mask
+ except TypeError:
+ weight = tf.transpose(softmax(tf.transpose(routing_logits, [0, 1, 3, 2])),
+ [0, 1, 3, 2]) * mask # N,max_len,k_max,1
+ if i < self.iteration_times - 1:
+ Z = reduce_sum(tf.matmul(weight, behavior_embdding_mapping_), axis=1, keep_dims=True) # N,1,k_max,E
+ interest_capsules = squash(Z)
+ delta_routing_logits = reduce_sum(
+ interest_capsules * behavior_embdding_mapping_,
+ axis=-1, keep_dims=True
+ )
+ routing_logits += delta_routing_logits
+ else:
+ Z = reduce_sum(tf.matmul(weight, behavior_embedding_mapping), axis=1, keep_dims=True)
+ interest_capsules = squash(Z)
+
interest_capsules = tf.reshape(interest_capsules, [-1, self.k_max, self.out_units])
return interest_capsules
@@ -213,7 +240,7 @@ def get_config(self, ):
def squash(inputs):
vec_squared_norm = reduce_sum(tf.square(inputs), axis=-1, keep_dims=True)
- scalar_factor = vec_squared_norm / (1 + vec_squared_norm) / tf.sqrt(vec_squared_norm + 1e-8)
+ scalar_factor = vec_squared_norm / (1 + vec_squared_norm) / tf.sqrt(vec_squared_norm + 1e-9)
vec_squashed = scalar_factor * inputs
return vec_squashed
@@ -235,3 +262,27 @@ def get_config(self, ):
config = {'index': self.index, }
base_config = super(EmbeddingIndex, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+
+
+class MaskUserEmbedding(Layer):
+
+ def __init__(self, k_max, **kwargs):
+ self.k_max = k_max
+ super(MaskUserEmbedding, self).__init__(**kwargs)
+
+ def build(self, input_shape):
+ super(MaskUserEmbedding, self).build(
+ input_shape) # Be sure to call this somewhere!
+
+ def call(self, x, training=None, **kwargs):
+ user_embedding, interest_num = x
+ if not training:
+ interest_mask = tf.sequence_mask(interest_num, self.k_max, tf.float32)
+ interest_mask = tf.reshape(interest_mask, [-1, self.k_max, 1])
+ user_embedding *= interest_mask
+ return user_embedding
+
+ def get_config(self, ):
+ config = {'k_max': self.k_max, }
+ base_config = super(MaskUserEmbedding, self).get_config()
+ return dict(list(base_config.items()) + list(config.items()))
diff --git a/deepmatch/models/dssm.py b/deepmatch/models/dssm.py
index 1ac95cd..f00eb3f 100644
--- a/deepmatch/models/dssm.py
+++ b/deepmatch/models/dssm.py
@@ -15,8 +15,8 @@
def DSSM(user_feature_columns, item_feature_columns, user_dnn_hidden_units=(64, 32),
item_dnn_hidden_units=(64, 32),
- dnn_activation='tanh', dnn_use_bn=False,
- l2_reg_dnn=0, l2_reg_embedding=1e-6, dnn_dropout=0, seed=1024, metric='cos'):
+ dnn_activation='relu', dnn_use_bn=False,
+ l2_reg_dnn=0, l2_reg_embedding=1e-6, dnn_dropout=0, gamma=10, seed=1024, metric='cos'):
"""Instantiates the Deep Structured Semantic Model architecture.
:param user_feature_columns: An iterable containing user's features used by the model.
@@ -28,6 +28,7 @@ def DSSM(user_feature_columns, item_feature_columns, user_dnn_hidden_units=(64,
:param l2_reg_dnn: float. L2 regularizer strength applied to DNN
:param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
:param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate.
+ :param gamma: float. Scaling factor.
:param seed: integer ,to use as random seed.
:param metric: str, ``"cos"`` for cosine or ``"ip"`` for inner product
:return: A Keras model instance.
@@ -55,12 +56,12 @@ def DSSM(user_feature_columns, item_feature_columns, user_dnn_hidden_units=(64,
item_dnn_input = combined_dnn_input(item_sparse_embedding_list, item_dense_value_list)
user_dnn_out = DNN(user_dnn_hidden_units, dnn_activation, l2_reg_dnn, dnn_dropout,
- dnn_use_bn, seed=seed)(user_dnn_input)
+ dnn_use_bn, output_activation='linear', seed=seed)(user_dnn_input)
item_dnn_out = DNN(item_dnn_hidden_units, dnn_activation, l2_reg_dnn, dnn_dropout,
- dnn_use_bn, seed=seed)(item_dnn_input)
+ dnn_use_bn, output_activation='linear', seed=seed)(item_dnn_input)
- score = Similarity(type=metric, gamma = 10)([user_dnn_out, item_dnn_out])
+ score = Similarity(type=metric, gamma=gamma)([user_dnn_out, item_dnn_out])
output = PredictionLayer("binary", False)(score)
diff --git a/deepmatch/models/fm.py b/deepmatch/models/fm.py
index 97bf339..5b25fe0 100644
--- a/deepmatch/models/fm.py
+++ b/deepmatch/models/fm.py
@@ -8,12 +8,13 @@
from ..layers.core import Similarity
-def FM(user_feature_columns, item_feature_columns, l2_reg_embedding=1e-6, seed=1024, metric='cos'):
+def FM(user_feature_columns, item_feature_columns, l2_reg_embedding=1e-6, gamma=10, seed=1024, metric='cos'):
"""Instantiates the FM architecture.
:param user_feature_columns: An iterable containing user's features used by the model.
:param item_feature_columns: An iterable containing item's features used by the model.
:param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
+ :param gamma: float. Scaling factor.
:param seed: integer ,to use as random seed.
:param metric: str, ``"cos"`` for cosine or ``"ip"`` for inner product
:return: A Keras model instance.
@@ -46,7 +47,7 @@ def FM(user_feature_columns, item_feature_columns, l2_reg_embedding=1e-6, seed=1
item_dnn_input = concat_func(item_sparse_embedding_list, axis=1)
item_vector_sum = Lambda(lambda x: reduce_sum(x, axis=1, keep_dims=False))(item_dnn_input)
- score = Similarity(type=metric)([user_vector_sum, item_vector_sum])
+ score = Similarity(type=metric, gamma=gamma)([user_vector_sum, item_vector_sum])
output = PredictionLayer("binary", False)(score)
diff --git a/deepmatch/models/mind.py b/deepmatch/models/mind.py
index 3053dd1..556e318 100755
--- a/deepmatch/models/mind.py
+++ b/deepmatch/models/mind.py
@@ -11,12 +11,13 @@
embedding_lookup, varlen_embedding_lookup, get_varlen_pooling_list, get_dense_input, build_input_features
from deepctr.layers import DNN
from deepctr.layers.utils import NoMask, combined_dnn_input
-from tensorflow.python.keras.layers import Concatenate
+from tensorflow.python.keras.layers import Concatenate, Lambda
from tensorflow.python.keras.models import Model
-from deepmatch.utils import get_item_embedding
from ..inputs import create_embedding_matrix
-from ..layers.core import CapsuleLayer, PoolingLayer, LabelAwareAttention, SampledSoftmaxLayer, EmbeddingIndex
+from ..layers.core import CapsuleLayer, PoolingLayer, MaskUserEmbedding, LabelAwareAttention, SampledSoftmaxLayer, \
+ EmbeddingIndex
+from ..utils import get_item_embedding
def shape_target(target_emb_tmp, target_emb_size):
@@ -27,7 +28,24 @@ def tile_user_otherfeat(user_other_feature, k_max):
return tf.tile(tf.expand_dims(user_other_feature, -2), [1, k_max, 1])
-def MIND(user_feature_columns, item_feature_columns, num_sampled=5, k_max=2, p=1.0, dynamic_k=False,
+def adaptive_interest_num(seq_len, k_max):
+ try:
+ log_len = tf.log1p(tf.cast(seq_len, dtype="float32"))
+ log_2 = tf.log(2.)
+ except AttributeError:
+ log_len = tf.math.log1p(tf.cast(seq_len, dtype="float32"))
+ log_2 = tf.math.log(2.)
+ k_user = tf.cast(tf.maximum(
+ 1.,
+ tf.minimum(
+ tf.cast(k_max, dtype="float32"), # k_max
+ log_len / log_2 # hist_len
+ )
+ ), dtype="int32")
+ return k_user
+
+
+def MIND(user_feature_columns, item_feature_columns, num_sampled=5, k_max=2, p=100, dynamic_k=True,
user_dnn_hidden_units=(64, 32), dnn_activation='relu', dnn_use_bn=False, l2_reg_dnn=0, l2_reg_embedding=1e-6,
dnn_dropout=0, output_activation='linear', seed=1024):
"""Instantiates the MIND Model architecture.
@@ -110,14 +128,20 @@ def MIND(user_feature_columns, item_feature_columns, num_sampled=5, k_max=2, p=1
# max_len = history_emb.get_shape()[1].value
hist_len = features['hist_len']
- high_capsule = CapsuleLayer(input_units=item_embedding_dim,
- out_units=item_embedding_dim, max_len=seq_max_len,
- k_max=k_max)((history_emb, hist_len))
+ if dynamic_k:
+ interest_num = Lambda(adaptive_interest_num, arguments={'k_max': k_max})(hist_len)
+ high_capsule = CapsuleLayer(input_units=item_embedding_dim,
+ out_units=item_embedding_dim, max_len=seq_max_len,
+ k_max=k_max)((history_emb, hist_len, interest_num))
+ else:
+ high_capsule = CapsuleLayer(input_units=item_embedding_dim,
+ out_units=item_embedding_dim, max_len=seq_max_len,
+ k_max=k_max)((history_emb, hist_len))
if len(dnn_input_emb_list) > 0 or len(dense_value_list) > 0:
user_other_feature = combined_dnn_input(dnn_input_emb_list, dense_value_list)
- other_feature_tile = tf.keras.layers.Lambda(tile_user_otherfeat, arguments={'k_max': k_max})(user_other_feature)
+ other_feature_tile = Lambda(tile_user_otherfeat, arguments={'k_max': k_max})(user_other_feature)
user_deep_input = Concatenate()([NoMask()(other_feature_tile), high_capsule])
else:
@@ -125,7 +149,7 @@ def MIND(user_feature_columns, item_feature_columns, num_sampled=5, k_max=2, p=1
user_embeddings = DNN(user_dnn_hidden_units, dnn_activation, l2_reg_dnn,
dnn_dropout, dnn_use_bn, output_activation=output_activation, seed=seed,
- name="user_embedding")(
+ name="user_dnn")(
user_deep_input)
item_inputs_list = list(item_features.values())
@@ -138,9 +162,10 @@ def MIND(user_feature_columns, item_feature_columns, num_sampled=5, k_max=2, p=1
pooling_item_embedding_weight = PoolingLayer()([item_embedding_weight])
if dynamic_k:
- user_embedding_final = LabelAwareAttention(k_max=k_max, pow_p=p, )((user_embeddings, target_emb, hist_len))
+ user_embeddings = MaskUserEmbedding(k_max)([user_embeddings, interest_num])
+ user_embedding_final = LabelAwareAttention(k_max=k_max, pow_p=p)((user_embeddings, target_emb, interest_num))
else:
- user_embedding_final = LabelAwareAttention(k_max=k_max, pow_p=p, )((user_embeddings, target_emb))
+ user_embedding_final = LabelAwareAttention(k_max=k_max, pow_p=p)((user_embeddings, target_emb))
output = SampledSoftmaxLayer(num_sampled=num_sampled)(
[pooling_item_embedding_weight, user_embedding_final, item_features[item_feature_name]])
diff --git a/deepmatch/models/sdm.py b/deepmatch/models/sdm.py
index 6d6ca96..5fbd5c4 100644
--- a/deepmatch/models/sdm.py
+++ b/deepmatch/models/sdm.py
@@ -15,10 +15,10 @@
from tensorflow.python.keras.layers import Dense, Lambda
from tensorflow.python.keras.models import Model
-from deepmatch.utils import get_item_embedding
from ..layers.core import PoolingLayer, SampledSoftmaxLayer, EmbeddingIndex
from ..layers.interaction import UserAttention, SelfMultiHeadAttention, AttentionSequencePoolingLayer
from ..layers.sequence import DynamicMultiRNN
+from ..utils import get_item_embedding
def SDM(user_feature_columns, item_feature_columns, history_feature_list, num_sampled=5, units=64, rnn_layers=2,
@@ -156,8 +156,3 @@ def SDM(user_feature_columns, item_feature_columns, history_feature_list, num_sa
get_item_embedding(pooling_item_embedding_weight, item_features[item_feature_name]))
return model
- # , Model(inputs=user_inputs_list, outputs=gate_output_reshape), Model(inputs=item_inputs_list,
- # outputs=get_item_embedding(
- # pooling_item_embedding_weight,
- # item_features[
- # item_feature_name]))
diff --git a/deepmatch/models/youtubednn.py b/deepmatch/models/youtubednn.py
index 3b96a70..f146e87 100644
--- a/deepmatch/models/youtubednn.py
+++ b/deepmatch/models/youtubednn.py
@@ -9,10 +9,9 @@
from deepctr.layers.utils import NoMask, combined_dnn_input
from tensorflow.python.keras.models import Model
-from deepmatch.layers import PoolingLayer
-from deepmatch.utils import get_item_embedding
from ..inputs import input_from_feature_columns, create_embedding_matrix
-from ..layers.core import SampledSoftmaxLayer, EmbeddingIndex
+from ..layers.core import SampledSoftmaxLayer, EmbeddingIndex, PoolingLayer
+from ..utils import get_item_embedding
def YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=5,
diff --git a/docs/pics/code2.jpg b/docs/pics/code2.jpg
new file mode 100644
index 0000000..e191f29
Binary files /dev/null and b/docs/pics/code2.jpg differ
diff --git a/docs/pics/planet_github.png b/docs/pics/planet_github.png
new file mode 100644
index 0000000..67efe96
Binary files /dev/null and b/docs/pics/planet_github.png differ
diff --git a/docs/requirements.readthedocs.txt b/docs/requirements.readthedocs.txt
new file mode 100644
index 0000000..1094240
--- /dev/null
+++ b/docs/requirements.readthedocs.txt
@@ -0,0 +1,2 @@
+tensorflow==2.6.2
+recommonmark==0.7.1
\ No newline at end of file
diff --git a/docs/source/Examples.md b/docs/source/Examples.md
index 2e652e2..e7efaad 100644
--- a/docs/source/Examples.md
+++ b/docs/source/Examples.md
@@ -39,13 +39,19 @@ if __name__ == "__main__":
# 1.Label Encoding for sparse features,and process sequence features with `gen_date_set` and `gen_model_input`
- features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip']
+ features = ['user_id', 'gender', 'age', 'occupation', 'zip']
feature_max_idx = {}
for feature in features:
lbe = LabelEncoder()
data[feature] = lbe.fit_transform(data[feature]) + 1
feature_max_idx[feature] = data[feature].max() + 1
+ id_count = data['movie_id'].value_counts()
+ mapdict = {t[0]: i for i, t in
+ enumerate(sorted([(k, v) for k, v in id_count.to_dict().items()], key=lambda x: x[1], reverse=True))}
+ data['movie_id'] = data['movie_id'].map(mapdict)
+ feature_max_idx['movie_id'] = data['movie_id'].max() + 1
+
user_profile = data[["user_id", "gender", "age", "occupation", "zip"]].drop_duplicates('user_id')
item_profile = data[["movie_id"]].drop_duplicates('movie_id')
@@ -76,10 +82,15 @@ if __name__ == "__main__":
# 3.Define Model and train
- K.set_learning_phase(True)
+ import tensorflow as tf
+
+ if tf.__version__ >= '2.0.0':
+ tf.compat.v1.disable_eager_execution()
+ else:
+ K.set_learning_phase(True)
model = YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=5, user_dnn_hidden_units=(64, embedding_dim))
- # model = MIND(user_feature_columns,item_feature_columns,dynamic_k=False,p=1,k_max=2,num_sampled=5,user_dnn_hidden_units=(64,embedding_dim),init_std=0.001)
+ # model = MIND(user_feature_columns,item_feature_columns,dynamic_k=True,k_max=2,num_sampled=5,user_dnn_hidden_units=(64,embedding_dim),init_std=0.001)
model.compile(optimizer="adam", loss=sampledsoftmaxloss) # "binary_crossentropy")
@@ -165,13 +176,19 @@ if __name__ == "__main__":
# 1.Label Encoding for sparse features,and process sequence features with `gen_date_set` and `gen_model_input`
- features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip', 'genres']
+ features = ['user_id', 'gender', 'age', 'occupation', 'zip']
feature_max_idx = {}
for feature in features:
lbe = LabelEncoder()
data[feature] = lbe.fit_transform(data[feature]) + 1
feature_max_idx[feature] = data[feature].max() + 1
+ id_count = data['movie_id'].value_counts()
+ mapdict = {t[0]: i for i, t in
+ enumerate(sorted([(k, v) for k, v in id_count.to_dict().items()], key=lambda x: x[1], reverse=True))}
+ data['movie_id'] = data['movie_id'].map(mapdict)
+ feature_max_idx['movie_id'] = data['movie_id'].max() + 1
+
user_profile = data[["user_id", "gender", "age", "occupation", "zip", "genres"]].drop_duplicates('user_id')
item_profile = data[["movie_id"]].drop_duplicates('movie_id')
@@ -210,12 +227,12 @@ if __name__ == "__main__":
item_feature_columns = [SparseFeat('movie_id', feature_max_idx['movie_id'], embedding_dim)]
- K.set_learning_phase(True)
-
import tensorflow as tf
if tf.__version__ >= '2.0.0':
tf.compat.v1.disable_eager_execution()
+ else:
+ K.set_learning_phase(True)
# units must be equal to item embedding dim!
model = SDM(user_feature_columns, item_feature_columns, history_feature_list=['movie_id', 'genres'],
diff --git a/docs/source/History.md b/docs/source/History.md
index d0c9f61..3fbc964 100644
--- a/docs/source/History.md
+++ b/docs/source/History.md
@@ -1,4 +1,5 @@
# History
+- 06/17/2022 : [v0.2.1](https://github.com/shenweichen/DeepMatch/releases/tag/v0.2.1) released.Fix some bugs.
- 10/12/2020 : [v0.2.0](https://github.com/shenweichen/DeepMatch/releases/tag/v0.2.0) released.Support different initializers for different embedding weights and loading pretrained embeddings.
- 05/17/2020 : [v0.1.3](https://github.com/shenweichen/DeepMatch/releases/tag/v0.1.3) released.Add `SDM` model .
- 04/10/2020 : [v0.1.2](https://github.com/shenweichen/DeepMatch/releases/tag/v0.1.2) released.Support [saving and loading model](./FAQ.html#save-or-load-weights-models).
diff --git a/docs/source/Quick-Start.md b/docs/source/Quick-Start.md
index 3053598..271ee44 100644
--- a/docs/source/Quick-Start.md
+++ b/docs/source/Quick-Start.md
@@ -1,7 +1,7 @@
# Quick-Start
## Installation Guide
-Now `deepmatch` is available for python `2.7 `and `3.5, 3.6, 3.7`.
+Now `deepmatch` is available for python `2.7 `and `3.5, 3.6, 3.7, 3.8`.
`deepmatch` depends on tensorflow, you can specify to install the cpu version or gpu version through `pip`.
### CPU version
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 4e882a8..fdddcde 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -26,7 +26,7 @@
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
-release = '0.2.0'
+release = '0.2.1'
# -- General configuration ---------------------------------------------------
diff --git a/docs/source/deepmatch.layers.interaction.rst b/docs/source/deepmatch.layers.interaction.rst
new file mode 100644
index 0000000..5492bef
--- /dev/null
+++ b/docs/source/deepmatch.layers.interaction.rst
@@ -0,0 +1,7 @@
+deepmatch.layers.interaction module
+===================================
+
+.. automodule:: deepmatch.layers.interaction
+ :members:
+ :no-undoc-members:
+ :no-show-inheritance:
diff --git a/docs/source/deepmatch.layers.sequence.rst b/docs/source/deepmatch.layers.sequence.rst
new file mode 100644
index 0000000..6e88433
--- /dev/null
+++ b/docs/source/deepmatch.layers.sequence.rst
@@ -0,0 +1,7 @@
+deepmatch.layers.sequence module
+================================
+
+.. automodule:: deepmatch.layers.sequence
+ :members:
+ :no-undoc-members:
+ :no-show-inheritance:
diff --git a/docs/source/index.rst b/docs/source/index.rst
index f5b25cc..7ebbb81 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -18,12 +18,12 @@ You can read the latest code at https://github.com/shenweichen/DeepMatch
News
-----
+06/17/2022 : Fix some bugs. `Changelog `_
+
10/12/2020 : Support different initializers for different embedding weights and loading pretrained embeddings. `Changelog `_
05/17/2020 : Add ``SDM`` model. `Changelog `_
-04/10/2020 : Support `saving and loading model <./FAQ.html#save-or-load-weights-models>`_ . `Changelog `_
-
DisscussionGroup
-----------------------
diff --git a/examples/colab_MovieLen1M_YoutubeDNN.ipynb b/examples/colab_MovieLen1M_YoutubeDNN.ipynb
index a5bd90e..8587653 100644
--- a/examples/colab_MovieLen1M_YoutubeDNN.ipynb
+++ b/examples/colab_MovieLen1M_YoutubeDNN.ipynb
@@ -3,17 +3,6 @@
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
- "id": "view-in-github"
- },
- "source": [
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "colab_type": "text",
"id": "rtox72csOQUN"
},
"source": [
@@ -25,7 +14,6 @@
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
"id": "bTWHz-heMkyw"
},
"source": [
@@ -34,52 +22,46 @@
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 1,
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 510
+ "base_uri": "https://localhost:8080/"
},
- "colab_type": "code",
"id": "yTl6d6jO1oqf",
- "outputId": "19f1902e-17a6-4a07-ab42-f012bd286eda"
+ "outputId": "6f4516af-0f03-4f35-8f0d-80e803021095"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "--2020-04-10 09:06:19-- http://files.grouplens.org/datasets/movielens/ml-1m.zip\n",
+ "--2022-06-17 04:30:51-- http://files.grouplens.org/datasets/movielens/ml-1m.zip\n",
"Resolving files.grouplens.org (files.grouplens.org)... 128.101.65.152\n",
"Connecting to files.grouplens.org (files.grouplens.org)|128.101.65.152|:80... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 5917549 (5.6M) [application/zip]\n",
"Saving to: ‘./ml-1m.zip’\n",
"\n",
- "\r",
- "./ml-1m.zip 0%[ ] 0 --.-KB/s \r",
- "./ml-1m.zip 7%[> ] 443.20K 1.85MB/s \r",
- "./ml-1m.zip 100%[===================>] 5.64M 14.4MB/s in 0.4s \n",
+ "./ml-1m.zip 100%[===================>] 5.64M 3.47MB/s in 1.6s \n",
"\n",
- "2020-04-10 09:06:19 (14.4 MB/s) - ‘./ml-1m.zip’ saved [5917549/5917549]\n",
+ "2022-06-17 04:30:54 (3.47 MB/s) - ‘./ml-1m.zip’ saved [5917549/5917549]\n",
"\n",
- "--2020-04-10 09:06:21-- https://raw.githubusercontent.com/shenweichen/DeepMatch/master/examples/preprocess.py\n",
- "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...\n",
- "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.\n",
+ "--2022-06-17 04:30:54-- https://raw.githubusercontent.com/shenweichen/DeepMatch/master/examples/preprocess.py\n",
+ "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n",
+ "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
- "Length: 2049 (2.0K) [text/plain]\n",
+ "Length: 5642 (5.5K) [text/plain]\n",
"Saving to: ‘preprocess.py’\n",
"\n",
- "preprocess.py 100%[===================>] 2.00K --.-KB/s in 0s \n",
+ "preprocess.py 100%[===================>] 5.51K --.-KB/s in 0s \n",
"\n",
- "2020-04-10 09:06:21 (34.8 MB/s) - ‘preprocess.py’ saved [2049/2049]\n",
+ "2022-06-17 04:30:54 (71.1 MB/s) - ‘preprocess.py’ saved [5642/5642]\n",
"\n",
"Archive: ml-1m.zip\n",
" inflating: ml-1m/movies.dat \n",
" inflating: ml-1m/ratings.dat \n",
" inflating: ml-1m/README \n",
" inflating: ml-1m/users.dat \n",
- "TensorFlow 1.x selected.\n",
"\u001b[33mWARNING: Skipping tensorflow as it is not installed.\u001b[0m\n"
]
}
@@ -88,16 +70,14 @@
"! wget http://files.grouplens.org/datasets/movielens/ml-1m.zip -O ./ml-1m.zip \n",
"! wget https://raw.githubusercontent.com/shenweichen/DeepMatch/master/examples/preprocess.py -O preprocess.py\n",
"! unzip -o ml-1m.zip \n",
- "%tensorflow_version 1.x\n",
"! pip uninstall -y -q tensorflow\n",
- "! pip install -q tensorflow-gpu==1.14.0\n",
+ "! pip install -q tensorflow-gpu==2.5.0\n",
"! pip install -q deepmatch"
]
},
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
"id": "p9UxNHuPMuW2"
},
"source": [
@@ -106,54 +86,22 @@
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 2,
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 496
+ "base_uri": "https://localhost:8080/"
},
- "colab_type": "code",
"id": "C_ZR6gzp1E2N",
- "outputId": "8401132a-5090-464a-879d-a27492416f4c"
+ "outputId": "903724ad-114b-4ea8-d0ce-151f9f6d4cdc"
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorboard/compat/tensorflow_stub/dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorboard/compat/tensorflow_stub/dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorboard/compat/tensorflow_stub/dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorboard/compat/tensorflow_stub/dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorboard/compat/tensorflow_stub/dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
- "/usr/local/lib/python3.6/dist-packages/tensorboard/compat/tensorflow_stub/dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
- " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/initializers.py:143: calling RandomNormal.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
- "Instructions for updating:\n",
- "Call initializer instance with the dtype argument instead of passing it to the constructor\n"
+ "WARNING:root:\n",
+ "DeepCTR version 0.9.1 detected. Your version is 0.8.2.\n",
+ "Use `pip install -U deepctr` to upgrade.Changelog: https://github.com/shenweichen/DeepCTR/releases/tag/v0.9.1\n"
]
}
],
@@ -172,7 +120,6 @@
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
"id": "fQq6O9XAMzPF"
},
"source": [
@@ -181,27 +128,21 @@
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 3,
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 139
+ "base_uri": "https://localhost:8080/"
},
- "colab_type": "code",
"id": "lcO29zFb21Od",
- "outputId": "97d9023e-cbd5-43dd-d2ef-769e3a34cf2c"
+ "outputId": "ea095585-f5ec-4d1c-9ffa-117531a5ed3b"
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:4: ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'.\n",
- " after removing the cwd from sys.path.\n",
- "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:6: ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'.\n",
- " \n",
- "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:8: ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'.\n",
- " \n"
+ "/usr/local/lib/python3.7/dist-packages/pandas/util/_decorators.py:311: ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'.\n",
+ " return func(*args, **kwargs)\n"
]
}
],
@@ -213,7 +154,7 @@
"rnames = ['user_id','movie_id','rating','timestamp']\n",
"ratings = pd.read_csv(data_path+'ml-1m/ratings.dat',sep='::',header=None,names=rnames)\n",
"mnames = ['movie_id','title','genres']\n",
- "movies = pd.read_csv(data_path+'ml-1m/movies.dat',sep='::',header=None,names=mnames)\n",
+ "movies = pd.read_csv(data_path+'ml-1m/movies.dat',sep='::',header=None,names=mnames,encoding=\"unicode_escape\")\n",
"\n",
"data = pd.merge(pd.merge(ratings,movies),user)#.iloc[:10000]\n"
]
@@ -221,7 +162,6 @@
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
"id": "L0yCWxQxM3se"
},
"source": [
@@ -230,107 +170,96 @@
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 4,
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 1000
+ "base_uri": "https://localhost:8080/"
},
- "colab_type": "code",
"id": "BMOvk_de2ML3",
- "outputId": "1e43a5e7-f71c-45a4-bab4-e1d6b1a73669"
+ "outputId": "24448edc-9100-4a01-c13f-c48d0a6632e0"
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "100%|██████████| 6040/6040 [00:12<00:00, 489.02it/s]\n"
+ "100%|██████████| 6040/6040 [00:17<00:00, 336.80it/s]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
- "6 6\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AttributeError: module 'gast' has no attribute 'Num'\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AttributeError: module 'gast' has no attribute 'Num'\n",
- "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/deepctr/layers/utils.py:167: calling reduce_sum_v1 (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.\n",
- "Instructions for updating:\n",
- "keep_dims is deprecated, use keepdims instead\n",
- "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/deepctr/layers/utils.py:193: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
- "Instructions for updating:\n",
- "Deprecated in favor of operator or tf.math.divide.\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/init_ops.py:1288: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
+ "6 6\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/usr/local/lib/python3.7/dist-packages/tensorflow/python/keras/backend.py:435: UserWarning: `tf.keras.backend.set_learning_phase` is deprecated and will be removed after 2020-10-11. To update it, simply pass a True/False value to the `training` argument of the `__call__` method of your layer or model.\n",
+ " warnings.warn('`tf.keras.backend.set_learning_phase` is deprecated and '\n",
+ "WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/python/ops/array_ops.py:5049: calling gather (from tensorflow.python.ops.array_ops) with validate_indices is deprecated and will be removed in a future version.\n",
"Instructions for updating:\n",
- "Call initializer instance with the dtype argument instead of passing it to the constructor\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AttributeError: module 'gast' has no attribute 'Num'\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AttributeError: module 'gast' has no attribute 'Num'\n",
- "WARNING:tensorflow:Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "WARNING: Entity > could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting >: AssertionError: Bad argument number for Name: 3, expecting 4\n",
- "Epoch 1/24\n",
- "988129/988129 [==============================] - 22s 23us/sample - loss: 4.0715\n",
- "Epoch 2/24\n",
- "988129/988129 [==============================] - 21s 21us/sample - loss: 3.7855\n",
- "Epoch 3/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.5596\n",
- "Epoch 4/24\n",
- "988129/988129 [==============================] - 21s 21us/sample - loss: 3.4199\n",
- "Epoch 5/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.3216\n",
- "Epoch 6/24\n",
- "988129/988129 [==============================] - 21s 21us/sample - loss: 3.2499\n",
- "Epoch 7/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.1846\n",
- "Epoch 8/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.1264\n",
- "Epoch 9/24\n",
- "988129/988129 [==============================] - 22s 22us/sample - loss: 3.0923\n",
- "Epoch 10/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.0566\n",
- "Epoch 11/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.0336\n",
- "Epoch 12/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 3.0066\n",
- "Epoch 13/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.9872\n",
- "Epoch 14/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.9659\n",
- "Epoch 15/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.9476\n",
- "Epoch 16/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.9363\n",
- "Epoch 17/24\n",
- "988129/988129 [==============================] - 21s 21us/sample - loss: 2.9267\n",
- "Epoch 18/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.9179\n",
- "Epoch 19/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.9012\n",
- "Epoch 20/24\n",
- "988129/988129 [==============================] - 21s 21us/sample - loss: 2.8925\n",
- "Epoch 21/24\n",
- "988129/988129 [==============================] - 21s 21us/sample - loss: 2.8830\n",
- "Epoch 22/24\n",
- "988129/988129 [==============================] - 22s 22us/sample - loss: 2.8797\n",
- "Epoch 23/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.8711\n",
- "Epoch 24/24\n",
- "988129/988129 [==============================] - 21s 22us/sample - loss: 2.8619\n",
+ "The `validate_indices` argument has no effect. Indices are always validated on CPU and never validated on GPU.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Train on 988129 samples\n",
+ "Epoch 1/20\n",
+ "988129/988129 [==============================] - 24s 25us/sample - loss: 4.4995\n",
+ "Epoch 2/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 4.2307\n",
+ "Epoch 3/20\n",
+ "988129/988129 [==============================] - 25s 25us/sample - loss: 3.8902\n",
+ "Epoch 4/20\n",
+ "988129/988129 [==============================] - 24s 24us/sample - loss: 3.6825\n",
+ "Epoch 5/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.5604\n",
+ "Epoch 6/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.4642\n",
+ "Epoch 7/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.3803\n",
+ "Epoch 8/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.3126\n",
+ "Epoch 9/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.2583\n",
+ "Epoch 10/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.2177\n",
+ "Epoch 11/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.1791\n",
+ "Epoch 12/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.1472\n",
+ "Epoch 13/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.1246\n",
+ "Epoch 14/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.0992\n",
+ "Epoch 15/20\n",
+ "988129/988129 [==============================] - 24s 24us/sample - loss: 3.0796\n",
+ "Epoch 16/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.0601\n",
+ "Epoch 17/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.0418\n",
+ "Epoch 18/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.0265\n",
+ "Epoch 19/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 3.0119\n",
+ "Epoch 20/20\n",
+ "988129/988129 [==============================] - 23s 23us/sample - loss: 2.9994\n",
"(6040, 32)\n",
"(3706, 32)\n"
]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/usr/local/lib/python3.7/dist-packages/tensorflow/python/keras/engine/training.py:2426: UserWarning: `Model.state_updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.\n",
+ " warnings.warn('`Model.state_updates` will be removed in a future version. '\n"
+ ]
}
],
"source": [
@@ -342,13 +271,19 @@
"\n",
"# 1.Label Encoding for sparse features,and process sequence features with `gen_date_set` and `gen_model_input`\n",
"\n",
- "features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip']\n",
+ "features = ['user_id', 'gender', 'age', 'occupation', 'zip']\n",
"feature_max_idx = {}\n",
"for feature in features:\n",
" lbe = LabelEncoder()\n",
" data[feature] = lbe.fit_transform(data[feature]) + 1\n",
" feature_max_idx[feature] = data[feature].max() + 1\n",
"\n",
+ "id_count = data['movie_id'].value_counts() \n",
+ "mapdict = {t[0]: i for i, t in\n",
+ " enumerate(sorted([(k, v) for k, v in id_count.to_dict().items()], key=lambda x: x[1], reverse=True))}\n",
+ "data['movie_id'] = data['movie_id'].map(mapdict)\n",
+ "feature_max_idx['movie_id'] = data['movie_id'].max() + 1\n",
+ "\n",
"user_profile = data[[\"user_id\", \"gender\", \"age\", \"occupation\", \"zip\"]].drop_duplicates('user_id')\n",
"\n",
"item_profile = data[[\"movie_id\"]].drop_duplicates('movie_id')\n",
@@ -379,14 +314,14 @@
"\n",
"# 3.Define Model and train\n",
"\n",
- "K.set_learning_phase(True)\n",
- "\n",
"import tensorflow as tf\n",
"if tf.__version__ >= '2.0.0':\n",
" tf.compat.v1.disable_eager_execution()\n",
- "\n",
+ "else:\n",
+ " K.set_learning_phase(True)\n",
+ " \n",
"model = YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=100, user_dnn_hidden_units=(128,64, embedding_dim))\n",
- "# model = MIND(user_feature_columns,item_feature_columns,dynamic_k=False,p=1,k_max=2,num_sampled=100,user_dnn_hidden_units=(128,64, embedding_dim))\n",
+ "# model = MIND(user_feature_columns,item_feature_columns,dynamic_k=True,k_max=2,num_sampled=100,user_dnn_hidden_units=(128,64, embedding_dim))\n",
"\n",
"model.compile(optimizer=\"adam\", loss=sampledsoftmaxloss) # \"binary_crossentropy\")\n",
"\n",
@@ -412,7 +347,6 @@
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
"id": "w_G3KWslKmJo"
},
"source": [
@@ -422,30 +356,27 @@
{
"cell_type": "markdown",
"metadata": {
- "colab_type": "text",
"id": "5SvyQLNVKkcs"
},
"source": []
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 5,
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 51
+ "base_uri": "https://localhost:8080/"
},
- "colab_type": "code",
"id": "j2ZNYNBOOqrN",
- "outputId": "2938673c-ff81-49a2-86d8-4266d2060ea3"
+ "outputId": "442609e8-f94d-42c3-d945-582374a5fa77"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Requirement already satisfied: faiss-cpu in /usr/local/lib/python3.6/dist-packages (1.6.3)\n",
- "Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from faiss-cpu) (1.18.2)\n"
+ "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
+ "Requirement already satisfied: faiss-cpu in /usr/local/lib/python3.7/dist-packages (1.7.2)\n"
]
}
],
@@ -455,22 +386,20 @@
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 6,
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 85
+ "base_uri": "https://localhost:8080/"
},
- "colab_type": "code",
"id": "6TY1l27iJU8U",
- "outputId": "5316c37f-fef1-44b3-8c31-6600d1e44da5"
+ "outputId": "3070ad94-9f84-4b51-d095-18053b84f5ce"
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "6040it [00:01, 4290.79it/s]"
+ "6040it [00:02, 3004.17it/s]"
]
},
{
@@ -478,8 +407,8 @@
"output_type": "stream",
"text": [
"\n",
- "recall 0.26473509933774836\n",
- "hit rate 0.26473509933774836\n"
+ "recall 0.3033112582781457\n",
+ "hit rate 0.3033112582781457\n"
]
},
{
@@ -524,10 +453,8 @@
},
{
"cell_type": "code",
- "execution_count": 0,
+ "execution_count": 6,
"metadata": {
- "colab": {},
- "colab_type": "code",
"id": "a97TB0obOrRe"
},
"outputs": [],
@@ -537,13 +464,12 @@
"metadata": {
"accelerator": "GPU",
"colab": {
- "authorship_tag": "ABX9TyOrqZNeC0DgyPX2JmJid1m7",
"collapsed_sections": [],
- "include_colab_link": true,
"name": "colab_MovieLen1M_YoutubeDNN",
"provenance": [],
"toc_visible": true
},
+ "gpuClass": "standard",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
diff --git a/examples/run_sdm.py b/examples/run_sdm.py
index fdf1def..902ea17 100644
--- a/examples/run_sdm.py
+++ b/examples/run_sdm.py
@@ -18,13 +18,19 @@
# 1.Label Encoding for sparse features,and process sequence features with `gen_date_set` and `gen_model_input`
- features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip', 'genres']
+ features = ['user_id', 'gender', 'age', 'occupation', 'zip']
feature_max_idx = {}
for feature in features:
lbe = LabelEncoder()
data[feature] = lbe.fit_transform(data[feature]) + 1
feature_max_idx[feature] = data[feature].max() + 1
+ id_count = data['movie_id'].value_counts()
+ mapdict = {t[0]: i for i, t in
+ enumerate(sorted([(k, v) for k, v in id_count.to_dict().items()], key=lambda x: x[1], reverse=True))}
+ data['movie_id'] = data['movie_id'].map(mapdict)
+ feature_max_idx['movie_id'] = data['movie_id'].max() + 1
+
user_profile = data[["user_id", "gender", "age", "occupation", "zip", "genres"]].drop_duplicates('user_id')
item_profile = data[["movie_id"]].drop_duplicates('movie_id')
diff --git a/examples/run_youtubednn.py b/examples/run_youtubednn.py
index d98a472..b9881ed 100644
--- a/examples/run_youtubednn.py
+++ b/examples/run_youtubednn.py
@@ -1,13 +1,12 @@
import pandas as pd
from deepctr.feature_column import SparseFeat, VarLenSparseFeat
+from deepmatch.models import *
+from deepmatch.utils import sampledsoftmaxloss
from preprocess import gen_data_set, gen_model_input
from sklearn.preprocessing import LabelEncoder
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.models import Model
-from deepmatch.models import *
-from deepmatch.utils import sampledsoftmaxloss
-
if __name__ == "__main__":
data = pd.read_csvdata = pd.read_csv("./movielens_sample.txt")
@@ -17,13 +16,19 @@
# 1.Label Encoding for sparse features,and process sequence features with `gen_date_set` and `gen_model_input`
- features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip']
+ features = ['user_id', 'gender', 'age', 'occupation', 'zip']
feature_max_idx = {}
for feature in features:
lbe = LabelEncoder()
data[feature] = lbe.fit_transform(data[feature]) + 1
feature_max_idx[feature] = data[feature].max() + 1
+ id_count = data['movie_id'].value_counts()
+ mapdict = {t[0]: i for i, t in
+ enumerate(sorted([(k, v) for k, v in id_count.to_dict().items()], key=lambda x: x[1], reverse=True))}
+ data['movie_id'] = data['movie_id'].map(mapdict)
+ feature_max_idx['movie_id'] = data['movie_id'].max() + 1
+
user_profile = data[["user_id", "gender", "age", "occupation", "zip"]].drop_duplicates('user_id')
item_profile = data[["movie_id"]].drop_duplicates('movie_id')
@@ -54,13 +59,15 @@
# 3.Define Model and train
- K.set_learning_phase(True)
import tensorflow as tf
+
if tf.__version__ >= '2.0.0':
- tf.compat.v1.disable_eager_execution()
+ tf.compat.v1.disable_eager_execution()
+ else:
+ K.set_learning_phase(True)
model = YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=5, user_dnn_hidden_units=(64, embedding_dim))
- #model = MIND(user_feature_columns,item_feature_columns,dynamic_k=False,p=1,k_max=2,num_sampled=5,user_dnn_hidden_units=(64, embedding_dim))
+ # model = MIND(user_feature_columns,item_feature_columns,dynamic_k=True,k_max=2,num_sampled=5,user_dnn_hidden_units=(64, embedding_dim))
model.compile(optimizer="adam", loss=sampledsoftmaxloss) # "binary_crossentropy")
diff --git a/setup.py b/setup.py
index 8ab2c5c..d5fe36e 100644
--- a/setup.py
+++ b/setup.py
@@ -4,14 +4,14 @@
long_description = fh.read()
REQUIRED_PACKAGES = [
- 'h5py', 'requests', "deepctr==0.8.2"
+ 'requests', "deepctr==0.9.1"
]
setuptools.setup(
name="deepmatch",
- version="0.2.0",
+ version="0.2.1",
author="Weichen Shen",
- author_email="wcshen1994@163.com",
+ author_email="weichenswc@163.com",
description="Deep matching model library for recommendations, advertising. It's easy to train models and to **export representation vectors** for user and item which can be used for **ANN search**.",
long_description=long_description,
long_description_content_type="text/markdown",
@@ -38,6 +38,7 @@
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Topic :: Scientific/Engineering',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
'Topic :: Software Development',
diff --git a/tests/models/MIND_test.py b/tests/models/MIND_test.py
index 0b9509b..ea9c9a1 100644
--- a/tests/models/MIND_test.py
+++ b/tests/models/MIND_test.py
@@ -1,21 +1,28 @@
+import pytest
import tensorflow as tf
-from tensorflow.python.keras import backend as K
-
from deepmatch.models import MIND
from deepmatch.utils import sampledsoftmaxloss
+from tensorflow.python.keras import backend as K
+
from ..utils import check_model, get_xy_fd
-def test_MIND():
+@pytest.mark.parametrize(
+ 'dynamic_k,p',
+ [(False, 1), (True, 100)
+ ]
+)
+def test_MIND(dynamic_k, p):
model_name = "MIND"
x, y, user_feature_columns, item_feature_columns = get_xy_fd(False)
- K.set_learning_phase(True)
if tf.__version__ >= '2.0.0':
tf.compat.v1.disable_eager_execution()
-
- model = MIND(user_feature_columns, item_feature_columns, num_sampled=2, user_dnn_hidden_units=(16, 4))
+ else:
+ K.set_learning_phase(True)
+ model = MIND(user_feature_columns, item_feature_columns, num_sampled=2, p=p, dynamic_k=dynamic_k,
+ user_dnn_hidden_units=(16, 4))
model.compile('adam', sampledsoftmaxloss)
check_model(model, model_name, x, y)
diff --git a/tests/models/SDM_test.py b/tests/models/SDM_test.py
index 60e3e5a..072caf8 100644
--- a/tests/models/SDM_test.py
+++ b/tests/models/SDM_test.py
@@ -9,13 +9,12 @@
def test_SDM():
model_name = "SDM"
- tf.keras.backend.set_learning_phase(1)
x, y, user_feature_columns, item_feature_columns, history_feature_list = get_xy_fd_sdm(False)
- K.set_learning_phase(True)
if tf.__version__ >= '2.0.0':
tf.compat.v1.disable_eager_execution()
-
+ else:
+ K.set_learning_phase(True)
model = SDM(user_feature_columns, item_feature_columns, history_feature_list, units=8)
# model.summary()
diff --git a/tests/models/YoutubeDNN_test.py b/tests/models/YoutubeDNN_test.py
index 46afb03..a014c16 100644
--- a/tests/models/YoutubeDNN_test.py
+++ b/tests/models/YoutubeDNN_test.py
@@ -10,10 +10,11 @@ def test_YoutubeDNN():
model_name = "YoutubeDNN"
x, y, user_feature_columns, item_feature_columns = get_xy_fd(False)
- K.set_learning_phase(True)
if tf.__version__ >= '2.0.0':
tf.compat.v1.disable_eager_execution()
+ else:
+ K.set_learning_phase(True)
model = YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=2, user_dnn_hidden_units=(16, 4))
model.compile('adam', sampledsoftmaxloss)