想象你开了一家餐厅,一面是「点菜老师傅」,他几十年经验,深知番茄配鸡蛋、土豆配牛肉这类两两搭配的经典组合;另一面是「创意主厨」,他脑洞大开,能把七八种食材融合成一道分子料理。两位大师共享同一间厨房、同一只冰箱——这就是 DeepFM 的精髓:让擅长低阶组合的 FM 与擅长高阶创意的 DNN 在同一「厨房」里协作,端到端输出一道完美预测菜:用户到底会不会点这道菜。 CTR 预估(点击率预估)正是推荐系统的核心任务——预测用户会不会点击某个商品或广告。DeepFM 用一个模型同时捕获低阶和高阶特征交互,既不需要人工构造交叉特征,又能端到端联合训练,是当前工业界最实用的深度推荐模型之一。
掌握 DeepFM,你将理解「低阶记忆 + 高阶泛化」如何在一个模型里协同工作,这是推荐系统工程师设计排序模型、提升点击率的核心基本功。
可视化演示
展示DeepFM共享Embedding的FM+DNN联合架构、FM二阶特征交叉的内积计算,以及低阶高阶交互的分工协作。
本节配有交互动效(进入视口后自动加载,约 3KB)。
'+_captions.arch+'
模型总览
你经营一家餐厅,想预测每位食客会不会点某道招牌菜。你请来两位大师:点菜老师傅(FM)经验老到,对「番茄配鸡蛋」「土豆配牛肉」这类两两搭配如数家珍;创意主厨(DNN)则擅长把多种食材层层融合,做出令人惊喜的分子料理。更妙的是,他们共享同一间厨房和同一只冰箱——不搞「各做各的再拼盘」,而是互相协作、一起出菜。这个「同一厨房」的设计,就是 DeepFM 的灵魂。
在推荐系统里,这家餐厅要解决的问题正是 CTR(点击率)预估:给定用户、商品、场景等特征,预测用户点击的概率。传统方法分两条路:FM 擅长二阶特征交互,但对高阶交互无能为力;DNN 能自动学习高阶非线性,却往往忽略了低阶的显式组合。DeepFM 把两者并入一个模型,让 FM 负责低阶(一阶权重 + 二阶交叉),DNN 负责高阶,最后把两路分数相加。
DeepFM 的最终输出用一个简单公式概括:
所以 DeepFM 的哲学很朴素:经验丰富的老师傅与脑洞大开的主厨在同一厨房协作,既不需要人工设计菜谱(交叉特征),又能同时端出低阶与高阶两道「交互菜」。
- FM 部分输出老师傅的经验分,包含全局偏置、一阶权重和两两特征交互
- DNN 部分输出主厨的创意分,把特征 Embedding 拼接后经过多层全连接网络
- σ 函数将两路相加的分数压缩到 0~1 之间,成为可解释的点击概率
FM因子分解
点菜老师傅的经验不是死记硬背「番茄必须配鸡蛋」,而是给每样食材赋予一个「风味档案」。番茄的档案是「酸甜、多汁」,鸡蛋的档案是「蛋香、绵密」,两个档案越匹配,这道经典菜就越受欢迎。这个「风味档案」在数学上就是隐向量,而判断两个食材是否匹配,就看它们的隐向量内积是否够大。
FM(因子分解机)处理的正是这样的场景:推荐系统的输入往往是大规模稀疏的 one-hot 特征——用户 100 万个 ID,只有当前用户那一位是 1。如果直接为每一对特征学习交叉权重 w_ij,绝大多数组合从未在训练集中出现过,权重根本学不出来。FM 的破局之道是:把交叉权重拆成两个隐向量的内积。
FM 的二阶交互部分长这样:
这个设计妙在:即使「某个用户 × 某个商品」从未一起出现,只要用户隐向量和商品隐向量各自被其他样本训练过,就能算出它们的内积——这就是 FM「冷启动」的底气。
- 遍历所有特征对外层 i 从 1 到 n,内层 j 从 i+1 到 n,保证每对只算一次
- 隐向量内积⟨v_i, v_j⟩ 表示第 i 个特征与第 j 个特征的「风味契合度」
- 乘以特征实际值x_i 和 x_j 为 0/1 时表示特征是否存在,连续特征则表示强度
DNN深度网络
创意主厨的做法则完全不同。他不满足于两两搭配,而是把食材先切碎(提取 Embedding),再一层层搅拌、加热、乳化(多层感知机),让看似无关的食材在多次「化学反应」中产生全新风味。这就是 DNN 捕捉高阶特征交互的方式。
在 DeepFM 中,DNN 的输入不是原始 one-hot 向量,而是每个特征域查表得到的 Embedding 向量拼接结果。假设用户域查到 4 维向量,商品域查到 4 维向量,拼接后就是 8 维的「食材碎末」,然后送进多层全连接网络。每经过一层,网络就做一次线性变换加非线性激活,信息不断重组,最终形成高阶交互表达。
DNN 部分的逐层传播公式:
有了这些层层的非线性变换,DNN 就能自动组合「深夜 + 美食 + 健身」这类三阶甚至更高阶的兴趣信号,这是老师傅的单层经验无法企及的。
- 第 l 层输入a⁽ˡ⁾ 是上一层的输出向量,首层是拼接后的 Embedding
- 线性变换权重矩阵 W⁽ˡ⁾ 与输入相乘,加上偏置 b⁽ˡ⁾,相当于一次「食材调味」
- ReLU 激活把负值截断为 0,引入非线性,让网络能表达复杂交互
Wide&Deep对比
你可能听过 Wide&Deep——它像两家餐厅的「拼盘合作」:Wide 餐厅负责提供几道人工设计的固定搭配(比如「晴天 + 冰淇淋」这种规则特征),Deep 餐厅负责做自由创意菜,最后把两道菜拼在一个盘子里端给顾客。问题是,Wide 那几道固定菜需要厨师长(算法工程师)手工研发,费时费力。
DeepFM 则让老师傅(FM)和主厨(DNN)在同一厨房协作。FM 部分自己就能自动挖掘二阶搭配,不需要任何人手工指定「番茄配鸡蛋」,而且 FM 和 DNN 共享 Embedding 层,互相促进,这是拼盘模式的 Wide&Deep 做不到的。
Wide&Deep 的输出公式对照:
正因为 DeepFM 用 FM 替换了 Wide,二阶交叉特征不再依赖人力,模型效率与效果都上了一个台阶。
- Wide 部分对原始特征和人工交叉特征 φ(x) 做线性加权,像点菜谱上的固定套餐
- Deep 部分深层网络最后一层输出 a^(l_f) 再做线性加权,像创意主厨的收尾摆盘
- 拼接求和两路结果相加再过 σ,输出点击概率
特征交互
共享冰箱的秘密在于:老师傅在思考「番茄配鸡蛋」时,主厨可能正在用鸡蛋做一道分子料理的「绑合剂」。双方看到的食材(Embedding)完全相同,一个人对食材的理解进步,另一个人也立刻受益。这正是共享 Embedding 带来的低阶与高阶交互的信息互补。
低阶交互指两个特征之间的显式组合,比如「星期天 + 电影票」,直观、可解释、在少量样本下就能学稳;高阶交互指多个特征经过多层网络融合后的隐式表达,比如「年轻用户 + 晚上十点 + 外卖 App + 小龙虾」,这种组合在原始样本中极稀疏,必须靠 DNN 泛化出来。FM 捕捉前者,DNN 捕捉后者,而共享 Embedding 让两者使用同一套特征表示,谁学到了新知识都会传递给另一方。
这种互补关系可以这样理解:
这种「一套特征两路复用」的设计,让 DeepFM 既能记住稳定的规律,又能探索新奇的偏好,在推荐场景中尤其珍贵。
- FM 低阶项显式计算所有两两组合,类似老师傅的经典菜谱,稳定可靠
- DNN 高阶项隐式学习复杂组合,像主厨的即兴创意,覆盖长尾需求
- 共享基础两者使用相同的 Embedding 查表结果,保证信息一致性
模型训练
店长(损失函数)要用一套统一的「满意评分」来同时考核两位厨师:食客真的点了这道菜,满分;点了别家菜,零分。所有厨师——不管是老师傅还是主创——都要根据这份评分调整自己的手法,谁对结果贡献大,谁就改得多。这套奖惩机制就是反向传播。
DeepFM 是一个端到端模型,FM 与 DNN 的所有参数(包括共享 Embedding)一起参与训练。由于 CTR 预估是二分类问题,最常用的损失是交叉熵(LogLoss):
训练时,梯度会沿两条路径同时回传,老师傅的经典菜谱(FM 参数)和主厨的创新配方(DNN 参数)同步改进,共享冰箱里的食材(Embedding)也在每一次迭代中被两家共同打磨。
- 遍历 N 个样本每个训练样本(用户-商品-行为)都算一次损失
- 正样本项真实点击 y_t=1 时只保留第一项,预测越接近 1 损失越小
- 负样本项真实未点击 y_t=0 时只保留第二项,惩罚把负样本预测为高概率
- 负号与平均让损失为正数并求平均,方便梯度下降优化
应用场景
这家「双厨餐厅」一旦运营成熟,就可以开连锁店了。DeepFM 在工业界遍地开花,凡是需要预测用户会不会点的场景,都有它的身影——信息流里会不会点开文章,广告位上会不会点击商品,搜索结果里会不会点进详情页。
在信息流推荐中,输入通常是「用户 ID + 文章类别 + 阅读时长 + 时间段」等特征。DeepFM 的 FM 部分能快速学到「足球迷 + 体育频道」这种稳定搭配,DNN 部分则能捕捉「深夜 + 美食类 + 健身人群」这种复杂的上下文兴趣,两者融合后 CTR(点击率)预估更准。在广告场景,CTR 预估直接决定广告排序和出价,DeepFM 的精准度直接影响营收。实际部署时,Embedding 表常驻内存,FM 二阶项可写成稀疏格式快速计算,DNN 部分用 TensorRT 或 ONNX 加速推理,单次预估耗时控制在毫秒级。
衡量这类场景效果的标准指标是 AUC:
- 正负样本配对遍历所有正样本 i 和负样本 j
- 比较大小指示函数 I(·) 在正样本预测值大于负样本时为 1
- 求平均除以正负样本总数 N⁺N⁻,得到 0~1 之间的排名指标
AI 应用场景
信息流推荐系统的 CTR 预估
阶段:推荐排序(Ranking)
解决的问题:传统 LR 需要人工构造「用户 × 文章」交叉特征,工程量大且覆盖不了长尾组合。DeepFM 的 FM 部分自动做二阶交叉,DNN 部分挖掘三阶以上的复杂兴趣组合,端到端预测点击概率,无需手工交叉。
具体案例:某新闻 App 在排序层引入 DeepFM,输入「用户 ID、文章 ID、类目、时段、历史点击序列」等特征后,CTR 提升 12%,原本每周手工产出交叉特征报表的团队得以转向更上层的策略优化。
广告竞价排序
阶段:广告排序与出价
解决的问题:广告平台需对每次曝光预估点击率,用于竞价排序。百亿级稀疏特征下,DeepFM 既能用 FM 自动组合「设备 × 广告位」等低阶模式,又能用 DNN 学习「年轻用户 + 深夜 + 美妆广告」的高阶上下文,提升预估精度与广告收入。
具体案例:某广告平台用 DeepFM 替换 LR 后,AUC 提升约 0.02,在相同预算下点击量提升 8%,ECPM 显著改善。
电商搜索排序
阶段:搜索召回与排序
解决的问题:电商搜索的「查询词 × 商品」组合空间巨大,人工交叉不现实。DeepFM 的共享 Embedding 让「保暖」「羽绒服」这类语义相关信息同时被 FM 与 DNN 利用,缓解稀疏性问题。
具体案例:某电商平台将 DeepFM 应用于搜索排序特征层后,发现「猫咪图案」与「宠物用品」这类跨域长尾组合被模型自动学到,长尾搜索转化率提升 9%。
Python 演示
import numpy as np class DeepFM: """简化版 DeepFM:FM 二阶交叉 + DNN 高阶交叉(NumPy 实现)""" def __init__(self, n_fields, n_symbols, k=8, hidden=(16, 8), seed=42): rng = np.random.default_rng(seed) self.n_fields = n_fields # 特征域数量,如 用户、商品、场景 self.n_symbols = n_symbols # 每个域的词表大小(one-hot 维度) self.k = k # Embedding 维度 self.w0 = 0.0 self.w = np.zeros(n_fields * n_symbols) # 一阶权重 self.V = rng.normal(0, 0.01, (n_fields * n_symbols, k)) # 隐向量表 self.offsets = [i * n_symbols for i in range(n_fields)] # 每个域起始索引 dims = [n_fields * k] + list(hidden) self.Ws = [rng.normal(0, 0.1, (dims[i], dims[i + 1])) for i in range(len(hidden))] self.bs = [np.zeros(dims[i + 1]) for i in range(len(hidden))] def _embed(self, x_idx): """把每个域选中的符号索引映射为拼接后的 Embedding 向量""" emb_list = [] for f in range(self.n_fields): idx = self.offsets[f] + x_idx[f] emb_list.append(self.V[idx]) return np.concatenate(emb_list) def fm_part(self, x_idx): """FM 部分:一阶线性 + 二阶两两隐向量内积""" x_flat = np.zeros(self.n_fields * self.n_symbols) for f in range(self.n_fields): x_flat[self.offsets[f] + x_idx[f]] = 1.0 linear = self.w0 + x_flat @ self.w embeds = [self.V[self.offsets[f] + x_idx[f]] for f in range(self.n_fields)] interaction = 0.0 for i in range(self.n_fields): for j in range(i + 1, self.n_fields): interaction += embeds[i] @ embeds[j] return linear + interaction def dnn_part(self, x_idx): """DNN 部分:拼接 Embedding 过多层 ReLU 网络""" a = self._embed(x_idx).reshape(1, -1) for W, b in zip(self.Ws, self.bs): a = np.maximum(0, a @ W + b) return float(a.sum()) def predict(self, x_idx): """两路输出相加,过 Sigmoid 得到点击概率""" z = self.fm_part(x_idx) + self.dnn_part(x_idx) return 1.0 / (1.0 + np.exp(-z)) if __name__ == "__main__": model = DeepFM(n_fields=3, n_symbols=10, k=4) sample = np.array([2, 5, 8]) # 用户=2,商品=5,场景=8 print("CTR 预估值:", round(model.predict(sample), 4))
self.V = rng.normal(0, 0.01, (n_fields * n_symbols, k))初始化每个特征 ID 的隐向量,供 FM 二阶内积和 DNN 共享使用self.offsets = [i * n_symbols for i in range(n_fields)]记录每个特征域在扁平词表中的起点,方便查 Embeddingemb_list.append(self.V[self.offsets[f] + x_idx[f]])取出当前域选中的那个 ID 对应的向量,这是共享 Embedding 的查表核心interaction += embeds[i] @ embeds[j]FM 二阶核心:对每对特征域的隐向量做内积linear = self.w0 + x_flat @ self.w一阶部分:全局偏置加一阶权重加权和a = self._embed(x_idx).reshape(1, -1)DNN 输入:拼接后的 Embedding 向量a = np.maximum(0, a @ W + b)ReLU 激活,逐层前向传播z = self.fm_part(x_idx) + self.dnn_part(x_idx)两路分数相加,模拟「老师傅 + 主厨」协同出菜
常见误区
误区我以为 DeepFM 只是把 Wide&Deep 的 Wide 部分换成 FM,本质没区别,甚至觉得 Wide&Deep 更先提出、更新。
正解两者内核差异很大。Wide 的逻辑回归需要人工构造交叉特征来「记忆」,Deep 侧负责「泛化」;而 DeepFM 用 FM 在 Embedding 层自动学习二阶交叉,完全不需要人工设计交叉特征,且 FM 与 DNN 共享 Embedding 端到端同步训练,信息利用效率更高。
为何常见:两者结构图都是「浅层 + 深层」双塔,形状相似,初学者容易只看结构轮廓而忽略浅层部分的工作方式差别。
误区既然 DNN 是万能的函数逼近器,能自动学习特征组合,那 FM 就是画蛇添足,直接去掉也能达到类似效果。
正解对高维稀疏特征,DNN 要学二阶交叉需要经过多层非线性组合,优化难度大、收敛慢,且容易欠拟合。FM 的显式二阶内积为低阶交互提供了「快捷键」,同时 FM 的梯度还能反向帮助共享 Embedding 层训练得更充分。大量实验证明,去掉 FM 部分后 AUC 会明显下降。
为何常见:深度学习的「万能逼近定理」让人产生深度可以替代一切的直觉,忽略了稀疏数据下优化难度的现实。
误区我认为 k 越大信息越丰富,于是把隐向量维度设置成 512 甚至 1024,觉得模型一定会更强。
正解隐向量维度决定特征表示的容量,但并非越大越好。维度太大容易在稀疏 ID 特征上过拟合,同时计算量剧增。实际工程中 k=8~16 已经足够,因为 FM 的特征交互只依赖两个 k 维向量的内积,DNN 也共享同一套低维稠密表示。
为何常见:深度学习中「更宽更大的网络更好」的经验被错误迁移到 Embedding 维度上,忽略了稀疏特征与小样本的矛盾。
误区模型能自动做交叉特征,那我应该把所有原始字段直接丢进模型,什么都不用准备了。
正解DeepFM 只是替你完成了「交叉特征」这一步,基础的清洗、去重、归一化、缺失值处理仍然必不可少。离散字段要编码成稳定的 ID 并做频次过滤,连续字段要归一化或分桶,否则 Embedding 查表的稳定性和训练效率都会大受影响。
为何常见:技术宣传常说「自动特征交叉」,让新手误以为连数据预处理都可以省略,忽略了特征工程是模型效果的基础保障。
误区DeepFM 效果这么好,我把所有推荐任务都换成 DeepFM 就行了,肯定最优。
正解模型选择取决于数据形态与业务约束。当特征极稀疏但样本量很小时,单独 FM 甚至 LR 可能更稳;当用户行为序列信息丰富时,含注意力序列建模的 DIN 系列更合适;当业务强依赖可解释性时,LR 或 GBDT 依然不可替代。DeepFM 最擅长的是「海量稀疏 ID 特征 + 大规模样本」的 CTR 预估场景。
为何常见:论文 SOTA 效果让人忽略适用边界,而工业界「没有免费午餐」——每种模型都有自己的前提条件。
面试题
Q1. DeepFM 中的 FM 部分主要负责什么?
- A.捕捉高阶特征交互
- B.捕捉低阶一二阶交互← 正确答案
- C.只做全局线性加权
- D.代替 DNN 筛选特征
答案:B。FM 部分负责一阶权重和二阶两两特征交叉,相当于老师傅的经典搭配经验;高阶交互由 DNN 负责。A 是 DNN 的职责,C 只描述了部分,D 不符合 FM 的设计。
Q2. DeepFM 输出层采用什么函数将分数转为 0~1 概率?
- A.ReLU 激活函数
- B.Softmax 归一化
- C.Sigmoid 函数← 正确答案
- D.Tanh 双曲正切
答案:C。CTR 预估是二分类问题,DeepFM 将 FM 与 DNN 的两路分数相加后过 Sigmoid(σ),把任意实数压缩到 (0,1) 区间作为点击概率。
Q3. DeepFM 相比 Wide&Deep 最核心的改进是?
- A.去掉了 DNN 部分
- B.用 FM 替代 Wide 部分← 正确答案
- C.增加了注意力机制
- D.无法端到端训练
答案:B。Wide&Deep 的 Wide 部分需要人工构造交叉特征,DeepFM 用 FM 自动学习二阶交叉来替代它,因此不再依赖人工特征工程,同时保持端到端训练。
Q4. FM 通过什么方式解决稀疏特征下二阶交叉参数难学习?
- A.人工构造所有组合特征
- B.用隐向量内积拆解权重← 正确答案
- C.把稀疏特征转为稠密编码
- D.用决策树做特征组合
答案:B。FM 将交叉权重 w_ij 拆成隐向量 v_i 与 v_j 的内积。即使某对特征从未共同出现,每个特征自身的隐向量也能从其他样本学到,内积仍然有效。A 是 Wide&Deep 的做法,C 描述的是 Embedding 而非交叉策略。
Q5. DeepFM 中 DNN 部分的输入是什么?
- A.原始 one-hot 向量
- B.FM 的一阶输出
- C.特征 Embedding 拼接← 正确答案
- D.FM 的二阶交互结果
答案:C。DNN 的输入是各特征域查表得到的 Embedding 向量拼接结果,这与 FM 共享同一张 Embedding 表。A 维度太高难以训练,B 和 D 是 FM 的输出而非 DNN 输入。
Q6. 关于 DeepFM 的结构,以下说法正确的有?
- A.FM 与 DNN 共享 Embedding 层← 正确答案
- B.两路输出相加后过 Sigmoid← 正确答案
- C.FM 部分与输入特征完全无关
- D.DNN 学习高阶非线性交互← 正确答案
答案:ABD。DeepFM 的 FM 和 DNN 确实共享 Embedding,输出相加过 Sigmoid,DNN 负责高阶交互。C 错误,FM 正是基于输入特征做二阶交叉。
Q7. CTR 预估任务在推荐系统中的核心作用是什么?
- A.统计用户活跃天数
- B.预测用户点击概率← 正确答案
- C.降低服务器存储成本
- D.自动清洗异常数据
答案:B。CTR 预估,即点击率预估,预测用户点击某个商品或广告的概率,直接用于排序与竞价,是推荐系统的核心环节。其余选项都不是 CTR 预估的职责。
Q8. 为什么 DeepFM 比「单独训练 FM + DNN 再融合」效果更好?
- A.端到端联合训练相互协同← 正确答案
- B.共享 Embedding 互相促进← 正确答案
- C.模型总参数量必然更少
- D.完全不需要输入特征处理
答案:AB。端到端训练让 FM 与 DNN 在同一个损失函数下协同优化,共享 Embedding 使低阶和高阶交互学习互相增强。C 不一定成立,参数量取决于配置;D 错误,输入特征处理仍然必要。
Q9. DeepFM 训练时通常选择的损失函数是?
- A.均方误差 MSE
- B.交叉熵 LogLoss← 正确答案
- C.合页损失 Hinge
- D.感知机损失函数
答案:B。CTR 预估是二分类,模型输出经过 Sigmoid 后是概率,交叉熵(LogLoss)能更好地度量概率分布差异并加速收敛。MSE 更适合回归,Hinge 主要用于 SVM 类模型。
Q10. 关于 DeepFM 的特征交互,下列说法正确的有?
- A.FM 仅做两两内积交互← 正确答案
- B.DNN 多层非线性捕捉高阶← 正确答案
- C.共享 Embedding 统一表示← 正确答案
- D.稀疏特征需人工先交叉
答案:ABC。FM 的显式二阶交互只覆盖两两组合,高阶由 DNN 隐式学习;两者共享 Embedding 保证了特征表示的同一性。D 错误,DeepFM 的卖点正是无需人工交叉特征。