推荐算法实战项目:FNN 原理以及案例实战(附完整 Python 代码)

2023-11-12

本文要介绍的是FNN模型,出自于张伟楠老师于2016年发表的论文《Deep Learning over Multi-field Categorical Data》

论文提出了两种深度学习模型,分别叫做FNN(Factorisation Machine supported Neural Network)和SNN(Sampling-based Neural Network),本文只介绍FNN模型。

其实学习FNN模型之前,强烈建议先学习FM模型,因为FNN模型其实可以看做是由一个FM模型和一个MLP组成的。

FM的引入是为了高效地将输入稀疏特征映射到稠密特征,从而加快FNN模型的训练。

介绍

用户行为预测在许多网页级应用上发挥着重要的作用,比如网页搜索、推荐系统、赞助搜索、以及广告展示等。

在在线广告中,举个例子,对目标用户群体的定位能力是区别于传统线下广告的关键优势。所有的定位技术,都依赖于预测是否特定的用户认为这个广告是相关的,给出用户在特定的场景中点击的概率。

目前大部分的CTR预测都是线性模型,如逻辑回归,朴素贝叶斯,FTRL逻辑回归和贝叶斯逻辑回归等。所有的这些都是基于使用one-hot编码的大量稀疏特征。线性模型简单,有效,但是性能偏差,因为无法学习到特征之间的相互关系。

非线性模型可以通过特征间的组合提高模型的能力。如FMs,将二值化的特征映射成连续的低维空间,通过内积获取特征间的相互关系。GBDT梯度提升树,通过树的构建过程,自动的学习特征的组合。

然而,这些方法并不能利用所有可能的组合。此外,许多模型仍然需要依靠手工进行特征工程,来决定如何进行特征的组合。另一个问题是,已有的CTR模型在对复杂数据间的潜在的模式上的表达能力是非常有限的。所以,它们的泛化能力是非常受限的。

​深度学习在CV和NLP上取得了很大的成功,在非监督的训练中,神经网络可以从原始的特征中学习到高维的特征表示,这个能力也可以用在CTR上。在CTR中,大部分的输入特征是来自各个领域的,而且是离散的类别特征。比如用户所在的城市信息(London,Paris,Beijing),设备类型(PC,Mobile),广告类别(Sports, Electronics)等等,并且特征之间的相互依赖是未知的。

因此,我们抱着极大地兴趣想了解一下,深度学习方法是如何在大规模的多特征域的离散类别数据上通过学习特征表示来提高CTR任务的估计准确度的。然而,大规模的输入特征空间需要调整大量的参数,这毫无疑问在计算上是非常昂贵的。与物理世界的图像或者音频数据不同,在推荐系统或者在线搜索等系统中,输入数据都是及其稀疏的。

举个例子,假如我们有100万个二进制输入特征,以及100个隐层,那么这大概需要1亿个连接才能构建第一层神经网络。

模型

先直接给出论文中的FNN模型图,如下:

FNN模型图

上图的右侧已经标明了每一层的含义,下面从模型自顶向下的角度详细解释一下。

  • 输出层
    模型的输出是一个实数作为预测的CTR,即特定用户在指定上下文的条件下点击给定广告的概率。

这里给出FM的方程:

为了进一步展示FM与FNN的关系,这里再补上一张图加以说明:

FM和FNN Embedding层各参数的对应关系

使用预训练的FM来初始化FNN模型的第一层参数可以有效地学习特征表示,并且绕开了高维二值输入带来的计算复杂度高问题。​更进一步,隐含层的权重(除了FM层)可以通过预训练的RBM来进行初始化。FM的权重可以通过SGD来进行更新,我们只需要更新那些不为0的单元,这样可以减少大量的计算。通过预训练FM层和其他的层进行初始化之后,再通过监督学习的方法进行微调,使用交叉熵的损失函数:

使用反向传播的链式法则,FNN模型(包含FM)的权重可以被高效地更新,举个例子,FM层的权重可以通过下述公式来进行更新:


FNN模型分析

FNN模型的特点:

  1. 采用FM预训练得到的隐含层及其权重作为神经网络的第一层的初始值,之后再不断堆叠全连接层,最终输出预测的点击率。
  2. 可以将FNN理解成一种特殊的embedding+MLP,其要求第一层嵌入后的各特征域特征维度一致,并且嵌入权重的初始化是FM预训练好的。
  3. 这不是一个端到端的训练过程,有贪心训练的思路。而且如果不考虑预训练过程,模型网络结构也没有考虑低阶特征组合。

