NueMF 《Neural Collaborative Filtering》

常规的协同过滤方法(矩阵分解)采用用户(user)和物品(item) 隐向量的内积来计算用户对该物品的评分:

其中, 为用户 和 物品 的隐向量, 为隐向量的维度。
但是,简单的矩阵分解并不能很好的表达隐向量之间的关系:

NueMF 《Neural Collaborative Filtering》_第1张图片
image.png

上面提到的问题可以采用增加隐向量的维度 来解决,但是这又会导致模型过拟合,特别是在稀疏数据集上更为明显。NeuMF 提出了用深度学习模型来学习隐向量之间的交互关系。
模型框架如下:

NueMF 《Neural Collaborative Filtering》_第2张图片
image.png

实际应用中的模型采用了如下结构:


NueMF 《Neural Collaborative Filtering》_第3张图片
image.png

计算过程如下:

其中, 和 分别为 GMF 和 MLP 的用户隐向量, 和 分别为 GMF 和 MLP 的物品隐向量。

损失函数:

tensorflow2.0 的算法实现
自定义了MLP的实现层:

import tensorflow as tf


class DNN(tf.keras.layers.Layer):

    def __init__(self, hidden_units, activation='relu', l2_reg=0.01, dropout_rate=0.5,
                 use_bn=True, seed=1024, **kwargs):
        super().__init__(**kwargs)
        self.hidden_units = hidden_units
        self.activation = activation
        self.l2_reg = l2_reg
        self.dropout_rate = dropout_rate
        self.use_bn = use_bn
        self.seed = seed
        self.hidden_layers = None
        self.bn_layers = None
        self.dropout_layers = None

    def build(self, input_shape):
        self.hidden_layers = [tf.keras.layers.Dense(units=self.hidden_units[i],
                                                    activation=self.activation,
                                                    use_bias=True,
                                                    kernel_regularizer=tf.keras.regularizers.l2(self.l2_reg),
                                                    bias_regularizer=tf.keras.regularizers.l2(self.l2_reg))
                              for i in range(len(self.hidden_units))]
        if self.use_bn:
            self.bn_layers = [tf.keras.layers.BatchNormalization() for _ in range(len(self.hidden_units))]

        self.dropout_layers = [tf.keras.layers.Dropout(self.dropout_rate, seed=self.seed + i)
                               for i in range(len(self.hidden_units))]
        super().build(input_shape)

    def call(self, inputs, training=None):
        deep_inputs = inputs
        for i in range(len(self.hidden_units)):
            fc = self.hidden_layers[i](deep_inputs)
            if self.use_bn:
                fc = self.bn_layers[i](fc, training=training)
            fc = self.dropout_layers[i](fc, training=training)
            deep_inputs = fc

        return deep_inputs

    def compute_output_shape(self, input_shape):
        if len(self.hidden_units) > 0:
            output_shape = input_shape[:-1] + (self.hidden_units[-1])
        else:
            output_shape = input_shape

        return tuple(output_shape)

    def get_config(self):
        config = {'hidden_units': self.hidden_units,
                  'activation': self.activation,
                  'l2_reg': self.l2_reg,
                  'dropout_rate': self.dropout_rate,
                  'use_bn': self.use_bn,
                  'seed': self.seed}
        base_config = super().get_config()

        return dict(list(config.items()) + list(base_config.items()))

模型层:

class NeuMF(tf.keras.Model):

    def __init__(self, user_size, item_size, hidden_units, embedding_size=32, activation='relu',
                 l2_reg=0.01, dropout_rate=0.5, use_bn=True, seed=1024, **kwargs):
        super().__init__()
        self.gmf_user_embedding = tf.keras.layers.Embedding(user_size, embedding_size,
                                                            embeddings_regularizer=tf.keras.regularizers.l2(l2_reg))
        self.gmf_item_embedding = tf.keras.layers.Embedding(item_size, embedding_size,
                                                            embeddings_regularizer=tf.keras.regularizers.l2(l2_reg))
        self.mlp_user_embedding = tf.keras.layers.Embedding(user_size, embedding_size,
                                                            embeddings_regularizer=tf.keras.regularizers.l2(l2_reg))
        self.mlp_item_embedding = tf.keras.layers.Embedding(item_size, embedding_size,
                                                            embeddings_regularizer=tf.keras.regularizers.l2(l2_reg))
        self.dnn = DNN(hidden_units, activation=activation, l2_reg=l2_reg, dropout_rate=dropout_rate,
                       use_bn=use_bn, seed=seed, **kwargs)
        self.dense = tf.keras.layers.Dense(units=1, activation=tf.nn.sigmoid, use_bias=False)

    def call(self, inputs, model_type='', training=None):
        # print(inputs)
        user_ids, item_ids = inputs['user_id'], inputs['item_id']
        gmf_user_embeddings = self.gmf_user_embedding(user_ids)  # [batch_size, embedding_size]
        gmf_item_embeddings = self.gmf_item_embedding(item_ids)  # [batch_size, embedding_size]
        mlp_user_embeddings = self.mlp_user_embedding(user_ids)  # [batch_size, embedding_size]
        mlp_item_embeddings = self.mlp_item_embedding(item_ids)  # [batch_size, embedding_size]
        # if model_type == 'gmf':
        #     deep_inputs = tf.multiply(gmf_user_embeddings, gmf_item_embeddings)
        #     outputs = self.dense(deep_inputs)
        # elif model_type == 'mlp':
        #     # [batch_size, embedding_size * 2]
        #     deep_inputs = tf.concat([mlp_user_embeddings, mlp_item_embeddings], axis=1)
        #     deep_outputs = self.dnn(deep_inputs, training)
        #     outputs = self.dense(deep_outputs)
        # else:
        # [batch_size, embedding_size]
        gmf_output = tf.multiply(gmf_user_embeddings, gmf_item_embeddings)
        # [batch_size, embedding_size * 2]
        mlp_inputs = tf.concat([mlp_user_embeddings, mlp_item_embeddings], axis=-1)
        # [batch_size, hidden_units[-1]
        mlp_outputs = self.dnn(mlp_inputs, training)
        # [batch_size, embedding_size + hidden_units[-1]]
        neumf_inputs = tf.concat([gmf_output, mlp_outputs], axis=-1)
        outputs = self.dense(neumf_inputs)
        return outputs

代码 github 地址
https://github.com/siyi8088/RS_code/blob/master/model_pipeline/neumf.py

【参考】

  1. https://arxiv.org/abs/1708.05031
  2. https://github.com/hexiangnan/neural_collaborative_filtering
  3. https://github.com/shenweichen/DeepCTR/blob/master/deepctr/layers/core.py

你可能感兴趣的:(NueMF 《Neural Collaborative Filtering》)