深度学习推荐系统(五)DeepCrossing模型及其在Criteo数据集上的应用

深度学习推荐系统(五)Deep&Crossing模型及其在Criteo数据集上的应用

在2016年, 随着微软的Deep Crossing, 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出, 推荐系统全面进入了深度学习时代, 时至今日, 依然是主流。 推荐模型主要有下面两个进展:

  • 与传统的机器学习模型相比, 深度学习模型的表达能力更强, 能够挖掘更多数据中隐藏的模式

  • 深度学习模型结构非常灵活, 能够根据业务场景和数据特点, 灵活调整模型结构, 使模型与应用场景完美契合

深度学习推荐模型,以多层感知机(MLP)为核心, 通过改变神经网络结构进行演化。

在这里插入图片描述

1 Deep&Crossing模型原理

1.1 Deep&Crossing模型提出的背景

  • Wide&Deep 模型的提出不仅综合了记忆能力泛化能力,而且开启了不同网络结构融合的新思路。

  • 在 Wide&Deep 模型之后,有越来越多的工作集中于分别改进Wide&Deep模型的 Wide部分或是 Deep 部分。

  • 典型的工作是2017年由斯坦福大学和谷歌的研究人员提出的 Deep&Cross模型(简称DCN)。

  • Deep&Cross 模型的主要思路是使用 Cross 网络替代原来的 Wide 部分。由于 Deep 部分的设计思路并没有本质的改变,最主要的创新点是Cross 部分的设计思路。

1.2 Deep&Crossing的模型结构

DCN模型的结构非常简洁,从下往上依次为:Embedding和Stacking层、Cross网络层与Deep网络层并列、输出合并层,得到最终的预测结果

在这里插入图片描述

1.2.1 Embedding and stacking layer

Embedding层作用依然是把稀疏离散的类别型特征变成低维密集型。

然后需要将所有的密集型特征(数值型特征)与通过embedding转换后的特征进行联合(Stacking)。

在这里插入图片描述

1.2.2 Cross NetWork模型

在这里插入图片描述

在这里插入图片描述

举例说明

在这里插入图片描述

可以看到

  • x1中包含了所有的x0的1,2阶特征的交互。第l层特征对应的最高的叉乘阶数为l+1

  • Cross网络的参数是共享的, 每一层的这个权重特征之间共享, 这个可以使得模型泛化到看不见的特征交互作用, 并且对噪声更具有鲁棒性。

  • Deep Network及组合层比较简单,不再赘述。

1.3 Deep&Crossing模型代码复现