FNN模型的优缺点:

  • 优点
    1.引入DNN对特征进行更高阶组合,减少特征工程,能在一定程度上增强FM的学习能力,这种尝试为后续深度推荐模型的发展提供了新的思路。

  • 缺点
    1.两阶段训练模式,在应用过程中不方便,且模型能力受限于FM表征能力的上限。
    2.FNN专注于高阶组合特征,但是却没有对低阶特征进行建模。

完整源码&技术交流

技术要学会分享、交流,不建议闭门造车。一个人走的很快、一堆人可以走的更远。

文章中的完整源码、资料、数据、技术交流提升, 均可加知识星球交流群获取,群友已超过2000人,添加时切记的备注方式为:来源+兴趣方向,方便找到志同道合的朋友。

方式①、添加微信号:mlc2060,备注:来自 获取推荐资料
方式②、微信搜索公众号:机器学习社区,后台回复:推荐资料

部分代码

模型部分代码:

import torch
import torch.nn as nn
from BaseModel.basemodel import BaseModel

class FNN(BaseModel):
    def __init__(self, config, dense_features_cols, sparse_features_cols):
        super(FNN, self).__init__(config)
        # 稠密和稀疏特征的数量
        self.num_dense_feature = dense_features_cols.__len__()
        self.num_sparse_feature = sparse_features_cols.__len__()

        # FNN的线性部分,对应 ∑WiXi
        self.embedding_layers_1 = nn.ModuleList([
            nn.Embedding(num_embeddings=feat_dim, embedding_dim=1)
                for feat_dim in sparse_features_cols
        ])

        # FNN的Interaction部分,对应∑∑<Vi,Vj>XiXj
        self.embedding_layers_2 = nn.ModuleList([
            nn.Embedding(num_embeddings=feat_dim, embedding_dim=config['embed_dim'])
                for feat_dim in sparse_features_cols
        ])

        # FNN的DNN部分
        self.hidden_layers = [self.num_dense_feature + self.num_sparse_feature*(config['embed_dim']+1)] + config['dnn_hidden_units']
        self.dnn_layers = nn.ModuleList([
            nn.Linear(in_features=layer[0], out_features=layer[1])\
                for layer in list(zip(self.hidden_layers[:-1], self.hidden_layers[1:]))
        ])
        self.dnn_linear = nn.Linear(self.hidden_layers[-1], 1, bias=False)

    def forward(self, x):
        # 先区分出稀疏特征和稠密特征,这里是按照列来划分的,即所有的行都要进行筛选
        dense_input, sparse_inputs = x[:, :self.num_dense_feature], x[:, self.num_dense_feature:]
        sparse_inputs = sparse_inputs.long()

        # 求出线性部分
        linear_logit = [self.embedding_layers_1[i](sparse_inputs[:, i]) for i in range(sparse_inputs.shape[1])]
        linear_logit = torch.cat(linear_logit, axis=-1)

        # 求出稀疏特征的embedding向量
        sparse_embeds = [self.embedding_layers_2[i](sparse_inputs[:, i]) for i in range(sparse_inputs.shape[1])]
        sparse_embeds = torch.cat(sparse_embeds, axis=-1)

        dnn_input = torch.cat((dense_input, linear_logit, sparse_embeds), dim=-1)

        # DNN 层
        dnn_output = dnn_input
        for dnn in self.dnn_layers:
            dnn_output = dnn(dnn_output)
            dnn_output = torch.tanh(dnn_output)
        dnn_logit = self.dnn_linear(dnn_output)

        # Final
        y_pred = torch.sigmoid(dnn_logit)

        return y_pred

注意这里实现的FNN模型跟论文中的并不完全一样。论文中描述的FNN模型的第一层的参数是通过预训练好的FM来初始化的,因此模型需要分为两个阶段来训练。这里为了简化,直接使用了两个Embedding层来代替FM中应该学习得到的参数,使得网络可以以端到端的方式训练,简化代码实现。

测试部分代码:

import torch
from FNN.network import FNN
import torch.utils.data as Data
from DeepCrossing.trainer import Trainer
from Utils.criteo_loader import getTestData, getTrainData

fnn_config = \
{
    'embed_dim': 8, # 用于控制稀疏特征经过Embedding层后的稠密特征大小
    'dnn_hidden_units': [128, 128],
    'num_epoch': 150,
    'batch_size': 64,
    'lr': 1e-3,
    'l2_regularization': 1e-4,
    'device_id': 0,
    'use_cuda': False,
    'train_file': '../Data/criteo/processed_data/train_set.csv',
    'fea_file': '../Data/criteo/processed_data/fea_col.npy',
    'validate_file': '../Data/criteo/processed_data/val_set.csv',
    'test_file': '../Data/criteo/processed_data/test_set.csv',
    'model_name': '../TrainedModels/FNN.model'
}

