特征交叉系列:FFM场感知因子分解机原理与实践

从FM到FFM知识准备

在上一节中[特征交叉系列:完全理解FM因子分解机原理和代码实战]介绍了FM算法,FM因子分解机通过在逻辑回归基础上增加所有特征的二阶交互项实现特征的交叉,但是随着特征数的增多二阶交互的数量呈平方级别增长,FM巧妙地给每个特征分配一个低维隐向量,通过隐向量之间的内积点乘来计算二阶交互项的权重,从而使得

  • 减少了二阶权重的参数数量,从 n(n-1)/2 降低到 nk
  • 避免了稀疏数据导致二阶权重无法求解的问题
  • 计算可以优化为训练和预测都是随着特征数量n的线性增长复杂度

而FFM(Field-aware Factorization Machines)场感知因子分解机,基于FM算法,在FM的公式基础上在二阶隐向量相乘的时候对不同的特征域进行了区分,使得不同业务特征的交叉具有个性化。


FFM原理综述

FFM中的field-aware场感知中的场代表特征域,一个特征域就是一个业务特征,而特征域下的特征代表业务特征的取值枚举结果,比如性别是一个特征域,而男,女分别是两个该特征域下的特征。
在明确何为特征域之后直接看FFM的公式

FFM公式

其中只有最右侧二阶特征交互部分和FM略有不一样,内积部分<vi,fj,vj,fi>增加了特征域f,在FM中特征i和特征j的二阶项权重是特征i的隐向量和特征j的隐向量进行内积,而在FFM中,该组二阶权重是特征i的隐向量组中对应于特征j的那个隐向量,和特征j的隐向量组中对应特征i的那个隐向量进行内积,仅此而已,本质上并没有改变FM这种模型的架构模式,FM是FFM的一个特例,及不细分f的作用,全部一视同仁。
在FFM中每个特征会有一组隐向量,组中隐向量的个数和特征域的个数相等,代表虽然是同一个特征,但是对来自于不同特征域的另一个特征都分配了一个单独不一样的隐向量,因此隐向量的维度是n * f * k,如下图所示

FFM隐向量示意图

给定一对特征<A,B>,每个特征分别拿到属于对方特征域的隐向量,而不是像FM使用统一的隐向量,从业务含义上来看,FFM觉得如果一个特征在和其他特征进行交互的时候使用同一个隐向量,隐向量容易做全局妥协,从而不能彻底学习到个性化的特征交互关系,不能指望一个隐向量能适配和所有的特征交叉学习,因此给每种不同特征的交叉单独分配了隐向量,充分发挥出模型的表达能力。


FFM PyTorch实践

FM可以进行计算优化,而FFM不能只能按照原始的公式进行计算,因此FFM的计算复杂度是O(kn方),即完成一个关于特征数量n的嵌套循环,每次循环计算一个长度是k的向量的内积,因此代码实现中会有一个嵌套循环计算再聚合的过程,另外FFM需要让模型知道特征域的数量,因为需要给每一个特征域构造隐向量,隐向量是一个三维的矩阵[f,n,k],分别为特征域数,特征数,隐向量维度。
本次实践的数据集和上一篇特征交叉系列:完全理解FM因子分解机原理和代码实战一致,采用用户的购买记录流水作为训练数据,用户侧特征是年龄,性别,会员年限等离散特征,商品侧特征采用商品的二级类目,产地,品牌三个离散特征,随机构造负样本,一共有10个特征域,全部是离散特征,对于枚举值过多的特征采用hash分箱,得到一共72个特征。
通过PyTorch构造网络结构如下