import torch.nn as nn
import torch.nn.functional as F
import torchclass CrossNetwork(nn.Module):"""Cross Network"""def __init__(self, layer_num, input_dim):super(CrossNetwork, self).__init__()self.layer_num = layer_num# 定义网络层的参数self.cross_weights = nn.ParameterList([nn.Parameter(torch.rand(input_dim, 1))for i in range(self.layer_num)])self.cross_bias = nn.ParameterList([nn.Parameter(torch.rand(input_dim, 1))for i in range(self.layer_num)])def forward(self, x):# x是(batchsize, dim)的形状, 先扩展一个维度到(batchsize, dim, 1)x_0 = torch.unsqueeze(x, dim=2)x = x_0.clone()xT = x_0.clone().permute((0, 2, 1))     # (batchsize, 1, dim)for i in range(self.layer_num):x = torch.matmul(torch.bmm(x_0, xT), self.cross_weights[i]) + self.cross_bias[i] + x   # (batchsize, dim, 1)xT = x.clone().permute((0, 2, 1))   # (batchsize, 1, dim)x = x.squeeze(2)  # (batchsize, dim)return xclass Dnn(nn.Module):"""Dnn part"""def __init__(self, hidden_units, dropout=0.):"""hidden_units: 列表, 每个元素表示每一层的神经单元个数, 比如[256, 128, 64], 两层网络, 第一层神经单元128, 第二层64, 第一个维度是输入维度dropout: 失活率"""super(Dnn, self).__init__()self.dnn_network = nn.ModuleList([nn.Linear(layer[0], layer[1]) for layer in list(zip(hidden_units[:-1], hidden_units[1:]))])self.dropout = nn.Dropout(p=dropout)def forward(self, x):for linear in self.dnn_network:x = linear(x)x = F.relu(x)x = self.dropout(x)return xclass DCN(nn.Module):def __init__(self, feature_info, hidden_units, layer_num, embed_dim=8,dnn_dropout=0.):"""feature_info: 特征信息(数值特征, 类别特征, 类别特征embedding映射)hidden_units: 列表, 隐藏单元的个数(多层残差那里的)layer_num: cross network的层数embed_dim: embedding维度dnn_dropout: Dropout层的失活比例"""super(DCN, self).__init__()self.dense_features, self.sparse_features, self.sparse_features_map = feature_info# embedding层, 这里需要一个列表的形式, 因为每个类别特征都需要embeddingself.embed_layers = nn.ModuleDict({'embed_' + str(key): nn.Embedding(num_embeddings=val, embedding_dim=embed_dim)for key, val in self.sparse_features_map.items()})# 统计embedding_dim的总维度# 一个离散型(类别型)变量 通过embedding层变为10纬embed_dim_sum = sum([embed_dim] * len(self.sparse_features))# 总维度 = 数值型特征的纬度 + 离散型变量经过embedding后的纬度dim_sum = len(self.dense_features) + embed_dim_sumhidden_units.insert(0, dim_sum)# 1、cross Network# layer_num是交叉网络的层数, hidden_units[0]表示输入的整体维度大小self.cross_network = CrossNetwork(layer_num, hidden_units[0])# 2、Deep Networkself.dnn_network = Dnn(hidden_units,dnn_dropout)# 最后一层线性层,输入纬度是(cross Network输出纬度 + Deep Network输出纬度)self.final_linear = nn.Linear(hidden_units[-1] + hidden_units[0], 1)def forward(self, x):# 1、先把输入向量x分成两部分处理、因为数值型和类别型的处理方式不一样dense_input, sparse_inputs = x[:, :len(self.dense_features)], x[:, len(self.dense_features):]# 2、转换为long形sparse_inputs = sparse_inputs.long()# 2、不同的类别特征分别embeddingsparse_embeds = [self.embed_layers['embed_' + key](sparse_inputs[:, i]) for key, i inzip(self.sparse_features_map.keys(), range(sparse_inputs.shape[1]))]# 3、把类别型特征进行拼接,即emdedding后,由3行转换为1行sparse_embeds = torch.cat(sparse_embeds, axis=-1)# 4、数值型和类别型特征进行拼接x = torch.cat([sparse_embeds, dense_input], axis=-1)# cross Networkcross_out = self.cross_network(x)# Deep Networkdeep_out = self.dnn_network(x)#  Concatenatetotal_x = torch.cat([cross_out, deep_out], axis=-1)# outoutputs = F.sigmoid(self.final_linear(total_x))return outputsif __name__ == '__main__':x = torch.rand(size=(1, 5), dtype=torch.float32)feature_info = [['I1', 'I2'],  # 连续性特征['C1', 'C2', 'C3'],  # 离散型特征{'C1': 20,'C2': 20,'C3': 20}]# 建立模型hidden_units = [128, 64, 32]net = DCN(feature_info, hidden_units,layer_num=2)print(net)print(net(x))
DCN((embed_layers): ModuleDict((embed_C1): Embedding(20, 8)(embed_C2): Embedding(20, 8)(embed_C3): Embedding(20, 8))(cross_network): CrossNetwork((cross_weights): ParameterList((0): Parameter containing: [torch.FloatTensor of size 26x1](1): Parameter containing: [torch.FloatTensor of size 26x1])(cross_bias): ParameterList((0): Parameter containing: [torch.FloatTensor of size 26x1](1): Parameter containing: [torch.FloatTensor of size 26x1]))(dnn_network): Dnn((dnn_network): ModuleList((0): Linear(in_features=26, out_features=128, bias=True)(1): Linear(in_features=128, out_features=64, bias=True)(2): Linear(in_features=64, out_features=32, bias=True))(dropout): Dropout(p=0.0, inplace=False))(final_linear): Linear(in_features=58, out_features=1, bias=True)
)
tensor([[0.9349]], grad_fn=<SigmoidBackward0>)

2 Deep&Crossing模型在Criteo数据集的应用