if __name__ == "__main__":
    ####################################################################################
    # FNN 模型
    ####################################################################################
    training_data, training_label, dense_features_col, sparse_features_col = getTrainData(fnn_config['train_file'], fnn_config['fea_file'])
    train_dataset = Data.TensorDataset(torch.tensor(training_data).float(), torch.tensor(training_label).float())

    test_data = getTestData(fnn_config['test_file'])
    test_dataset = Data.TensorDataset(torch.tensor(test_data).float())

    fnn = FNN(fnn_config, dense_features_cols=dense_features_col, sparse_features_cols=sparse_features_col)
    print(fnn)
    ####################################################################################
    # 模型训练阶段
    ####################################################################################
    # # 实例化模型训练器
    trainer = Trainer(model=fnn, config=fnn_config)
    # 训练
    trainer.train(train_dataset)
    # 保存模型
    trainer.save()

    ####################################################################################
    # 模型测试阶段
    ####################################################################################
    fnn.eval()
    if fnn_config['use_cuda']:
        fnn.loadModel(map_location=lambda storage, loc: storage.cuda(fnn_config['device_id']))
        fnn = fnn.cuda()
    else:
        fnn.loadModel(map_location=torch.device('cpu'))

    y_pred_probs = fnn(torch.tensor(test_data).float())
    y_pred = torch.where(y_pred_probs>0.5, torch.ones_like(y_pred_probs), torch.zeros_like(y_pred_probs))
    print("Test Data CTR Predict...\n ", y_pred.view(-1))

在criteo数据集上的部分测试结果,输出的是每一个测试数据的点击率预估:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

