和前面的模型结构上都是大差不差的,但是FM归根结底还是个二阶特征交叉的模型,NFM在在Embedding层后添加 特征交叉池化层 用于对 Embedding向量两两计算元素积操作,并对交叉特征向量求和,得到池化层的输出向量。(可能描述不清楚,可以参考下面论文给出的计算过程)再把该向量输入上层的多层全连接神经网络,进行进一步的交叉。对比前面的DeepFM模型,讲二阶特征交叉部分由并行结构改为了串联的结构,DNN在二阶交叉特征进行进一步交叉,而DeepFM是二阶交叉特征 + 一阶特征DNN,还是在改变特征交叉的操作。说明特征交叉在推荐算法中确实很重要,让模型具备更强的非线性表达能力。

xivi 是 Embedding输出的向量

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
from sklearn.preprocessing import LabelEncoder, MinMaxScaler
from torch.utils.data import DataLoader, TensorDataset
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import pandas as pdclass DNN(nn.Module):def __init__(self, hidden_units):super().__init__()self.layers = nn.ModuleList([nn.Linear(in_features, out_features, bias=True) for in_features, out_features in zip(hidden_units[:-1], hidden_units[1:])])def forward(self, x):for layer in self.layers:x = F.relu(layer(x))return xclass NFM(nn.Module):def __init__(self, features_info, hidden_units, embedding_dim):super(NFM, self).__init__()# 解析特征信息self.dense_features, self.sparse_features, self.sparse_features_nunique = features_info# 解析拿到所有 数值型 和 稀疏型特征信息self.__dense_features_nums = len(self.dense_features)self.__sparse_features_nums = len(self.sparse_features)# embedding self.embeddings = nn.ModuleDict({"embed_" + key : nn.Embedding(num_embeds, embedding_dim)for key, num_embeds in self.sparse_features_nunique.items()})stack_dim = self.__dense_features_nums + embedding_dimhidden_units.insert(0, stack_dim)self.dnn = DNN(hidden_units)self.dnn_last_linear = nn.Linear(hidden_units[-1], 1, bias=False)def forward(self, x):# 从输入x中单独拿出 sparse_input 和 dense_input dense_inputs, sparse_inputs = x[:, :self.__dense_features_nums], x[:, self.__dense_features_nums:]sparse_inputs = sparse_inputs.long()embedding_feas = [self.embeddings["embed_" + key](sparse_inputs[:, idx]) for idx, key in enumerate(self.sparse_features)]embedding_feas = torch.stack(embedding_feas)embedding_feas = embedding_feas.permute((1, 0, 2))# 特征交叉池化层计算,参考公式embedding_feas = 1/2 * (torch.pow(torch.sum(embedding_feas, dim=1),2) - torch.sum(torch.pow(embedding_feas, 2), dim=1))input_feas = torch.cat([embedding_feas, dense_inputs], dim=-1)output = F.sigmoid(self.dnn_last_linear(self.dnn(input_feas)))return outputdef getCriteo(data_path='./criteo/train.csv'):df_data = pd.read_csv(data_path, sep=',')df_data.drop(['Id'], axis=1, inplace=True)dense_features = ['I'+str(i+1) for i in range(13)]sparse_features = ['C'+str(i+1) for i in range(26)]# 填充缺失值df_data[sparse_features] = df_data[sparse_features].fillna('-1')df_data[dense_features] = df_data[dense_features].fillna(0)# 类别型特征进行 LabelEncoder 编码for feature in sparse_features:df_data[feature] = LabelEncoder().fit_transform(df_data[feature])# 数值型特征进行 特征归一化df_data[dense_features] = MinMaxScaler().fit_transform(df_data[dense_features])label = df_data.pop('Label')sparse_features_nunique = {}for fea in sparse_features:sparse_features_nunique[fea] = df_data[fea].nunique()features_info = [dense_features, sparse_features, sparse_features_nunique]return df_data, label, features_infoclass TrainTask:def __init__(self, model, lr=0.001, use_cuda=False):self.__device = torch.device("cuda" if torch.cuda.is_available() and use_cuda else "cpu")self.__model = model.to(self.__device)self.__loss_fn = nn.BCELoss().to(self.__device)self.__optimizer = torch.optim.Adam(model.parameters(), lr=lr)self.train_loss = []self.eval_loss = []self.train_metric = []self.eval_metric = []def __train_one_batch(self, feas, labels):""" 训练一个batch"""self.__optimizer.zero_grad()# 1. 正向outputs = self.__model(feas)# 2. loss求解loss = self.__loss_fn(outputs.squeeze(), labels)# 3. 梯度回传loss.backward()self.__optimizer.step()return loss.item(), outputsdef __train_one_epoch(self, train_dataloader, epoch_id):""" 训练一个epoch"""self.__model.train()loss_sum = 0batch_id = 0for batch_id, (feas, labels) in enumerate(train_dataloader):feas, labels = Variable(feas).to(self.__device), Variable(labels).to(self.__device)loss, outputs = self.__train_one_batch(feas, labels)loss_sum += lossself.train_loss.append(loss_sum / (batch_id + 1))print("Training Epoch: %d, mean loss: %.5f" % (epoch_id, loss_sum / (batch_id + 1)))def train(self, train_dataset, eval_dataset, epochs, batch_size):# 构造DataLoadertrain_data_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)eval_data_loader = DataLoader(dataset=eval_dataset, batch_size=batch_size, shuffle=True)for epoch in range(epochs):print('-' * 20 + ' Epoch {} starts '.format(epoch) + '-' * 20)# 训练一个轮次self.__train_one_epoch(train_data_loader, epoch_id=epoch)# 验证一遍self.__eval(eval_data_loader, epoch_id=epoch)def __eval(self, eval_dataloader, epoch_id):""" 验证集上推理一遍"""batch_id = 0loss_sum = 0self.__model.eval()for batch_id, (feas, labels) in enumerate(eval_dataloader):with torch.no_grad():feas, labels = Variable(feas).to(self.__device), Variable(labels).to(self.__device)# 1. 正向outputs = self.__model(feas)# 2. loss求解loss = self.__loss_fn(outputs.view(-1), labels)loss_sum += loss.item()self.eval_loss.append(loss_sum / (batch_id + 1))print("Evaluate Epoch: %d, mean loss: %.5f" % (epoch_id, loss_sum / (batch_id + 1)))def __plot_metric(self, train_metrics, val_metrics, metric_name):""" 指标可视化"""epochs = range(1, len(train_metrics) + 1)plt.plot(epochs, train_metrics, 'bo--')plt.plot(epochs, val_metrics, 'ro-')plt.title('Training and validation '+ metric_name)plt.xlabel("Epochs")plt.ylabel(metric_name)plt.legend(["train_"+metric_name, 'val_'+metric_name])plt.show()def plot_loss_curve(self):self.__plot_metric(self.train_loss, self.eval_loss, "Loss")if __name__ == "__main__":df_data, label, features_info = getCriteo()# 划分、构建数据集、数据通道x_train, x_val, y_train, y_val = train_test_split(df_data, label, test_size=0.2, random_state=2022)train_dataset = TensorDataset(torch.tensor(x_train.values).float(), torch.tensor(y_train.values).float())val_dataset = TensorDataset(torch.tensor(x_val.values).float(), torch.tensor(y_val.values).float())# 构建模型model = NFM(features_info, hidden_units=[64, 32], embedding_dim=8)task = TrainTask(model, use_cuda=False)task.train(train_dataset, val_dataset, 20, 16)task.plot_loss_curve()

