当前位置:   article > 正文

【推荐系统】DeepFM模型分析

deepfm

目录

一、原理

二、pytorch代码分析

1、数据准备

2、构建模型

2.1、FM模型

2.2、DNN模型

2.3、DeepFM模型

三、代码讲解 & 连接


emb层收敛速度慢的原因

1、输入极端稀疏化。这就意味着里面有很多0,导致w无法更新。

2、参数数量往往占整个神经网络参数数量的大半以上。


复习总结

fm:输入离散特征,离散特征经过emb_table,得到emb,#[batch_size, num_fields, embed_dim]每个特征的emb做交叉;
lr:输入离散特征,离散特征经过emb_table,得到emb,接liner(xx, 1),得到1的预测prob,#[batch_size, 1];
dnn:输入离散特征+数值型特征,离散特征经过emb_table,得到emb+数值型特征#[batch_size, deep_dims],经过DNN,得到prob;

深度推荐模型之DeepFM - 知乎

参考代码:GitHub - datawhalechina/torch-rechub: A Lighting Pytorch Framework for Recommendation Models, Easy-to-use and Easy-to-extend.

一、原理

解决的问题。(介绍的博客很多,建议看其他的人原理介绍。)

CTR预测任务中, 高阶特征和低阶特征的学习都非常的重要。 推荐模型我们也学习了很多,基本上是从最简单的线性模型(LR), 到考虑低阶特征交叉的FM, 到考虑高度交叉的神经网络,再到两者都考虑的W&D组合模型。 这样一串联就会发现前面这些模型存在的问题了, 简单盘点一下:

简单的线性模型虽然简单,同样这样是它的不足,就是限制了模型的表达能力,随着数据的大且复杂,这种模型并不能充分挖掘数据中的隐含信息,且忽略了特征间的交互,如果想交互,需要复杂的特征工程。

FM模型考虑了特征的二阶交叉,但是这种交叉仅停留在了二阶层次,虽然说能够进行高阶,但是计算量和复杂性一下子随着阶数的增加一下子就上来了。所以二阶是最常见的情况,会忽略高阶特征交叉的信息。

DNN,适合天然的高阶交叉信息的学习,但是低阶的交叉会忽略掉。

那么如果把上面这几种结构组合一下子,是不是效果会强大一些呢? 所以W&D模型在这个思路上进行了一个伟大的尝试,把简单的LR模型和DNN模型进行了组合, 使得模型既能够学习高阶组合特征,又能够学习低阶的特征模式,但是W&D的wide部分是用了LR模型, 这一块依然是需要一些经验性的特征工程的,且Wide部分和Deep部分需要两种不同的输入模式, 这个在具体实际应用中需要很强的业务经验。

所以总结起来就是:

  • FM与DNN共享输入emb向量。
  • 但是emb的参数更新是依赖于DNN部分,更新好的emb直接拿给FM去使用。

FM和DNN共享特征emb的好处

 关于【特征交互】

在CTR预测中, 学习用户点击行为背后的特征隐式交互非常重要。

二阶特征交互原来是这个意思:
通过对主流应用市场的研究,我们发现人们经常在用餐时间下载送餐的应用程序,这就表明应用类别和时间戳之间的(阶数-2)交互作用是CTR预测的一个信号。

三阶或者高阶特征交互是这个意思:
我们还发现男性青少年喜欢射击游戏和RPG游戏,这意味着应用类别、用户性别和年龄的(阶数-3)交互是CTR的另一个信号。

根据谷歌的W&D模型的应用, 作者发现同时考虑低阶和高阶的交互特征,比单独考虑其中之一有更多的改进

这也就是作者要进行本篇文章研究的原因或者动机之一(改进了LR,FM,DNN)。

论文介绍的小经验,

下面依然是工业上的一些使用经验, 这个模型也是工业上常用的模型:

  1. MLP这端神经网络的层数, 工业上的经验值不超过3层,一般用两层即可。
  2. MLP这端隐藏神经元的个数,工业上的经验值,一般128就差不多,最多不超过500
  3. embedding的维度一般不要超过50维, 经验值10-50

二、pytorch代码分析

https://github.com/zhongqiangwu960812/AI-RecommenderSystem/tree/master/DeepFM