class Linear(nn.Module):def __init__(self, feat_num):super(Linear, self).__init__()self.embedding = nn.Embedding(feat_num, 1)self.bias = nn.Parameter(torch.zeros(1))def forward(self, x):# [None, 10] => [None, 10, 1] => [None, 1]x_emb = torch.sum(self.embedding(x), dim=1) + self.biasreturn x_embclass Cross(nn.Module):def __init__(self, field_num, feat_num, emb_dim=4):super(Cross, self).__init__()self.field_num = field_numself.feat_num = feat_numself.embedding = nn.ModuleList([nn.Embedding(feat_num, emb_dim) for x in range(field_num)])for embedding in self.embedding:torch.nn.init.xavier_uniform_(embedding.weight.data)def forward(self, x):# 每个特征域下,所有有值的特征的隐向量# [None, 10] => [None, 10, 4] => [...[None, 10, 4]...]x_emb = [self.embedding[i](x) for i in range(self.field_num)]cross_part = []for i in range(self.field_num - 1):for j in range(i + 1, self.field_num):# 对方是j这个特征域时,i对应的隐向量vifj = x_emb[j][:, i]# 对方是i这个特征域时,j对应的隐向量vjfi = x_emb[i][:, j]# [None, 4] * [None, 4] => [None, 1] 内积计算权重,vi*vj=1dot = torch.sum(vifj * vjfi, dim=1, keepdim=True)cross_part.append(dot)cross_part = torch.sum(torch.cat(cross_part, dim=1), dim=1, keepdim=True)return cross_partclass FFM(nn.Module):def __init__(self, field_num, feat_dim, emb_dim=4):super(FFM, self).__init__()self.linear = Linear(feat_dim)self.cross = Cross(field_num, feat_dim, emb_dim)def forward(self, x):linear_part = self.linear(x)  # [None, 1]inter = self.cross(x)  # [None, 1]output = linear_part + inter  # [None, 1]output = torch.sigmoid(output)return output.squeeze(dim=1)

在FFM主类中定义了两个子网络分别是线性层linear和FFM交叉层cross,注意网络的输入x是所有有值(值为1)位置的特征的索引,从FFM的公式来看,值为0的特征对结果没有影响,因此只需要输入有值的特征,再者本例全部是离散分箱变量,所有有值的特征都是1,因此只要输入有值位置的索引即可,一条输入例如

>>> train_data[0]
Out[120]: (tensor([ 2, 10, 14, 18, 34, 39, 47, 51, 58, 64]), tensor(0))

其中x的长度10代表10个特征域,每个域的值是特征的全局位置索引,从0到71,一共72个特征,索引的目的是在模型中通过nn.Embedding映射到对应的隐向量。由于x输入的特殊结构,在FFM的线性层也无法使用nn.Linear直接构造,而是采用nn.Embedding取映射对应的权重。
代码中的核心FFM部分为关于特征域数量的嵌套循环

        for i in range(self.field_num - 1):for j in range(i + 1, self.field_num):# 对方是j这个特征域时,i对应的隐向量vifj = x_emb[j][:, i]# 对方是i这个特征域时,j对应的隐向量vjfi = x_emb[i][:, j]# [None, 4] * [None, 4] => [None, 1] 内积计算权重,vi*vj=1dot = torch.sum(vifj * vjfi, dim=1, keepdim=True)

在计算过程中任意两个特征域之间必定会有一次交叉,且交叉的特征结果vi*vj等于1,原因是样本在某个特征域上必定有一个分箱会有值,所以任意两个特征域的交叉都有意义,由于有值的特征必为1,因此交叉的结果也等于1,因此在代码中只需要计算内积部分即可。
训练代码省略可参考FM的训练代码,FFM训练日志如下

epoch: 6 step: 342 loss: 0.6628243923187256 auc: 0.6277077959960697
epoch: 6 step: 344 loss: 0.6709915399551392 auc: 0.6240200959018551
epoch: 6 step: 346 loss: 0.6623412370681763 auc: 0.6348941361849251
epoch: 6 step: 348 loss: 0.6673620343208313 auc: 0.6245207652466411
epoch: 6 step: 350 loss: 0.6685708165168762 auc: 0.6267709923664122
[evaluation] loss: 0.6645713235650744 auc: 0.6287447944840227
本轮auc比之前最大auc下降:0.0012863341431852415, 当前最大auc: 0.6300311286272079---------early stop!----------

在上一节FM的实践中,验证集的早停最大AUC在0.627左右,而本节FFM的验证集早停在多次训练观察之后维持在0.630左右,略微提升了0.3个百分点,说明FFM这种提高特征交叉隐向量的数量和自由度对模型预测精度有一定的提升。