【推荐算法 学习与复现】-- 深度学习系列 -- NFM相关推荐

  1. 推荐算法普查(基于深度学习)

    摘要 深度学习已经成为推荐算法研究者们理想的选择.随着机器学习领域研究兴趣的强力增长,已经很难跟踪谁才是TopN推荐问题的最先进算法.与此同时,最近有几篇文章指出现在机器学习领域实践方面的一些问题,比 ...

  2. 主要推荐系统算法总结及Youtube深度学习推荐算法实例概括

    主要推荐系统算法总结及Youtube深度学习推荐算法实例概括 By ZhuZhiboSmith2017年7月09日 17:00 现如今,许多公司使用大数据来做超级相关推荐,并以此来增加收益.在海量推荐 ...

  3. 三维图形几何变换算法实验_基于深度学习的三维重建算法综述

    点击上方"计算机视觉life",选择"星标" 快速获得最新干货 00 前言 目前,三维重建技术已在游戏.电影.测绘.定位.导航.自动驾驶.VR/AR.工业制造以 ...

  4. 从起源到具体算法,这篇深度学习综述论文送给你

    来源:机器之心 本文共4602字,建议阅读8分钟. 本文为大家从最基础的角度来为大家解读什么是深度学习,以及深度学习的一些前沿发展. 自 2012 年多伦多大学 Alex Krizhevsky 等人提 ...

  5. 基于自动图像分割算法和扩展数据集深度学习的经济作物病害识别

    基于自动图像分割算法和扩展数据集深度学习的经济作物病害识别 1.作物病害识别出现的问题 实际应用中作物图像的复杂背景信息和训练数据不足会导致深度学习的错误识别. 2.研究内容 提出了一种基于自动图像分 ...

  6. 深度学习算法(第5期)----深度学习中的优化器选择

    欢迎关注微信公众号"智能算法" – 原文链接(阅读体验更佳): 深度学习算法(第5期)----深度学习中的优化器选择 上一期,我们一起学习了TensorFlow在训练深度网络的时候 ...

  7. 【推荐】AI人工智能-机器视觉-深度学习资料合集44篇

    机器视觉是人工智能正在快速发展的一个分支.简单说来,机器视觉就是用机器代替人眼来做测量和判断.机器视觉系统是通过机器视觉产品(即图像摄取装置,分CMOS和CCD两种)将被摄取目标转换成图像信号,传送给 ...

  8. 国内外免费电子书(数学、算法、图像、深度学习、机器学习)

    0. 数学 prob.pdf(概率论基础) Probabilistic-Programming-and-Bayesian-Methods-for-Hackers(Github) All The Mat ...

  9. 【深度学习】综述 | 深度学习的最新进展

    Recent Advances in Deep Learning:An Overview 来源:机器学习研习院 本文我们将简要讨论近年来关于深度学习的最新进展. 摘要:深度学习是机器学习和人工智能研究 ...

  10. 深度学习入门之PyTorch学习笔记:深度学习框架

    深度学习入门之PyTorch学习笔记 绪论 1 深度学习介绍 2 深度学习框架 2.1 深度学习框架介绍 2.1.1 TensorFlow 2.1.2 Caffe 2.1.3 Theano 2.1.4 ...