使用是的部分Criteo数据集(原本包含45百万用户的点击记录,共有13个连续特征,26个分类特征。),介绍如下:

总共 13 列数值型特征 + 共有 26 列类别型特征(单值离散)

本次实验数据介绍:
- 1279个训练数据
- 320个验证数据
- 400个测试数据

torch.__version__: 1.3.1

加载所需要的包 

  1. import numpy as np
  2. import pandas as pd
  3. import matplotlib.pyplot as plt
  4. from tqdm import tqdm
  5. import datetime
  6. # pytorch
  7. import torch
  8. from torch.utils.data import DataLoader, Dataset, TensorDataset
  9. import torch.nn as nn
  10. import torch.nn.functional as F
  11. import torch.optim as optim
  12. # from torchkeras import summary, Model
  13. from sklearn.metrics import roc_auc_score
  14. import warnings
  15. warnings.filterwarnings('ignore')

1、数据准备

  1. # 指定训练数据路径
  2. file_path = './preprocessed_data/'
  3. def prepared_data(file_path):
  4. # 读入训练集, 验证集和测试集
  5. train = pd.read_csv(file_path + 'train_set.csv')
  6. val = pd.read_csv(file_path + 'val_set.csv')
  7. test = pd.read_csv(file_path + 'test_set.csv')
  8. trn_x, trn_y = train.drop(columns='Label').values, train['Label'].values
  9. val_x, val_y = val.drop(columns='Label').values, val['Label'].values
  10. test_x = test.values
  11. fea_col = np.load(file_path + 'fea_col.npy', allow_pickle=True)
  12. return fea_col, (trn_x, trn_y), (val_x, val_y), test_x
  13. """导入数据"""
  14. fea_cols, (trn_x, trn_y), (val_x, val_y), test_x = prepared_data(file_path)
  15. # 把数据构建成数据管道
  16. dl_train_dataset = TensorDataset(torch.tensor(trn_x).float(), torch.tensor(trn_y).float())
  17. dl_val_dataset = TensorDataset(torch.tensor(val_x).float(), torch.tensor(val_y).float())
  18. dl_train = DataLoader(dl_train_dataset, shuffle=True, batch_size=32)
  19. dl_val = DataLoader(dl_val_dataset, shuffle=True, batch_size=32)

我们可以打印一下数据,看一下内容:

  1. for x, y in iter(dl_train):
  2. print(x)
  3. print(x.shape, y)
  4. break
  5. # 运行结果:
  6. tensor([[8.4211e-02, 8.9118e-02, 0.0000e+00, ..., 5.3100e+02, 0.0000e+00,
  7. 0.0000e+00],
  8. [2.1053e-02, 2.5426e-04, 3.5474e-04, ..., 5.4700e+02, 0.0000e+00,
  9. 0.0000e+00],
  10. [0.0000e+00, 1.2713e-04, 0.0000e+00, ..., 5.3100e+02, 0.0000e+00,
  11. 0.0000e+00],
  12. ...,
  13. [0.0000e+00, 2.5426e-04, 1.1825e-04, ..., 5.7000e+02, 2.7000e+01,
  14. 4.6400e+02],
  15. [0.0000e+00, 8.3905e-03, 4.3751e-03, ..., 3.8000e+02, 2.0000e+00,
  16. 1.6000e+02],
  17. [0.0000e+00, 1.2713e-04, 0.0000e+00, ..., 1.6300e+02, 0.0000e+00,
  18. 0.0000e+00]])
  19. torch.Size([32, 39]) tensor([0., 0., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0.,
  20. 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.])

[32, 39] 是因为总共有13+26个特征,32是dl_train = DataLoader(dl_train_dataset, shuffle=True, batch_size=32)定义的。遍历一次,拉取32个样本数据。

2、构建模型

这里依然是使用继承nn.Module基类构建模型, 并辅助应用模型容器进行封装。这个模型也是两部分组成, 左边是FM模型, 右边是DNN模型, DNN模型和之前的形式一样, 所以下面我们首先先实现这两个单模型,然后把它们拼起来

DeepFM的模型架构如下:

2.1、FM模型

  1. class FM(nn.Module):
  2. """FM part"""
  3. def __init__(self, latent_dim, fea_num):
  4. """
  5. latent_dim: 各个离散特征隐向量的维度
  6. input_shape: 这个最后离散特征embedding之后的拼接和dense拼接的总特征个数
  7. """
  8. super(FM, self).__init__()
  9. self.latent_dim = latent_dim
  10. # 定义三个矩阵, 一个是全局偏置,
  11. # 一个是一阶权重矩阵,
  12. # 一个是二阶交叉矩阵,注意这里的参数由于是可学习参数,需要用nn.Parameter进行定义
  13. self.w0 = nn.Parameter(torch.zeros([1,]))
  14. self.w1 = nn.Parameter(torch.rand([fea_num, 1]))
  15. self.w2 = nn.Parameter(torch.rand([fea_num, latent_dim]))
  16. def forward(self, inputs):
  17. # 一阶交叉
  18. # print("self.w0:{}".format(self.w0))
  19. # self.w0:Parameter containing:
  20. # tensor([-0.0227], requires_grad=True)
  21. # (samples_num, 1) # B,1
  22. first_order = self.w0 + torch.mm(inputs, self.w1)
  23. # 二阶交叉 这个用FM的最终化简公式
  24. # (samples_num, 1) # B,1
  25. second_order = 1/2 * torch.sum(
  26. torch.pow(torch.mm(inputs, self.w2), 2) - torch.mm(torch.pow(inputs,2), torch.pow(self.w2, 2)),
  27. dim = 1,
  28. keepdim = True
  29. )
  30. return first_order + second_order

2.2、DNN模型

  1. class Dnn(nn.Module):
  2. """Dnn part"""
  3. def __init__(self, hidden_units, dropout=0.):
  4. """
  5. hidden_units: 列表, 每个元素表示每一层的神经单元个数, 比如[256, 128, 64], 两层网络, 第一层神经单元128, 第二层64, 第一个维度是输入维度
  6. dropout = 0.
  7. """
  8. super(Dnn, self).__init__()
  9. self.dnn_network = nn.ModuleList([nn.Linear(layer[0], layer[1]) for layer in list(zip(hidden_units[:-1], hidden_units[1:]))])
  10. self.dropout = nn.Dropout(dropout)
  11. def forward(self, x):
  12. for linear in self.dnn_network:
  13. x = linear(x)
  14. x = F.relu(x)
  15. x = self.dropout(x)
  16. return x

中间有个部分不明白

  1. for layer in list(zip(hidden_units[:-1], hidden_units[1:])):
  2. print(layer)
  3. (256, 128)
  4. (128, 64)

意思就是输入x,经过(256,128)的NN+relu。然后再经过(12,64)的NN+relu。最后接一个dropout。 