最后的最后

感谢你们的阅读和喜欢,我收藏了很多技术干货,可以共享给喜欢我文章的朋友们,如果你肯花时间沉下心去学习,它们一定能帮到你。

因为这个行业不同于其他行业,知识体系实在是过于庞大,知识更新也非常快。作为一个普通人,无法全部学完,所以我们在提升技术的时候,首先需要明确一个目标,然后制定好完整的计划,同时找到好的学习方法,这样才能更快的提升自己。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

五、面试资料

我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下。
在这里插入图片描述

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

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

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

相关文章

ArcGIS模型构建器实例:一键拓扑(附模型下载)

ArcGIS模型构建器特别适用于流程固定的工作流。 要素的拓扑处理就非常符合这一特点&#xff0c;一个要素的拓扑过程基本固定&#xff0c;但是每次拓扑都要来一轮操作就很烦&#xff0c;这正是模型构建器的用武之地。 下面以ArcGIS Pro为例介绍在模型构建器中的整个拓扑流程&a…

CPU 使用率过高问题排查

文章目录 CPU 使用率过高问题排查1. CPU使用率过高常见问题2. 压力测试2.1 stress安装参数说明测试示例 2.2 stress-ng安装参数说明测试示例 3. 问题排查3.1 使用 top 命令3.2 使用 ps 命令3.3 使用 perf top3.4 vmstat 命令常用信息内存信息磁盘信息 CPU 使用率过高问题排查 …

第一篇 逻辑门(与门、或门、非门、异或门)

一、实验目的 了解DE1-SOC开发板一些外设。 掌握常用组合逻辑门电路的基本原理。 学习Verilog HDL的基本语法。 学习使用ModelSim工具对设计的电路进行仿真&#xff0c;包括编写Testbench仿真代码&#xff0c;以及ModelSim工具的使用。 熟悉使用Quartus软件从创建Quartus工…

算法金 | Python 中有没有所谓的 main 函数?为什么?

​大侠幸会&#xff0c;在下全网同名[算法金] 0 基础转 AI 上岸&#xff0c;多个算法赛 Top [日更万日&#xff0c;让更多人享受智能乐趣] 定义和背景 在讨论Python为何没有像C或Java那样的明确的main函数之前&#xff0c;让我们先理解一下什么是main函数以及它在其他编程语言…

javaweb——js

JavaScript是一种网页脚本语言。JavaScript代码可以很容易的嵌入到HTML页面中。 js引入 JavaScript嵌入到HTML页面中 <body><script>alert("Hello JS")</script> </body>再HTML页面中插入外部脚本JavaScript <body><script src&…

GIS数据快捷共享发布工具使用时注意事项

我们所有工具软件下载解压后&#xff0c;不要放在C盘或桌面&#xff0c;这样会产生权限冲突问题问题&#xff0c;这是WINDOWS的安全保护&#xff0c;大家要注意&#xff01;也不要让解压目录嵌套太深&#xff0c;Windows目录长度识别是有一定限制的!如果可以&#xff0c;最好是…

微收付系统让客户有钱花,让商家有钱赚!

微收付系统让客户有钱花&#xff0c;让商家有钱赚&#xff01; 作者按&#xff1a;随着那场呼啸全球的疫情&#xff0c;谜一样的消失&#xff01;给全球经济带来了沉重的打击&#xff0c;经济不振和战争笼罩着世界每一个角落&#xff0c;实体店面临着收款难&#xff0c;有钱人花…

C语言 数组——数组的其他应用之筛法求素数

目录 数组的其他应用 求100以内的所有素数 筛法求100以内的所有素数 自顶向下、逐步求精设计算法 数组的其他应用 求100以内的所有素数 筛法求100以内的所有素数 自顶向下、逐步求精设计算法 step 1&#xff1a;设计总体算法  初始化数组a&#xff0c;使a[2]2, a[3]3,..…

Flink系列六:Flink SQl 之常用的连接器(Connector)

一、动态表 & 连续查询(Continuous Query) 1、动态表&#xff08;Dynamic Tables&#xff09; 当流中有新数据到来&#xff0c;初始的表中会插入一行&#xff1b;而基于这个表定义的SQL查询&#xff0c;就应该在之前的基础上更新结果。这样得到的表就会不断地动态变化&…