推荐算法实战项目:FNN 原理以及案例实战(附完整 Python 代码) 的相关文章

  • 从 Django 调用 Postgres SQL 存储过程

    我正在开发一个带有 Postgresql 数据库的 Django 项目 我编写了一个可以在 Postgres 上完美运行的存储过程 现在我想从 Django 1 5 调用该存储过程 我已经编写了代码 但它提示错误 CREATE FUNCTI
  • 使用 Python 创建 MIDI

    本质上 我正在尝试从头开始创建 MIDI 并将它们放到网上 我对不同的语言持开放态度 但更喜欢使用Python 两种语言之一 如果这有什么区别的话 并且想知道我应该使用哪个库 提前致谢 看起来这就是您正在寻找的 适用于 Python 的简单
  • TensorFlow:带有轴选项的 bincount

    在 TensorFlow 中 我可以使用 tf bincount 获取数组中每个元素的计数 x tf placeholder tf int32 None freq tf bincount x tf Session run freq feed
  • NumPy linalg.eig

    我有这个烦人的问题 但我还没有弄清楚 我有一个矩阵 我想找到特征向量 所以我写 val vec np linalg eig mymatrix 然后我得到了 vec 我的问题是 当我小组中的其他人对相同的矩阵 mymatrix 做同样的事情时
  • 字符串中的注释和注释中的字符串

    我正在尝试使用 Python 和 Regex 计算 C 代码中包含的注释中的字符数 但没有成功 我可以先删除字符串以删除字符串中的注释 但这也会删除注释中的字符串 结果会很糟糕 是否有机会通过使用正则表达式来询问不匹配注释中的字符串 反之亦
  • PyTorch 给出 cuda 运行时错误

    我对我的代码做了一些小小的修改 以便它不使用 DataParallel and DistributedDataParallel 代码如下 import argparse import os import shutil import time
  • ImportError:运行 jupyter Notebook 时没有名为 IPython.paths 的模块?

    我通过以下方式安装了 jupyter usr local opt python bin python2 7 m pip install jupyter 这将安装 ipython 版本 4 1 2 但是 当我运行 jupyter Notebo
  • 如何使用 javascript/jquery/AJAX 调用 Django REST API?

    我想使用 Javascript jQuery AJAX 在前端调用 Django Rest API 请求方法是 POST 但当我看到 API 调用它的调用 OPTIONS 方法时 所以 我开始了解access control allow o
  • 对使用 importlib.util 导入的对象进行酸洗

    我在使用Python的pickle时遇到了一个问题 我需要通过将文件路径提供给 importlib util 来加载一些 Python 模块 如下所示 import importlib util spec importlib util sp
  • 迭代列表的奇怪速度差异

    我创建了两个重复两个不同值的长列表 在第一个列表中 值交替出现 在第二个列表中 一个值出现在另一个值之前 a1 object object 10 6 a2 a1 2 a1 1 2 然后我迭代它们 不对它们执行任何操作 for in a1 p
  • Werkzeug 中的线程和本地代理。用法

    首先 我想确保我正确理解了功能的分配 分配本地代理功能以通过线程内的模块 包 共享变量 对象 我对吗 其次 用法对我来说仍然不清楚 也许是因为我误解了作业 我用烧瓶 如果我有两个 或更多 模块 A B 我想将对象C从模块A导入到模块B 但我
  • 在 Windows 上使用带有对数刻度的 matplotlib 时出现 Unicode 错误

    我正在使用 python 2 6 和 matplotlib 如果我运行 matplotlib 库页面中提供的示例 histogram demo py 它工作正常 我已经大大简化了这个脚本 import numpy as np import
  • 使用 NLP 进行地址分割

    我目前正在开发一个项目 该项目应识别地址的每个部分 例如来自 str Jack London 121 Corvallis ARAD ap 1603 973130 输出应如下所示 street name Jack London no 121
  • falcon,AttributeError:“API”对象没有属性“create”

    我正在尝试测试我的猎鹰路线 但测试总是失败 而且看起来我把所有事情都做对了 my app py import falcon from resources static import StaticResource api falcon API
  • Python对象初始化性能

    我只是做了一些快速的性能测试 我注意到一般情况下初始化列表比显式初始化列表慢大约四到六倍 这些可能是错误的术语 我不确定这里的行话 例如 gt gt gt import timeit gt gt gt print timeit timeit
  • PIL - 需要抖动,但限制调色板会导致问题

    我是 Python 新手 正在尝试使用 PIL 来执行 Arduino 项目所需的解析任务 这个问题涉及到Image convert 方法以及调色板 抖动等选项 我有一些硬件能够一次仅显示 16 种颜色的图像 但它们可以指定为 RGB 三元
  • 字符串列表,获取n个元素的公共子串,Python

    我的问题可能类似于this https stackoverflow com questions 37514193 count the number of occurrences of n length not given string in
  • OSX 上的 locale.getlocale() 问题

    我需要获取系统区域设置来执行许多操作 最终我想使用 gettext 翻译我的应用程序 我打算在 Linux 和 OSX 上分发它 但我在 OSX Snow Leopard 上遇到了问题 python Python 2 5 2 r252 60
  • 导入错误:无法导入名称“时间戳”

    我使用以下代码在 python 3 6 3 中成功安装了 ggplot conda install c conda forge ggplot 但是当我使用下面的代码将其导入笔记本时 出现错误 from ggplot import Impor
  • 操作错误:(sqlite3.OperationalError) SQL 变量太多,同时将 SQL 与数据帧一起使用

    我有一个熊猫数据框 如下所示 activity User Id 0 VIEWED MOVIE 158d292ec18a49 1 VIEWED MOVIE 158d292ec18a49 2 VIEWED MOVIE 158d292ec18a4