2.3、DeepFM模型

  1. class DeepFM(nn.Module):
  2. def __init__(self, feature_columns, hidden_units, dnn_dropout=0.):
  3. """
  4. DeepFM:
  5. :param feature_columns: 特征信息, 这个传入的是fea_cols
  6. :param hidden_units: 隐藏单元个数, 一个列表的形式, 列表的长度代表层数, 每个元素代表每一层神经元个数
  7. """
  8. super(DeepFM, self).__init__()
  9. self.dense_feature_cols, self.sparse_feature_cols = feature_columns
  10. # embedding
  11. self.embed_layers = nn.ModuleDict({
  12. 'embed_' + str(i): nn.Embedding(num_embeddings=feat['feat_num'], embedding_dim=feat['embed_dim'])
  13. for i, feat in enumerate(self.sparse_feature_cols)
  14. })
  15. print("self.embed_layers\n", self.embed_layers)
  16. # print("[0]:", self.sparse_feature_cols[0]['embed_dim']) # 8
  17. # 这里要注意Pytorch的linear和tf的dense的不同之处,
  18. # Pytorch的linear需要输入特征和输出特征维度, 而传入的hidden_units的第一个是第一层隐藏的神经单元个数,这里需要加个输入维度
  19. self.fea_num = len(self.dense_feature_cols) + len(self.sparse_feature_cols)*self.sparse_feature_cols[0]['embed_dim']
  20. hidden_units.insert(0, self.fea_num) # 在hidden前加入输入特征的维度
  21. self.fm = FM(self.sparse_feature_cols[0]['embed_dim'], self.fea_num)
  22. self.dnn_network = Dnn(hidden_units, dnn_dropout)
  23. self.nn_final_linear = nn.Linear(hidden_units[-1], 1)
  24. def forward(self, x):
  25. dense_inputs, sparse_inputs = x[:, :len(self.dense_feature_cols)], x[:, len(self.dense_feature_cols):]
  26. sparse_inputs = sparse_inputs.long() # 转成long类型才能作为nn.embedding的输入
  27. sparse_embeds = [self.embed_layers['embed_'+str(i)](sparse_inputs[:, i]) for i in range(sparse_inputs.shape[1])]
  28. # print("sparse_inputs.shape[1]", sparse_inputs.shape[1]) # 26个离散型特征
  29. # for i in range(sparse_inputs.shape[1]): # 遍历第1个离散特征,i=1
  30. # print("(sparse_inputs[:, i])\n ", (sparse_inputs[:, i])) # 32个batchsize的第1个特征
  31. # tensor([201, 10, 12, 170, 154, 12, 52, 236, 161, 74, 76, 126, 51, 183,
  32. # 42, 149, 51, 9, 91, 126, 10, 37, 51, 51, 125, 230, 131, 132,
  33. # 12, 12, 130, 12])
  34. # c = self.embed_layers['embed_'+str(i)](sparse_inputs[:, i]) # [1,32,8]
  35. # 从emb table中lookup 第1特征的emb矩阵中,get 32个id对应的emb向量是多少,get到第1个特征中,id=201的vector是多少
  36. # print("self.embed_layers['embed_'+str(i)](sparse_inputs[:, i])\n", self.embed_layers['embed_'+str(i)](sparse_inputs[:, i]))
  37. sparse_embeds = torch.cat(sparse_embeds, dim=-1) # 横向拼接, dim=-1按照最后一维拼接。
  38. # sparse_embeds_size torch.Size([32, 208])
  39. # print("sparse_embeds_size ", sparse_embeds.shape)
  40. # 把离散特征和连续特征进行拼接作为FM和DNN的输入
  41. x = torch.cat([sparse_embeds, dense_inputs], dim=-1)
  42. # Wide
  43. wide_outputs = self.fm(x)
  44. # deep
  45. deep_outputs = self.nn_final_linear(self.dnn_network(x))
  46. # 模型的最后输出
  47. outputs = F.sigmoid(torch.add(wide_outputs, deep_outputs))
  48. return outputs

其中有些不理解的地方进行了打印,

self.embed_layers

  1. self.embed_layers
  2. ModuleDict(
  3. (embed_0): Embedding(79, 8)
  4. (embed_1): Embedding(252, 8)
  5. (embed_10): Embedding(926, 8)
  6. (embed_11): Embedding(1239, 8)
  7. (embed_12): Embedding(824, 8)
  8. (embed_13): Embedding(20, 8)
  9. (embed_14): Embedding(819, 8)
  10. (embed_15): Embedding(1159, 8)
  11. (embed_16): Embedding(9, 8)
  12. (embed_17): Embedding(534, 8)
  13. (embed_18): Embedding(201, 8)
  14. (embed_19): Embedding(4, 8)
  15. (embed_2): Embedding(1293, 8)
  16. (embed_20): Embedding(1204, 8)
  17. (embed_21): Embedding(7, 8)
  18. (embed_22): Embedding(12, 8)
  19. (embed_23): Embedding(729, 8)
  20. (embed_24): Embedding(33, 8)
  21. (embed_25): Embedding(554, 8)
  22. (embed_3): Embedding(1043, 8)
  23. (embed_4): Embedding(30, 8)
  24. (embed_5): Embedding(7, 8)
  25. (embed_6): Embedding(1164, 8)
  26. (embed_7): Embedding(39, 8)
  27. (embed_8): Embedding(2, 8)
  28. (embed_9): Embedding(908, 8)
  29. )

sparse_embeds = [self.embed_layers['embed_'+str(i)](sparse_inputs[:, i]) for i in range(sparse_inputs.shape[1])]

26个离散型特征:sparse_inputs.shape[1] 26。