SQL Developer 导入CSV数据

之前已经写过一篇文章&#xff1a;将文本文件导入Oracle数据库的简便方法&#xff1a;SQL Developer 本文是类似的&#xff0c;只不过使用的是官方提供的 CSV文件&#xff0c;确实是标准的CSV&#xff08;comma separated values&#xff09;。 COL1,COL2,COL3 "e40a9db…

2024年文艺文化与社会发展国际会议(ICLCSD 2024)

2024年文艺文化与社会发展国际会议 2024 International Conference on Literature, Culture and Social Development 【1】会议简介 2024年文艺文化与社会发展国际会议是一场汇集全球文艺文化和社会科学领域精英的盛会。本次会议以“文艺文化与社会发展”为主题&#xff0c;旨在…

[Java基础揉碎]坦克大战 java事件处理机制

目录 坦克大战游戏演示 ​编辑 为什么要写这个项目 java绘图坐标体系 java绘图技术 Graphics的常用方法 // 画直线 ​编辑 // 画矩形边框 // 画填充矩形 // 画填充椭圆 // 获取图片资源 // 写字 绘出坦克 新建一个tankgame包, 新建一个类Tank, 里面包含横…

01_初识微服务

文章目录 一、微服务概述1.1 什么是微服务1.2 对比微服务架构与单体架构1.3 微服务设计原则1.4 微服务开发框架1.5 简单理解分布式部署与集群部署 二、微服务的核心概念2.1 服务注册与发现2.2 微服调用&#xff08;通信&#xff09;2.3 服务网关2.4 服务容错2.5 链路追踪参考链…

CSAPP Lab04——Cache Lab大师手笔,匠心制作

浮沉浪似人潮 哪会没有思念 你我伤心到 讲不出再见 ——讲不出再见 完整代码见&#xff1a;CSAPP/cachelab-handout at main SnowLegend-star/CSAPP (github.com) Part A: Cache Simulator 这个lab描述背大锅&#xff0c;开始我是真有点没看懂题目的描述。特别是“M 20,1”“…

构建大型语言模型(LLM)产品的实战指南

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

基于多尺度相关小波分解的单幅图像去雾和去噪方法(MATLAB)

小波变换具有优美的数学背景和强大的多分辨率分析能力。它集成和发展了短时傅里叶变换的思想并克服了其时间窗口不可变的缺点。小波变换通过使用具有局部感受野和多尺度的基函数。形成了同时具有局部和全局性质的信号表征。与DCT等全局变换相比&#xff0c;小波变换可以防止局部…

Java面试八股之Executors可以创建哪几种类型的线程池

Executors可以创建哪几种类型的线程池 newSingleThreadExecutor&#xff1a; 创建一个单线程的线程池&#xff0c;此线程池确保所有的任务都在同一个线程中按顺序执行。适用于需要保证任务顺序执行&#xff0c;或者在单线程中运行的任务。 newFixedThreadPool&#xff1a; …

每日两题 / 34. 在排序数组中查找元素的第一个和最后一个位置 33. 搜索旋转排序数组(LeetCode热题100)

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 根据二分函数&#xff0c;得到>target和<target的两个&#xff0c;分别是答案的l和r class Solution { public:vector<int> searchRange(vector<int>& nums,…

Python | Leetcode Python题解之第130题被围绕的区域

题目&#xff1a; 题解&#xff1a; class Solution:def solve(self, board: List[List[str]]) -> None:if not board:returnn, m len(board), len(board[0])que collections.deque()for i in range(n):if board[i][0] "O":que.append((i, 0))board[i][0] &q…

github有趣项目:Verilog在线仿真( DigitalJS+edaplayground)

DigitalJS https://github.com/tilk/digitaljs这个项目是一个用Javascript实现的数字电路模拟器。 它旨在模拟由硬件设计工具合成的电路 像 Yosys&#xff08;这里是 Github 存储库&#xff09;&#xff0c;它有一个配套项目 yosys2digitaljs&#xff0c;它可以转换 Yosys 将文…