随机推荐

  • 等待一秒lua

    等待1秒 threadpool wait 1 等待1秒 threadpool wait 1 lua 等待1秒 threadpool wait 1
  • 嵌入式学习之STM32实现OLED

    嵌入式学习之STM32实现OLED 一 实验要求 二 SPI介绍 三 OLED介绍 四 实验过程 1 代码编写 实验结果演示 一 实验要求 理解OLED屏显和汉字点阵编码原理 使用STM32F103的SPI或IIC接口实现以下功能 显示自己
  • VS2019之WebAPI的创建与调用方法

    一 使用VS2019创建WebAPI 使用ValuesController cs来编写WebAPI的方法 重要 WebApiConfig cs的配置代码 注意访问方式 WebApi在访问时在主机名后加 api 然后再加控件器 方法 参数 如
  • R、Rstudio和Rtools的安装(以4.3.0版本为例)

    1 R的安装 下载地址 The Comprehensive R Archive Network tsinghua edu cn 这里下载的是4 3 0版本 选择Windows版本 下载后选择路径进行安装 默认选项即可 2 Rtools的安装
  • LabVIEW2018安装与使用

    安装 https blog csdn net m0 38106923 article details 88654150 每一个labview程序叫做一个vi 文件 新建vi 前面板 放一些控件 eg 输入控件 输出控件 显示控件 右键 选择
  • HttpMessageNotReadableException: JSON parse error: Unexpected character (‘“‘ (code 34)): was expecti

    作者 我弟 接口请求报错 2022 07 16 16 41 01 579 WARN 18820 nio 9002 exec 3 w s m s DefaultHandlerExceptionResolver Resolved org spr
  • Redis数据库安装

    1 redis安装包下载 redis安装包下载地址 https github com MicrosoftArchive redis releases windows下载msi安装包即可 2 安装redis 下载完成后 点击进行安装 按默认配
  • IT项目管理 — 作业7

    题目 Tony Prince 和他的团队正在做一个娱乐和健康方面的项目 他们被要求修改现有的成本估计 以便能有一个可靠的评价项目绩效的基线 进度和成本目标是在 6 个月内在 200 000 美元的预算下完成项目 准备和打印一页类似于图 7
  • 有什么好用的Angular插件推荐吗?

    10 个最受欢迎的 Angular 库 一 Angular Material Angular Material 是由 Google 开发的一款工具 是适合与 Angular 框架一起使用的 UI UX 组件库 Angular Materia
  • 实现DNS主从复制、子域、转发、智能DNS

    主从复制 前提准备 关闭SElinux 关闭防火墙 时间同步 环境说明 Centos7 ip地址 dns master 10 0 0 100 dns slave 10 0 0 103 web 10 0 0 101 目的 搭建DNS主从服务器
  • 计算机原理-结构组成

    cpu 中央处理器 程序控制 操作控制 时间控制 数据处理 运算器 算数逻辑单元ALU 逻辑运行 累加计算器AC 为alu提供工作区 数据缓存寄存器 DR 暂存指令和数据 状态条件寄存器PSW 保存指令条件码 控制器 程序计数器PC 指令计
  • python华为OD机试-进制转换-(5)

    题目5 题目描述 写出一个程序 接受一个十六进制的数 输出该数值的十进制表示 输入描述 输入一个十六进制的数值字符串 注意 一个用例会同时有多组输入数据 请参考帖子https www nowcoder com discuss 276处理多组
  • Matlab中的画图函数

    目录 一 二维曲线和图形 1 二维图像基本命令plot 1 曲线线型 颜色和标记点类型 2 设置曲线线宽 标记点大小 标记点边框颜色和标记点填充颜色等 3 坐标轴设置 4 坐标轴刻度设置 5 图例 6 更多的设置 二 图形的控制与表现 1
  • spring-MVC__spring__hibernate整合值hibernate的配置文件 (hibernate.cfg.xml)

  • QT-样式表

    Qt样式表是一个可以自定义部件外观的十分强大的机制 除了那些能够通过子类化QStyle更改的外观 其余的都可以使用Qt样式表来美化 Qt样式表的概念 术语和语法都受到了HTML的层叠样式表 Cascading Style Sheets CS
  • Ubuntu使用darknet实现YOLOv4-tiny预训练模型测试+训练自己的数据集+评估自己的模型

    文章目录 1 使用YOLOv4 tiny预训练模型 2 训练自己的数据集 2 1 建立yolov4 tiny数据格式 2 2 开始训练 2 3 多GPU训练 3 评估自己的模型 参考博客 YOLOv4 tiny的原理本文不做讲解 只有应用方
  • 黑马程序员SSM-Spring学习笔记

    学完Spring之后是SpringMVC 文章目录 前言 一 注解开发 1 1 注解开发定义bean 1 2纯注解开发 1 3bean作用范围 1 4依赖注入 自动装配 1 5 第三方bean管理 1 6 总结 二 Spring整合MyBa
  • qt槽函数如何传递多个参数_Qt 信号槽如何传递参数(或带参数的信号槽)

    标签 信号槽如何传递参数 或带参数的信号槽 利用Qt进行程序开发时 有时需要信号槽来完成参数传递 带参数的信号槽在使用时 有几点需要注意的地方 下面结合实例进行介绍 第一点 当信号与槽函数的参数数量相同时 它们参数类型要完全一致 signa
  • LeetCode 27.移除元素

    文章目录 题目分析 解题思路 思路1 暴力求解 遍历 接口源码 思路2 空间换时间 接口源码 思路3 双指针 快慢指针 接口源码 题目链接 LeetCode 27 移除元素 题目分析 给你一个数组 nums 和一个值 val 你需要 原地
  • 推荐算法实战项目:FNN 原理以及案例实战(附完整 Python 代码)

    本文要介绍的是FNN模型 出自于张伟楠老师于2016年发表的论文 Deep Learning over Multi field Categorical Data 论文提出了两种深度学习模型 分别叫做FNN Factorisation Mac