最新文章

  1. python拼写检查_拼写检查 - Python文本处理教程™
  2. 每个软件开发人员都应该知道的5种设计模式
  3. 【Python基础】太香了!推荐6个Python数据分析神器!!
  4. yum标准化安装nginx最新版
  5. es6语法-let定义变量和常量
  6. skywalking(4)
  7. R语言基础入门(7)之数据类型的性质
  8. 都9012年了,还有人说IntelliJ IDEA不好用?那是因为没掌握这些技巧。
  9. 为什么需要分布式配置中心
  10. (后端)SpringMVC提交数组时不能超过256个值(转)
  11. 抖音短视频如何快速制作?抖音怎么赚钱?
  12. 【面试题】前端人70%以上 不了解的promise/async await
  13. nginx设置IP、文件目录、请求头白名单
  14. 默认连接电脑的模式为MTP
  15. 人死后竟然会知道自己死了?
  16. 三大运营商问题反馈或投诉——移动/联通/电信 ,另附一堆使用电话
  17. 小公司的程序员,老想跳槽怎么办?
  18. 4G网络怎么设置网速更快?
  19. Docker的安装 与 环境配置 及 阿里云镜像仓库配置、常用命令等
  20. 【2k-3k高分辨率界面调整】jmeter3.3 win10界面元素调整,界面兼容,jemter文字太小

热门文章

  1. JAVA JNI调用科大讯飞离线语音合成(Linux篇)
  2. 灼口综合征的症状这么多呢呀?!
  3. SL8100 宽电压100V降压12V-24V大功率LED照明降压恒流驱动芯片IC
  4. PyTorch学习笔记2:nn.Module、优化器、模型的保存和加载、TensorBoard
  5. C++ if条件语句用法
  6. 客户管理中如何管理好客户资料
  7. 电脑不能连接wifi怎么办连不上wifi怎么办
  8. vs code修改代码后再次运行,报错:file“<stdin>“,line 1
  9. 【Python自动化任务】让运维更简单的7种定时任务实现方式,总有一种适合你的场景
  10. 计算机图形学之光线跟踪算法的研究与实现2017年我的优秀毕业论文