(sparse_inputs[:, i]) ,假如i=1,(sparse_inputs[:, 1]),输入Batchsize的所有行第一列。

  1. # 32个batchsize的第1个特征
  2. (sparse_inputs[:, i])
  3. tensor([13, 15, 26, 27, 0, 64, 56, 26, 40, 15, 0, 43, 0, 43, 33, 0, 0, 36,
  4. 0, 26, 0, 0, 0, 43, 26, 0, 33, 0, 33, 33, 75, 27])

self.embed_layers['embed_'+str(1)](sparse_inputs[:, 1])

从embed_1的embedding矩阵中,找到13,15,26。。。27的id对应的emb vector。

  1. tensor([[-1.4639, -0.7128, -1.0563, -1.4808, 0.4443, 0.0396, -0.4131, -0.4098],
  2. [-0.3633, 0.3777, 0.6757, -0.3183, 0.7299, 1.1299, 0.7224, 0.2695],
  3. [ 2.2873, 0.2555, 0.7544, -1.0387, 2.0232, 1.0837, 1.1289, -0.4323],
  4. [-0.2851, -0.3741, 0.8221, 0.7784, -0.1501, -0.3380, 1.2154, 0.1392],
  5. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  6. [ 1.3064, -0.2468, 0.9592, -0.6913, 0.1329, 0.2627, -0.0209, -0.9455],
  7. [ 0.6701, 0.0199, 1.1647, -0.0132, 0.5499, -0.6432, 2.4543, 0.2394],
  8. [ 2.2873, 0.2555, 0.7544, -1.0387, 2.0232, 1.0837, 1.1289, -0.4323],
  9. [ 0.0656, 0.8834, -1.2746, -0.5263, -1.3244, -0.5119, 0.8927, -1.0337],
  10. [-0.3633, 0.3777, 0.6757, -0.3183, 0.7299, 1.1299, 0.7224, 0.2695],
  11. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  12. [-0.4535, -0.2620, 0.8880, 0.5566, 0.5189, 1.0608, -0.9572, -0.6825],
  13. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  14. [-0.4535, -0.2620, 0.8880, 0.5566, 0.5189, 1.0608, -0.9572, -0.6825],
  15. [ 0.8973, 1.0933, -0.3527, -0.3034, -0.7779, 0.1933, 1.0803, 2.2664],
  16. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  17. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  18. [ 0.4971, 0.2588, 0.4070, 0.9371, 1.3312, 1.1213, -0.4729, -0.1009],
  19. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  20. [ 2.2873, 0.2555, 0.7544, -1.0387, 2.0232, 1.0837, 1.1289, -0.4323],
  21. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  22. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  23. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  24. [-0.4535, -0.2620, 0.8880, 0.5566, 0.5189, 1.0608, -0.9572, -0.6825],
  25. [ 2.2873, 0.2555, 0.7544, -1.0387, 2.0232, 1.0837, 1.1289, -0.4323],
  26. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  27. [ 0.8973, 1.0933, -0.3527, -0.3034, -0.7779, 0.1933, 1.0803, 2.2664],
  28. [-0.2266, -0.0376, -0.1725, 0.4715, 1.5847, 0.0148, -0.7969, -0.3344],
  29. [ 0.8973, 1.0933, -0.3527, -0.3034, -0.7779, 0.1933, 1.0803, 2.2664],
  30. [ 0.8973, 1.0933, -0.3527, -0.3034, -0.7779, 0.1933, 1.0803, 2.2664],
  31. [-1.9452, -1.4843, -0.4154, -0.0963, -0.3846, 0.4062, -0.5578, -0.4342],
  32. [-0.2851, -0.3741, 0.8221, 0.7784, -0.1501, -0.3380, 1.2154, 0.1392]],
  33. grad_fn=<EmbeddingBackward>)