数据的预处理可以参考

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用_undo_try的博客-CSDN博客

2.1 准备训练数据

import pandas as pdimport torch
from torch.utils.data import TensorDataset, Dataset, DataLoaderimport torch.nn as nn
from sklearn.metrics import auc, roc_auc_score, roc_curveimport warnings
warnings.filterwarnings('ignore')
# 封装为函数
def prepared_data(file_path):# 读入训练集,验证集和测试集train_set = pd.read_csv(file_path + 'train_set.csv')val_set = pd.read_csv(file_path + 'val_set.csv')test_set = pd.read_csv(file_path + 'test.csv')# 这里需要把特征分成数值型和离散型# 因为后面的模型里面离散型的特征需要embedding, 而数值型的特征直接进入了stacking层, 处理方式会不一样data_df = pd.concat((train_set, val_set, test_set))# 数值型特征直接放入stacking层dense_features = ['I' + str(i) for i in range(1, 14)]# 离散型特征需要需要进行embedding处理sparse_features = ['C' + str(i) for i in range(1, 27)]# 定义一个稀疏特征的embedding映射, 字典{key: value},# key表示每个稀疏特征, value表示数据集data_df对应列的不同取值个数, 作为embedding输入维度sparse_feas_map = {}for key in sparse_features:sparse_feas_map[key] = data_df[key].nunique()feature_info = [dense_features, sparse_features, sparse_feas_map]  # 这里把特征信息进行封装, 建立模型的时候作为参数传入# 把数据构建成数据管道dl_train_dataset = TensorDataset(# 特征信息torch.tensor(train_set.drop(columns='Label').values).float(),# 标签信息torch.tensor(train_set['Label'].values).float())dl_val_dataset = TensorDataset(# 特征信息torch.tensor(val_set.drop(columns='Label').values).float(),# 标签信息torch.tensor(val_set['Label'].values).float())dl_train = DataLoader(dl_train_dataset, shuffle=True, batch_size=16)dl_vaild = DataLoader(dl_val_dataset, shuffle=True, batch_size=16)return feature_info,dl_train,dl_vaild,test_set
file_path = './preprocessed_data/'feature_info,dl_train,dl_vaild,test_set = prepared_data(file_path)

2.2 建立Deep&Crossing模型

from _01_DeepAndCrossing import DCN# 建立模型
hidden_units = [128, 64, 32]net = DCN(feature_info, hidden_units,layer_num=len(hidden_units))
# 测试一下模型
for feature, label in iter(dl_train):out = net(feature)print(feature.shape)print(out.shape)print(out)break

2.3 模型的训练

from AnimatorClass import Animator
from TimerClass import Timer# 模型的相关设置
def metric_func(y_pred, y_true):pred = y_pred.datay = y_true.datareturn roc_auc_score(y, pred)def try_gpu(i=0):if torch.cuda.device_count() >= i + 1:return torch.device(f'cuda:{i}')return torch.device('cpu')def train_ch(net, dl_train, dl_vaild, num_epochs, lr, device):"""⽤GPU训练模型"""print('training on', device)net.to(device)# 二值交叉熵损失loss_func = nn.BCELoss()optimizer = torch.optim.Adam(params=net.parameters(), lr=lr)animator = Animator(xlabel='epoch', xlim=[1, num_epochs],legend=['train loss', 'train auc', 'val loss', 'val auc'],figsize=(8.0, 6.0))timer, num_batches = Timer(), len(dl_train)log_step_freq = 10for epoch in range(1, num_epochs + 1):# 训练阶段net.train()loss_sum = 0.0metric_sum = 0.0for step, (features, labels) in enumerate(dl_train, 1):timer.start()# 梯度清零optimizer.zero_grad()# 正向传播predictions = net(features)loss = loss_func(predictions, labels.unsqueeze(1) )try:          # 这里就是如果当前批次里面的y只有一个类别, 跳过去metric = metric_func(predictions, labels)except ValueError:pass# 反向传播求梯度loss.backward()optimizer.step()timer.stop()# 打印batch级别日志loss_sum += loss.item()metric_sum += metric.item()if step % log_step_freq == 0:animator.add(epoch + step / num_batches,(loss_sum/step, metric_sum/step, None, None))# 验证阶段net.eval()val_loss_sum = 0.0val_metric_sum = 0.0for val_step, (features, labels) in enumerate(dl_vaild, 1):with torch.no_grad():predictions = net(features)val_loss = loss_func(predictions, labels.unsqueeze(1))try:val_metric = metric_func(predictions, labels)except ValueError:passval_loss_sum += val_loss.item()val_metric_sum += val_metric.item()if val_step % log_step_freq == 0:animator.add(epoch + val_step / num_batches, (None,None,val_loss_sum / val_step , val_metric_sum / val_step))print(f'final: loss {loss_sum/len(dl_train):.3f}, auc {metric_sum/len(dl_train):.3f},'f' val loss {val_loss_sum/len(dl_vaild):.3f}, val auc {val_metric_sum/len(dl_vaild):.3f}')print(f'{num_batches * num_epochs / timer.sum():.1f} examples/sec on {str(device)}')
lr, num_epochs = 0.001, 10
train_ch(net, dl_train, dl_vaild, num_epochs, lr, try_gpu())

