• 【推荐系统】DeepFM模型


    因子分解机(Factorization Machines, FM)通过对于每一维特征的隐变量内积来提取特征组合。虽然理论上来讲FM可以对高阶特征组合进行建模,但实际上因为计算复杂度的原因一般都只用到了二阶特征组合,对于更高阶的特征组合,可以用Deep解决。

    FM因子分解机

    数学原理: 

    • 当k足够大时,对于任意对称正定的实矩阵W\epsilon R^{n*n},均存在实矩阵V \epsilon R^{n*k},使得W = VV^{T} 

    FM模型 

    • w0为偏置项,蓝色部分为特征一阶计算,橘色部分为特征二阶计算(包含特征的隐向量内积计算)

    •  特征二阶计算中,将特征矩阵W分解为两个隐向量矩阵vi,vj

     两个隐向量矩阵做矩阵运算得到W特征矩阵

    •  当二阶特征交叉时,不仅两个特征Xi,Xj之间相乘,这两个特征的各自的隐向量之间也要做内积运算。

     FM模型二阶计算部分推导

    • 二阶计算部分 = 特征矩阵除对角线元素之外元素的一半(特征矩阵对称正定矩阵,对角线两侧元素完全相同。

    DeepFM

    DeepFM包含两部分:神经网络部分与因子分解机部分,分别负责低阶特征的提取和高阶特征的提取。这两部分共享同样的输入。

    1. 不需要预训练 FM 得到隐向量;
    2. 不需要人工特征工程;
    3. 能同时学习低阶和高阶的组合特征;
    4. FM 模块和 Deep 模块共享 Feature Embedding 部分,可以更快的训练,以及更精确的训练学习。

    1. import tensorflow as tf
    2. def get_dataset(file_path):
    3. dataset = tf.data.experimental.make_csv_dataset(
    4. file_path,
    5. batch_size=12,
    6. label_name='label',
    7. na_value="0",
    8. num_epochs=1,
    9. ignore_errors=True)
    10. return dataset
    11. train_dataset = get_dataset('trainingSamples.csv')
    12. test_dataset = get_dataset('testSamples.csv')
    13. #输入特征
    14. inputs = {
    15. 'movieAvgRating': tf.keras.layers.Input(name='movieAvgRating', shape=(), dtype='float32'),
    16. 'movieRatingStddev': tf.keras.layers.Input(name='movieRatingStddev', shape=(), dtype='float32'),
    17. 'movieRatingCount': tf.keras.layers.Input(name='movieRatingCount', shape=(), dtype='int32'),
    18. 'userAvgRating': tf.keras.layers.Input(name='userAvgRating', shape=(), dtype='float32'),
    19. 'userRatingStddev': tf.keras.layers.Input(name='userRatingStddev', shape=(), dtype='float32'),
    20. 'userRatingCount': tf.keras.layers.Input(name='userRatingCount', shape=(), dtype='int32'),
    21. 'releaseYear': tf.keras.layers.Input(name='releaseYear', shape=(), dtype='int32'),
    22. 'movieId': tf.keras.layers.Input(name='movieId', shape=(), dtype='int32'),
    23. 'userId': tf.keras.layers.Input(name='userId', shape=(), dtype='int32'),
    24. 'userRatedMovie1': tf.keras.layers.Input(name='userRatedMovie1', shape=(), dtype='int32'),
    25. 'userGenre1': tf.keras.layers.Input(name='userGenre1', shape=(), dtype='string'),
    26. 'userGenre2': tf.keras.layers.Input(name='userGenre2', shape=(), dtype='string'),
    27. 'userGenre3': tf.keras.layers.Input(name='userGenre3', shape=(), dtype='string'),
    28. 'userGenre4': tf.keras.layers.Input(name='userGenre4', shape=(), dtype='string'),
    29. 'userGenre5': tf.keras.layers.Input(name='userGenre5', shape=(), dtype='string'),
    30. 'movieGenre1': tf.keras.layers.Input(name='movieGenre1', shape=(), dtype='string'),
    31. 'movieGenre2': tf.keras.layers.Input(name='movieGenre2', shape=(), dtype='string'),
    32. 'movieGenre3': tf.keras.layers.Input(name='movieGenre3', shape=(), dtype='string'),
    33. }
    34. #将类别型特征进行One-hot编码,再进行embedding化得到稠密的特征向量
    35. #movie Id
    36. # One-hot
    37. movie_col = tf.feature_column.categorical_column_with_identity(key='movieId', num_buckets=1001)
    38. #embedding
    39. movie_emb_col = tf.feature_column.embedding_column(movie_col, 10)
    40. #转化成multi-hot
    41. movie_ind_col = tf.feature_column.indicator_column(movie_col)
    42. # user Id
    43. user_col = tf.feature_column.categorical_column_with_identity(key='userId', num_buckets=30001)
    44. user_emb_col = tf.feature_column.embedding_column(user_col, 10)
    45. user_ind_col = tf.feature_column.indicator_column(user_col) # user id indicator columns
    46. # 不同风格的特征list
    47. genre_vocab = ['Film-Noir', 'Action', 'Adventure', 'Horror', 'Romance', 'War', 'Comedy', 'Western', 'Documentary',
    48. 'Sci-Fi', 'Drama', 'Thriller',
    49. 'Crime', 'Fantasy', 'Animation', 'IMAX', 'Mystery', 'Children', 'Musical']
    50. # 将类别特征进行hash映射。根据单词的序列顺序,把单词根据index转换成one hot encoding。
    51. user_genre_col = tf.feature_column.categorical_column_with_vocabulary_list(key="userGenre1",
    52. vocabulary_list=genre_vocab)
    53. # indicator_column(),将 categorical_column表示成 multi-hot形式的 dense tensor,同一个元素在一行出现多次, 计数会超过1
    54. user_genre_ind_col = tf.feature_column.indicator_column(user_genre_col)
    55. #embedding_column(),将稀疏矩阵转换为稠密矩阵
    56. user_genre_emb_col = tf.feature_column.embedding_column(user_genre_col, 10)
    57. # item genre embedding feature
    58. item_genre_col = tf.feature_column.categorical_column_with_vocabulary_list(key="movieGenre1",
    59. vocabulary_list=genre_vocab)
    60. item_genre_ind_col = tf.feature_column.indicator_column(item_genre_col)
    61. item_genre_emb_col = tf.feature_column.embedding_column(item_genre_col, 10)
    62. # FM的一阶特征运算
    63. #将预处理完的类别特征列合并
    64. cat_columns = [movie_ind_col, user_ind_col, user_genre_ind_col, item_genre_ind_col]
    65. #数值型特征不用经过独热编码和特征稠密化,转换成可以输入神经网络的dense类型直接输入网络
    66. #转换类型
    67. deep_columns = [tf.feature_column.numeric_column('releaseYear'),
    68. tf.feature_column.numeric_column('movieRatingCount'),
    69. tf.feature_column.numeric_column('movieAvgRating'),
    70. tf.feature_column.numeric_column('movieRatingStddev'),
    71. tf.feature_column.numeric_column('userRatingCount'),
    72. tf.feature_column.numeric_column('userAvgRating'),
    73. tf.feature_column.numeric_column('userRatingStddev')]
    74. #DenseFeatures(),针对类别型特征生成稠密张量
    75. first_order_cat_feature = tf.keras.layers.DenseFeatures(cat_columns)(inputs)
    76. first_order_cat_feature = tf.keras.layers.Dense(1, activation=None)(first_order_cat_feature)
    77. #针对数值型特征生成稠密张量
    78. first_order_deep_feature = tf.keras.layers.DenseFeatures(deep_columns)(inputs)
    79. first_order_deep_feature = tf.keras.layers.Dense(1, activation=None)(first_order_deep_feature)
    80. #添加一个对张量进行求和的层
    81. first_order_feature = tf.keras.layers.Add()([first_order_cat_feature, first_order_deep_feature])
    82. ## FM的二阶特征运算
    83. #类别特征
    84. second_order_cat_columns_emb = [tf.keras.layers.DenseFeatures([item_genre_emb_col])(inputs),
    85. tf.keras.layers.DenseFeatures([movie_emb_col])(inputs),
    86. tf.keras.layers.DenseFeatures([user_genre_emb_col])(inputs),
    87. tf.keras.layers.DenseFeatures([user_emb_col])(inputs)
    88. ]
    89. second_order_cat_columns = []
    90. for feature_emb in second_order_cat_columns_emb:
    91. feature = tf.keras.layers.Dense(64, activation=None)(feature_emb)
    92. feature = tf.keras.layers.Reshape((-1, 64))(feature)
    93. second_order_cat_columns.append(feature)
    94. #数值特征
    95. second_order_deep_columns = tf.keras.layers.DenseFeatures(deep_columns)(inputs)
    96. second_order_deep_columns = tf.keras.layers.Dense(64, activation=None)(second_order_deep_columns)
    97. second_order_deep_columns = tf.keras.layers.Reshape((-1, 64))(second_order_deep_columns)
    98. second_order_fm_feature = tf.keras.layers.Concatenate(axis=1)(second_order_cat_columns + [second_order_deep_columns])
    99. #二阶特征计算
    100. deep_feature = tf.keras.layers.Flatten()(second_order_fm_feature)
    101. deep_feature = tf.keras.layers.Dense(32, activation='relu')(deep_feature)
    102. deep_feature = tf.keras.layers.Dense(16, activation='relu')(deep_feature)
    103. class ReduceLayer(tf.keras.layers.Layer):
    104. #init(),参数初始化
    105. def __init__(self, axis, op='sum', **kwargs):
    106. super().__init__()
    107. self.axis = axis
    108. self.op = op
    109. assert self.op in ['sum', 'mean']
    110. #获取输入数据的shape
    111. def build(self, input_shape):
    112. pass
    113. #调用call()会被执行
    114. def call(self, input, **kwargs):
    115. if self.op == 'sum':
    116. return tf.reduce_sum(input, axis=self.axis)
    117. elif self.op == 'mean':
    118. return tf.reduce_mean(input, axis=self.axis)
    119. return tf.reduce_sum(input, axis=self.axis)
    120. second_order_sum_feature = ReduceLayer(1)(second_order_fm_feature)
    121. second_order_sum_square_feature = tf.keras.layers.multiply([second_order_sum_feature, second_order_sum_feature])
    122. second_order_square_feature = tf.keras.layers.multiply([second_order_fm_feature, second_order_fm_feature])
    123. second_order_square_sum_feature = ReduceLayer(1)(second_order_square_feature)
    124. ## second_order_fm_feature
    125. second_order_fm_feature = tf.keras.layers.subtract([second_order_sum_square_feature, second_order_square_sum_feature])
    126. concatenated_outputs = tf.keras.layers.Concatenate(axis=1)([first_order_feature, second_order_fm_feature, deep_feature])
    127. output_layer = tf.keras.layers.Dense(1, activation='sigmoid')(concatenated_outputs)
    128. model = tf.keras.Model(inputs, output_layer)
    129. # compile the model, set loss function, optimizer and evaluation metrics
    130. model.compile(
    131. loss='binary_crossentropy',
    132. optimizer='adam',
    133. metrics=['accuracy', tf.keras.metrics.AUC(curve='ROC'), tf.keras.metrics.AUC(curve='PR')])
    134. # train the model
    135. model.fit(train_dataset, epochs=5)
    136. # evaluate the model
    137. test_loss, test_accuracy, test_roc_auc, test_pr_auc = model.evaluate(test_dataset)
    138. print('\n\nTest Loss {}, Test Accuracy {}, Test ROC AUC {}, Test PR AUC {}'.format(test_loss, test_accuracy,
    139. test_roc_auc, test_pr_auc))
    140. # print some predict results
    141. predictions = model.predict(test_dataset)
    142. for prediction, goodRating in zip(predictions[:12], list(test_dataset)[0][1][:12]):
    143. print("Predicted good rating: {:.2%}".format(prediction[0]),
    144. " | Actual rating label: ",
    145. ("Good Rating" if bool(goodRating) else "Bad Rating"))

     【王喆-推荐系统】模型篇-(task7)DeepFM处理交叉特征

     推荐系统 - DeepFM架构详解

  • 相关阅读:
    关于lenra你需要了解的
    【AI绘画】免费GPU Tesla A100 32G算力部署Stable Diffusion
    SpringBoot连接MySQL数据库,使用Mybatis框架(入门)
    python快速构建http服务
    卷积神经网络处理图像,卷积神经网络图像增强
    Upload-labs 1~15 通关详细教程
    含文档+PPT+源码等]精品基于Uniapp实现的美食APP[包运行成功]计算机毕业设计安卓项目源码
    大数据Doris(十):添加BE步骤
    开发基于 ChatGPT 分析热点事件并生成文章的网站应用【热点问天】把百度等热点用chatGPT来对热点事件分析海量发文章 开发步骤 多种方式获取利润
    vue从地址栏输入路径后path和导航按钮不匹配问题
  • 原文地址:https://blog.csdn.net/m0_51933492/article/details/126888136