输入x,y数据

  1. (features, labels)
  2. (tensor([[0.0000e+00, 3.8139e-04, 4.7298e-04, ..., 7.1000e+02, 2.0000e+00,
  3. 3.6600e+02],
  4. [0.0000e+00, 3.8139e-04, 1.7737e-03, ..., 5.7300e+02, 0.0000e+00,
  5. 0.0000e+00],
  6. [6.3158e-02, 1.2713e-04, 3.5474e-04, ..., 6.7000e+01, 2.7000e+01,
  7. 4.0500e+02],
  8. ...,
  9. [0.0000e+00, 4.8309e-03, 0.0000e+00, ..., 4.3100e+02, 2.7000e+01,
  10. 5.4500e+02],
  11. [0.0000e+00, 8.8991e-03, 0.0000e+00, ..., 1.6300e+02, 1.0000e+00,
  12. 5.4400e+02],
  13. [0.0000e+00, 3.8139e-04, 8.8684e-03, ..., 6.7000e+01, 2.7000e+01,
  14. 4.0500e+02]]), tensor([0., 0., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0.,
  15. 0., 0., 0., 0., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0.]))
  16. features.shape torch.Size([32, 39])
  17. labels.shape torch.Size([32])

然后再将所有的emb特征,根据dim=-1,最后一维(横向拼接),sparse_embeds_size  torch.Size([32, 208])。当做所有离散特征的处理结果。

上述代码只能处理单值离散型特征。

得到sparse_embeds:

  • 单值离散特征:

feat_a = [12], lookup idx=12的emb vector即可。

  • 如果想要处理变长离散特征, pad_size=5:

feat_b = [12,14,9,0,0], lookup idx=12,14,9的emb vector, 再除以3。

最后整个DeepFM模型结构如下,

  1. DeepFM(
  2. (embed_layers): ModuleDict(
  3. (embed_0): Embedding(79, 8)
  4. (embed_1): Embedding(252, 8)
  5. (embed_10): Embedding(926, 8)
  6. (embed_11): Embedding(1239, 8)
  7. (embed_12): Embedding(824, 8)
  8. (embed_13): Embedding(20, 8)
  9. (embed_14): Embedding(819, 8)
  10. (embed_15): Embedding(1159, 8)
  11. (embed_16): Embedding(9, 8)
  12. (embed_17): Embedding(534, 8)
  13. (embed_18): Embedding(201, 8)
  14. (embed_19): Embedding(4, 8)
  15. (embed_2): Embedding(1293, 8)
  16. (embed_20): Embedding(1204, 8)
  17. (embed_21): Embedding(7, 8)
  18. (embed_22): Embedding(12, 8)
  19. (embed_23): Embedding(729, 8)
  20. (embed_24): Embedding(33, 8)
  21. (embed_25): Embedding(554, 8)
  22. (embed_3): Embedding(1043, 8)
  23. (embed_4): Embedding(30, 8)
  24. (embed_5): Embedding(7, 8)
  25. (embed_6): Embedding(1164, 8)
  26. (embed_7): Embedding(39, 8)
  27. (embed_8): Embedding(2, 8)
  28. (embed_9): Embedding(908, 8)
  29. )
  30. (fm): FM()
  31. (dnn_network): Dnn(
  32. (dnn_network): ModuleList(
  33. (0): Linear(in_features=221, out_features=128, bias=True)
  34. (1): Linear(in_features=128, out_features=64, bias=True)
  35. (2): Linear(in_features=64, out_features=32, bias=True)
  36. )
  37. (dropout): Dropout(p=0.0, inplace=False)
  38. )
  39. (nn_final_linear): Linear(in_features=32, out_features=1, bias=True)
  40. )

三、代码讲解 & 连接

推荐算法之: DeepFM及使用DeepCTR测试

深度学习deepctr 推荐算法召回youtube和排序deepfm,保存与加载、预测和部署(使用deepctr实现deepfm)

一些好的链接:

DeepFM推荐系统 论文+代码 (数据来源+代码)

https://github.com/whk6688/tensorflow-DeepFM(提供增量训练的代码)

AI上推荐 之 FNN、DeepFM与NFM(FM在深度学习中的身影重现) (大部分理论介绍来自于这里)

https://github.com/zhongqiangwu960812/AI-RecommenderSystem/tree/master/DeepFM deepfm pytorch版

推荐算法之: DeepFM及使用DeepCTR测试

推荐系统遇上深度学习(一)--FM模型理论和实践(可以回顾下FM原理)

数据下载地址:

https://s3-eu-west-1.amazonaws.com/kaggle-display-advertising-challenge-dataset/dac.tar.gz

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/827025
推荐阅读
相关标签
  

闽ICP备14008679号