在这里插入图片描述

2.4 模型的预测

y_pred_probs = net(torch.tensor(test_set.values).float())
y_pred = torch.where(y_pred_probs>0.5,torch.ones_like(y_pred_probs),torch.zeros_like(y_pred_probs)
)
y_pred.data[:10]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/65707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AAC之处理码流分析工具(三十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

Qt各个版本下载及安装教程(离线和非离线安装)

Qt各个版本下载链接&#xff1a; Index of /archive/qthttps://download.qt.io/archive/qt/ 离线安装 &#xff0c;离线安装很无脑&#xff0c;下一步下一步就可以。 我离线下载 半个小时把2G的exe下载下来了

RNN 单元:分析 GRU 方程与 LSTM,以及何时选择 RNN 而不是变压器

一、说明 深度学习往往感觉像是在雪山上找到自己的道路。拥有坚实的原则会让你对做出决定更有信心。我们都去过那里 在上一篇文章中&#xff0c;我们彻底介绍并检查了 LSTM 单元的各个方面。有人可能会争辩说&#xff0c;RNN方法已经过时了&#xff0c;研究它们是没有意义的。的…

CSS实现白天/夜晚模式切换

目录 功能介绍 示例 原理 代码 优化 总结 功能介绍 在网页设计和用户体验中&#xff0c;模式切换功能是一种常见的需求。模式切换可以为用户提供不同的界面外观和布局方案&#xff0c;以适应其个人偏好或特定环境。在这篇博客中&#xff0c;我们将探索如何使用纯CSS实现一…

Debezium的三种部署方式

Debezium如何部署 debezium 有下面三种部署方式,其中最常用的就是 kafka connect。 kafka connect 一般情况下,我们通过 kafka connect 来部署 debezium,kafka connect 是一个框架和运行时: source connectors:像 debezium 这样将记录发送到 kafka 的source connectors…

Linux音频了解

ALPHA I.MX6U 开发板支持音频&#xff0c;板上搭载了音频编解码芯片 WM8960&#xff0c;支持播放以及录音功能&#xff01; 本章将会讨论如下主题内容。 ⚫ Linux 下 ALSA 框架概述&#xff1b; ⚫ alsa-lib 库介绍&#xff1b; ⚫ alsa-lib 库移植&#xff1b; ⚫ alsa-l…

卡特兰数和算法

在组合数学中&#xff0c;卡特兰数是一系列自然数&#xff0c;出现在各种组合计数问题中&#xff0c;通常涉及递归定义的对象。它们以比利时数学家尤金查尔斯卡特兰&#xff08;Eugne Charles Catalan&#xff09;的名字命名。 卡特兰数序列是1, 1, 2, 5, 14, 42......&#xf…

合宙Air724UG LuatOS-Air LVGL API控件--复选框 (Checkbox)

复选框 (Checkbox) 复选框主要是让用户进行一些内容选择&#xff0c;或者同意用户协议。 示例代码 – 复选框回调函数 function event_handler(obj, event) if event lvgl.EVENT_VALUE_CHANGED then print(“State”, lvgl.checkbox_is_checked(obj)) end end – 创建复选框…

STM32 FREERTOS osDelayUntil()异常

问题&#xff1a; 在使用osDelayUntil&#xff08;&#xff09;进行固定延时时发现不起作用&#xff0c;程序不能按照预期的延时进行执行&#xff08;比延时要快&#xff09;。 #define taskMBSysManage_Delay_TIME 1000 TickType_t xLastWakeTime; xLastWakeTime xTaskGe…

githubPage部署Vue项目

github中新建项目 my-web &#xff08;编写vue项目代码&#xff09; myWebOnline(存放Vue打包后的dist包里面的文件) 发布流程 &#xff08;假设my-web项目已经编写完成&#xff09;Vue-cli my-web vue.config.js文件中 const { defineConfig } require(vue/cli-service)…

OpenCV(八):图像二值化

目录 1.固定值二值化 2.自适应阈值二值化 3.Android JNI完整代码 1.固定值二值化 固定阈值二值化是OpenCV中一种简单而常用的图像处理技术&#xff0c;用于将图像转换为二值图像。在固定阈值二值化中&#xff0c;像素值根据一个预定义的阈值进行分类&#xff0c;大于阈值的…

对比Flink、Storm、Spark Streaming 的反压机制

分析&回答 Flink 反压机制 Flink 如何处理反压? Storm 反压机制 Storm反压机制 Storm 在每一个 Bolt 都会有一个监测反压的线程&#xff08;Backpressure Thread&#xff09;&#xff0c;这个线程一但检测到 Bolt 里的接收队列&#xff08;recv queue&#xff09;出现了…

Java异常(Error与Exception)与常见异常处理——第八讲

前言 前面我们讲解了Java的基础语法以及面向对象的思想,相信大家已经基本掌握了Java的基本编程。在之前代码中,我们也看到代码写错了编译器会提示报错,或者编译器没有提示,但是运行的时候报错了,比如前面的数组查询下标超过数组的长度。所以在使用计算机语言进行项目开发的…

简单了解ICMP协议

目录 一、什么是ICMP协议&#xff1f; 二、ICMP如何工作&#xff1f; 三、ICMP报文格式 四、ICMP的作用 五、ICMP的典型应用 5.1 Ping程序 5.2 Tracert(Traceroute)路径追踪程序 一、什么是ICMP协议&#xff1f; ICMP因特网控制报文协议是一个差错报告机制&#xff0c;…

实力认证!OceanBase获“鼎信杯”优秀技术支撑奖

6 月 30 日&#xff0c;2023 “鼎信杯”信息技术发展论坛在京隆重举办第二届“鼎信杯”大赛颁奖典礼。OceanBase 凭借完全自主研发的原生分布式数据库&#xff0c;以及丰富的核心系统国产数据库升级案例&#xff0c;斩获“优秀技术支撑奖”。 论坛上&#xff0c;国内首个基于在…

ThreeJS 模型中内嵌文字

之前有过模型中内嵌html网页&#xff0c;地址☞threeJS 模型中加载html页面_threejs 加载dom元素_小菜花29的博客-CSDN博客 这次是纯粹的在模型中嵌入文本信息&#xff0c;进行简单的文字展示 展示效果图 1. 使用FontLoader文字加载器 引入文本json文件&#xff0c;代码如下…

数据结构(Java实现)-排序

排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&#xff…

2022年下半年系统架构设计师真题(下午带答案)

试题一 (25分) 某电子商务公司拟升级其会员与促销管理系统&#xff0c;向用户提供个性化服务&#xff0c;提高用户的粘性。在项目立项之初&#xff0c;公司领导层一致认为本次升级的主要目标是提升会员管理方式的灵活性&#xff0c;由于当前用户规模不大&#xff0c;业务也相对…

数据结构(Java实现)-Map和Set

搜索树 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左右子树也…

快速上手GIT命令,现学也能登堂入室

系列文章目录 手把手教你安装Git&#xff0c;萌新迈向专业的必备一步 GIT命令只会抄却不理解&#xff1f;看完原理才能事半功倍&#xff01; 快速上手GIT命令&#xff0c;现学也能登堂入室 系列文章目录一、GIT HELP1. 命令文档2. 简要说明 二、配置1. 配置列表2. 增删改查3. …