想象你走进一家老字号餐厅“知味楼”的后厨。采购员刚从食材市场扛回半头猪、两篓活鱼、一筐时蔬,粗粗地挑出了一堆“可能有用”的食材——这一步叫召回。可你不可能一口吃掉全部食材,真正决定你这顿饭满不满意的,是主厨老陈。他在一分钟内,从这堆食材里挑出几道菜,排出先后次序:先上冷盘,再上热菜,最后是甜汤。这个“排菜顺序”的决策,就是推荐系统里的排序模型。 食材是海量商品,上菜顺序就是商品展示的先后。用户点开 App 只看得见排在最前面的几条——就像你只会认真吃上桌的前三道菜。主厨老陈的方法经历了四代进化:起初靠一张固定打分表,后来发现了“菜与菜的搭配规律”,再后来学会了“一整桌菜的协调感”,如今,他能熟客进门时根据对方今天的点菜,动态调整每道菜的优先级。而这一切,必须在上菜不超时的前提下完成——排菜超过 100 毫秒,客人转头就走了。 这篇内容,我们跟着老陈一起看:排序模型如何从最简单的打分,进化到“千人千面”的动态推荐,以及它落到真实系统里要拿捏的分寸。

岗位关联

排序模型是推荐系统“临门一脚”的决策核心,掌握从 LR 到 DIN 的演进逻辑与在线部署要点,是算法工程师在电商、广告、内容平台做出真实业务增益的必备能力。

目录
  1. 可视化演示
  2. 排序流程定位
  3. LR逻辑回归
  4. FM特征交叉
  5. DeepFM融合
  6. DIN注意力
  7. 在线部署工程
  8. 多目标演进
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

演示从LR到FM再到DeepFM的模型演进、低阶与高阶特征交互,以及在线serving的延迟控制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

排序模型演进 LR→FM→DeepFM 交互能力增强 线性→交叉→深度 演进提升精度

排序流程定位

老陈站在案台前,眼前堆着几十种食材。客人只有一双筷子,他必须在心里快速排出一个上菜顺序:先来的、最显眼的,一定要是客人最可能满意的菜。这套“排菜”功夫,在推荐系统里就是排序模型——它决定了召回到的几百个候选商品,最终以什么顺序出现在用户屏幕上。

整个推荐链路是一条流水线:召回先从百万级商品池里粗筛出几百个候选,排序再对这几百个逐一精打分,最后重排做多样性和商业规则微调。排在最前面的商品获得最多的曝光,位置靠前一位,点击率可能翻倍——所以排序的精度直接决定了业务的天花板。同时它必须快:用户点一下,全链路要在 200 毫秒内响应,排序分到的预算往往只有几十毫秒。精度和延迟,是排序模型的一体两面。

形式上,排序模型对每个候选商品输出一个分数,再按分数降序排列。

老陈很清楚,排菜顺序就是客人的满意度。同样,排序模型的位置就是商品的命运——理解了这个前提,我们才能看懂后面每一种模型为何要进化。

scorei=f(u,vi,c)\text{score}_i = f(u, v_i, c)
Vfinal=sort(Vcand, score, desc)\text{V}_{\text{final}} = \text{sort}(\text{V}_{\text{cand}}, \, \text{score}, \, \text{desc})
两个公式分别回答“打多少分”和“怎么排”:模型融合用户、商品、场景三类信息打分,随后按分数从高到低输出最终列表。
  1. 打分函数对第 i 个候选商品,模型输出一个实数值分数,这个分数是用户 u、商品 vᵢ、上下文 c 共同决定的,对应主厨综合“客人是谁、菜是什么、现在什么场合”来打分。
    scorei=f(u,vi,c)\text{score}_i = f(u, v_i, c)
  2. 降序排序把候选集合里所有商品的得分做降序排列,得到最终展示列表。排第一位的商品代表“主厨最推荐的那道菜”,获得最强曝光。
    Vfinal=sort(Vcand, score, desc)\text{V}_{\text{final}} = \text{sort}(\text{V}_{\text{cand}}, \, \text{score}, \, \text{desc})

LR逻辑回归

老陈年轻时用一本“固定打分本”:客人是北方人加 2 分,这道菜含肉加 3 分,晚上八点用餐加 1 分……把分数加起来,超过某个门槛就推。这套逻辑简单、能解释、上线快,是推荐系统历史上第一代的排序主力——逻辑回归(Logistic Regression,简称 LR)。

LR 把每个特征乘上一个权重,累加得到一个“原始分”,再用Sigmoid 函数(一条 S 形曲线,把任意实数压到 0 到 1 之间)转成概率,这个概率被解释为“用户点击该商品的倾向”。它的数学形式非常简洁:

LR 的代价是不会自动做特征交叉——“男性用户 × 球鞋类目”这样的组合信号,它学不到,只能靠人工手动拼特征。老陈后来发现,光靠固定加分根本hold不住千变万化的搭配,于是他开始研究“菜与菜之间的化学反应”。

p(y=1∣x)=σ(w0+∑i=1nwixi)=11+e−(w0+∑i=1nwixi)p(y=1 \mid x) = \sigma \left( w_0 + \sum_{i=1}^{n} w_i x_i \right) = \frac{1}{1 + e^{-(w_0 + \sum_{i=1}^{n} w_i x_i)}}
公式的本质:先对特征做线性加权,再用 Sigmoid 压缩成点击概率。权重越大,该特征对点击的正向影响越强。
  1. 线性加权每个特征 xᵢ 乘以权重 wᵢ,加上偏置 w₀,得到原始得分 z。对应老陈打分本上的“每道菜按规则加分”。
    z=w0+∑i=1nwixiz = w_0 + \sum_{i=1}^{n} w_i x_i
  2. Sigmoid 压缩把原始得分 z 带入 Sigmoid 函数,无论 z 是正负无穷,输出都落在 (0,1) 区间,可以作为点击概率。z 越大,p 越接近 1,代表越推荐。
    p=11+e−zp = \frac{1}{1 + e^{-z}}

FM特征交叉

老陈渐渐摸到门道:宫保鸡丁配米饭更受欢迎,冰啤酒配红烧肉是绝配。每道菜都可以用几个“口味维度”来描述——咸度、辣度、甜度——两道菜是否搭,就看它们的口味向量是否合拍。这就是因子分解机(Factorization Machine,简称 FM) 的核心思想。

FM 为每个特征学习一个 k 维隐向量,两个特征的交叉权重用它们的向量内积来代替。这个设计的妙处在于参数共享:比如“啤酒”的隐向量在“啤酒×烧烤”和“啤酒×火锅”里都被用到,所以某个组合即使没在训练数据里出现过,也能根据其他组合的反馈估计出它的交叉权重。这在稀疏特征(大量 ID 类 one-hot 特征)场景下是巨大的突破。FM 的预测公式是:

FM 让老陈学会了“两两搭配”,但一个宴席的体验不只是每对菜的关系,还有一整桌的协调感。深度学习登场,帮老陈看到了更复杂的全局。

y^(x)=w0+∑i=1nwixi+∑i=1n∑j=i+1n⟨vi,vj⟩xixj\hat{y}(x) = w_0 + \sum_{i=1}^{n} w_i x_i + \sum_{i=1}^{n} \sum_{j=i+1}^{n} \langle v_i, v_j \rangle x_i x_j
前两项与 LR 相同,第三项是二阶交叉项:所有特征两两配对,权重取两个隐向量的内积。内积越大,说明这对特征的搭配越“合拍”。
  1. 总模型FM 的预测 = 全局偏置 + 线性项 + 二阶交叉项。其中 $\sum_{i<j}$ 表示所有无序特征对。
    y^(x)=w0+∑i=1nwixi+∑i=1n∑j=i+1n⟨vi,vj⟩xixj\hat{y}(x) = w_0 + \sum_{i=1}^{n} w_i x_i + \sum_{i=1}^{n} \sum_{j=i+1}^{n} \langle v_i, v_j \rangle x_i x_j
  2. 展开内积把内积按隐向量的维度 f 展开,看到真实的计算量是 O(n²k),n 是特征数,k 是隐向量维度。
    ∑i<j⟨vi,vj⟩xixj=∑i<j∑f=1kvi,fvj,fxixj\sum_{i<j} \langle v_i, v_j \rangle x_i x_j = \sum_{i<j} \sum_{f=1}^{k} v_{i,f} v_{j,f} x_i x_j
  3. 合并化简把“无序对求和”变成“全部对求和的一半,再减去 i=j 的对角项”,这一步是 FM 能被工业落地的关键。
    ∑i<j∑fvi,fvj,fxixj=12∑f=1k[(∑i=1nvi,fxi)2−∑i=1nvi,f2xi2]\sum_{i<j} \sum_{f} v_{i,f} v_{j,f} x_i x_j = \frac{1}{2} \sum_{f=1}^{k} \left[ \left( \sum_{i=1}^{n} v_{i,f} x_i \right)^2 - \sum_{i=1}^{n} v_{i,f}^2 x_i^2 \right]
  4. 复杂度先算 $\sum_i v_{i,f} x_i$(O(nk)),再整体平方,总复杂度从 O(n²k) 降到 O(nk),线上毫秒级推理才成为可能。
    ∑i=1n∑j=i+1n⟨vi,vj⟩xixj=12∑f=1k[(∑i=1nvi,fxi)2−∑i=1nvi,f2xi2]\sum_{i=1}^{n} \sum_{j=i+1}^{n} \langle v_i, v_j \rangle x_i x_j = \frac{1}{2} \sum_{f=1}^{k} \left[ \left( \sum_{i=1}^{n} v_{i,f} x_i \right)^2 - \sum_{i=1}^{n} v_{i,f}^2 x_i^2 \right]

DeepFM融合

老陈发现,光记住“两两搭配”还不够——一桌菜里,前菜、硬菜、汤、甜品的先后节奏,是一套复杂的全局协调。硬菜之间的气场不能互相压制,汤不能和甜品太像。人工去总结这种“高阶搭配”几乎不可能,深度学习就是来接管这套复杂直觉的。

DeepFM 把 FM 和深度神经网络(Deep Neural Network,简称 DNN)拼在一起:左侧 FM 显式建模低阶(一阶、二阶)交互,右侧 DNN 自动学习高阶非线性交互,二者共享输入特征、并行输出,结果相加再过 Sigmoid。相比“先 FM 预训练再塞进深度网络”的老办法,DeepFM 端到端联合训练,简单又有效。

DeepFM 让老陈练就了“整桌配菜”的功力,但他还有一招更绝的:对熟客,他不是平均对待对方的所有喜好,而是看今天对方点了什么,动态调整推荐。这就是注意力机制。

y^=σ(yFM+yDeep)\hat{y} = \sigma \left( y_{\text{FM}} + y_{\text{Deep}} \right)
a(l+1)=ReLU(W(l)a(l)+b(l))a^{(l+1)} = \text{ReLU} \left( W^{(l)} a^{(l)} + b^{(l)} \right)
DeepFM 的回答是“都要”:FM 保住能解释的搭配直觉,Deep 补上说不清的高阶协调,两者并行相加、一起训练。
  1. 并行相加FM 分支的输出与 Deep 分支的输出相加,再过 Sigmoid 得到最终概率。两个分支谁强都不冲突,是互补关系。
    y^=σ(yFM+yDeep)\hat{y} = \sigma \left( y_{\text{FM}} + y_{\text{Deep}} \right)
  2. Deep 单层DNN 的每一层把上一层输出做线性变换加偏置,再用 ReLU 激活。层数越堆越高,能表达的特征交互就越复杂。
    a(l+1)=ReLU(W(l)a(l)+b(l))a^{(l+1)} = \text{ReLU} \left( W^{(l)} a^{(l)} + b^{(l)} \right)
  3. 共享输入FM 与 Deep 共用同一份特征,不需要各自做特征工程,特征在两侧以不同的方式被利用,最终由梯度同步更新。
    yFM=yFM(x),yDeep=yDeep(x)y_{\text{FM}} = y_{\text{FM}}(x), \quad y_{\text{Deep}} = y_{\text{Deep}}(x)

DIN注意力

熟客张先生每月来八次。老陈没有把张先生过去点过的 50 道菜平均看待,而是看今天张先生已经夹了两口辣子鸡,他立刻意识到:下一道该上冰镇酸梅汤,而不是奶油蘑菇汤。候选的菜不同,老陈注意到的“历史记忆”也不同——这就是深度兴趣网络(Deep Interest Network,简称 DIN) 的思路。

用户的点击历史是一串很长的行为序列,DIN 用“当前候选商品”作为探照灯,去照亮历史记录里最相关的部分:给相关的历史行为分配更高的注意力权重,不相关的压低。最后把所有历史行为加权求和,得到用户的动态兴趣表达——同一用户,面对球鞋和面对口红时,表达出的兴趣向量完全不同。

老陈的“看人下菜”越来越神,但别忘了:客人还等着呢。再厉害的功力,如果上菜超时,一切都是白搭。接下来看看这套手艺如何在后厨的高压线上狂奔。

αi=exp⁡(ϕ(hi,ha))∑j=1Mexp⁡(ϕ(hj,ha))\alpha_i = \frac{\exp \left( \phi \left( h_i, h_a \right) \right)}{\sum_{j=1}^{M} \exp \left( \phi \left( h_j, h_a \right) \right)}
vU=∑i=1Mαihiv_U = \sum_{i=1}^{M} \alpha_i h_i
第一个公式是 softmax 权重:历史行为与候选商品越匹配、权重越高;第二个公式把 M 个历史行为按权重加权求和,得到该候选下的用户兴趣向量。
  1. 注意力权重每个历史行为 $h_i$ 和候选商品 $h_a$ 先由打分函数计算匹配分,再做 softmax 归一化成权重。匹配分高的历史行为,会被模型“多看两眼”。
    αi=exp⁡(ϕ(hi,ha))∑j=1Mexp⁡(ϕ(hj,ha))\alpha_i = \frac{\exp \left( \phi \left( h_i, h_a \right) \right)}{\sum_{j=1}^{M} \exp \left( \phi \left( h_j, h_a \right) \right)}
  2. 动态兴趣把 M 个历史行为的向量按注意力权重加权求和,得到用户此刻的兴趣向量 $v_U$。换一个候选商品,$v_U$ 就随之改变。
    vU=∑i=1Mαihiv_U = \sum_{i=1}^{M} \alpha_i h_i
  3. 激活单元打分函数 φ 用一个小型 MLP 实现,把历史行为与候选商品拼接、相减、点乘后映射成标量,表示“这俩有多相关”。
    ϕ(hi,ha)=MLP([hi,ha,hi−ha,hi⋅ha])\phi(h_i, h_a) = \text{MLP} \left( [h_i, h_a, h_i - h_a, h_i \cdot h_a] \right)

在线部署工程

老陈再熟练,从接到点单到端菜上桌,如果超过三分钟,客人一定拍桌子走人。推荐系统也一样:用户一个请求进来,全链路必须在 200 毫秒内返回,排序环节只分到几十毫秒。在这几十毫秒里,模型要读取实时特征、完成前向推理、吐出排序结果——这就是在线 serving 工程的挑战。

工程上三件事最关键:特征实时计算(用户刚点的赞,10 毫秒内要被下次请求读到,靠日志管道和特征缓存);推理时延控制(模型不能无限加大,必要时做量化、剪枝、蒸馏);模型压缩与更新(把大模型压缩到能在 CPU/GPU 上 20 毫秒跑完,同时保持一天多次的线上效果更新)。

主厨的功夫再深,上菜慢了照样没人吃。但光快还不够——餐厅要赚钱。客人既要好吃,又要上菜快,还要价格实惠,老陈开始盘算:怎么让这顿饭既让客人满意,又让餐厅盈利?

Ttotal=T召回+T排序+T重排≤200  msT_{\text{total}} = T_{\text{召回}} + T_{\text{排序}} + T_{\text{重排}} \le 200 \; \text{ms}
全链路延迟预算是一块蛋糕:召回、排序、重排各切一片,排序通常只分到 20-50 毫秒。超时的代价是用户流失,必须给每个环节钉死预算。
  1. 延迟预算用户从发出请求到看到结果的总时间被分解为召回、排序、重排三段,总预算不超过 200 毫秒。排序段一般占 20% 到 30%,也就是 40-60 毫秒。
    Ttotal=T召回+T排序+T重排≤200  msT_{\text{total}} = T_{\text{召回}} + T_{\text{排序}} + T_{\text{重排}} \le 200 \; \text{ms}
  2. 特征时效实时特征从用户行为发生,到日志收集、清洗、写入缓存、被排序请求读取,整个链路的端到端时延必须足够小,否则“刚刚的行为”就变成“昨天的记忆”。
    Tfeature=T日志+T清洗+T缓存≤10  msT_{\text{feature}} = T_{\text{日志}} + T_{\text{清洗}} + T_{\text{缓存}} \le 10 \; \text{ms}

多目标演进

一桌好菜的标准从来不止一个:客人要好吃,老板娘要翻台率,老板要利润。如果排序只盯着“点击率”,推荐出来的全是标题党,客人点了却不付钱;只盯着“转化率”,又可能错过高潜力的新客。多目标排序就是同时优化点击、转化、GMV(成交总额)等多个业务指标。

工业界常用的结构是共享底座 + 多塔:底层共享用户、商品的 embedding,往上分出几个塔,各自预测一个目标——点击率(CTR)、转化率(CVR)、成交价值(GMV)。预测结果按业务权重融合成最终分数。同时,模型不能只靠每天离线训练一次,还要跟随实时反馈做在线学习:用户每次点击、下单,都变成一条样本,立刻更新模型参数,让推荐跟上今天的流行趋势。

老陈的排菜哲学,终于从“凭感觉”进化到“用数据经营”。从 LR 到 DIN,从单目标到多目标,排序模型不再是孤零零的公式,而是牵动整个推荐系统命脉的掌勺人。

score=pCTRα×pCVRβ×priceγ\text{score} = \text{pCTR}^{\alpha} \times \text{pCVR}^{\beta} \times \text{price}^{\gamma}
θt+1=θt−η∇θL(θt;xt,yt)\theta_{t+1} = \theta_t - \eta \nabla_{\theta} L \left( \theta_t; x_t, y_t \right)
第一个公式是业务融合:点击率、转化率、客单价按指数加权相乘,指数控制各目标的“话语权”;第二个公式是在线学习:拿到一条实时样本就沿梯度方向更新一次参数。
  1. 多目标加权pCTR 是点击概率、pCVR 是转化概率、price 是客单价,三个值相乘得到最终排序分。指数 α、β、γ 控制不同目标的权重,比如大促期间调大 γ 让 GMV 多说话。
    score=pCTRα×pCVRβ×priceγ\text{score} = \text{pCTR}^{\alpha} \times \text{pCVR}^{\beta} \times \text{price}^{\gamma}
  2. 在线学习每来一条实时样本 $(x_t, y_t)$,计算损失对参数的梯度,让参数 $\theta$ 朝负梯度方向迈一小步,步长由学习率 η 控制。推荐系统就这么“活”了起来。
    θt+1=θt−η∇θL(θt;xt,yt)\theta_{t+1} = \theta_t - \eta \nabla_{\theta} L \left( \theta_t; x_t, y_t \right)
  3. 共享底座多塔多个目标塔共享同一个底层 embedding,既减少重复训练,又让点击、转化、GMV 三个目标互相借力。
    shared=Embedding(x),yk=Towerk(shared)\text{shared} = \text{Embedding}(x), \quad y_k = \text{Tower}_k(\text{shared})

AI 应用场景

电商平台的商品排序

阶段:排序阶段(精排)

解决的问题:淘宝、京东这类平台每天有上亿商品,用户搜“运动鞋”能召回几千个候选。如果只按销量排序,小商家新品永远没曝光。排序模型融合用户历史、商品属性、价格带、促销信息,为每个用户现场算出“最可能买”的顺序,让新品也能靠精准匹配获得展示。

具体案例:用户“小李”最近浏览了篮球鞋,但没买。他再次点进 App 时,排序模型通过 DIN 注意力,把他的历史浏览与候选球鞋做匹配,把几双“性价比高、适合实战”的球鞋提到前三,同时多目标加权里把转化率权重调高,促成首单。

信息流广告的实时竞价排序

阶段:排序 + Serving 工程

解决的问题:今日头条、抖音的信息流广告,每次请求要在 50 毫秒内同时完成“内容排序”和“广告竞价排序”。延迟直接决定广告收入:每慢 10 毫秒,用户流失和竞价损失都是千万级。排序模型必须做模型压缩(量化、蒸馏),配合特征缓存和预估结果缓存才能扛住峰值流量。

具体案例:某广告主投放新品预热,平台用 DeepFM 做 CTR 预估、用多目标融合把“点击 × 转化”加权,实时竞价系统在 30 毫秒内给出出价和排序结果,广告点击率比旧版本提升了 18%。

外卖平台的多目标排序

阶段:多目标排序 + 在线学习

解决的问题:美团、饿了么的商家排序要同时优化点击、下单、配送时效、平台佣金。只看点击会把“图片好看但难吃”的店排前面,只看转化会偏向老店。多塔模型共享用户偏好底座,分别预估点击、下单概率,再用业务加权融合,让用户满意、商家有单、平台赚钱三赢。

具体案例:午饭高峰,排序模型通过在线学习捕捉到“今天降温”,实时把热汤类商家的转化权重调高,并给配送距离近的商家加权,用户下单转化率提升了 12%,超时投诉反而下降了。

Python 演示

python54 行
import numpy as npfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import accuracy_score  class FM:    """极简因子分解机:在 LR 的线性加权之外引入二阶特征交叉"""     def __init__(self, n_features, k=4, lr=0.2, epochs=300):        self.w0 = 0.0        self.w = np.zeros(n_features)        self.V = np.random.normal(0, 0.1, (n_features, k))        self.lr = lr        self.epochs = epochs     def _cross(self, X):        # 二阶交叉项: 0.5 * sum_f( (sum_i v_if x_i)^2 - sum_i (v_if x_i)^2 )        square_sum = (X @ self.V) ** 2        sum_square = (X ** 2) @ (self.V ** 2)        return 0.5 * (square_sum - sum_square).sum(axis=1)     def predict(self, X):        logits = self.w0 + X @ self.w + self._cross(X)        return 1 / (1 + np.exp(-logits))     def fit(self, X, y):        n = len(X)        for _ in range(self.epochs):            p = self.predict(X)            err = p - y            self.w0 += self.lr * err.mean()            self.w += self.lr * (err @ X) / n            A = X.T @ (err[:, None] * (X @ self.V)) / n            B = self.V * (X ** 2 * err[:, None]).sum(axis=0)[:, None] / n            self.V += self.lr * (A - B)  # 构造 XOR 数据:x3 是干扰特征,真实标签只与 x1, x2 有关rng = np.random.default_rng(42)X = rng.integers(0, 2, size=(400, 3)).astype(float)y = (X[:, 0] != X[:, 1]).astype(int) # 逻辑回归基线:只能线性加权,学不会特征交叉lr = LogisticRegression()lr.fit(X, y) # 因子分解机:线性 + 二阶交叉fm = FM(n_features=3, k=4, lr=0.2, epochs=300)fm.fit(X, y) pred_lr = lr.predict(X)pred_fm = (fm.predict(X) > 0.5).astype(int)print("LR准确率: %.3f" % accuracy_score(y, pred_lr))print("FM准确率: %.3f" % accuracy_score(y, pred_fm))
目的:用 XOR 数据对比逻辑回归与因子分解机的表现,直观展示“特征交叉”对排序模型的意义——线性模型学不到组合规律,FM 可以。
  1. class FM:定义一个极简因子分解机类,只保留核心的线性项 + 二阶交叉项,对应正文中主厨从“固定打分”到“口味向量搭配”的进化。
  2. self.V = np.random.normal(0, 0.1, (n_features, k))每个特征初始化一个 k 维隐向量,交叉权重用隐向量内积计算,这就是 FM 参数共享的来源。
  3. square_sum = (X @ self.V) ** 2先算每个样本所有特征在隐向量维度上的投影总和,再平方;这是化简公式里的“和的平方”部分。
  4. sum_square = (X ** 2) @ (self.V ** 2)计算“平方和”部分,与上一步配合,把 O(n²k) 的二阶项压缩成 O(nk) 计算。
  5. err = p - y预测概率与真实标签的差,梯度下降的方向;误差越大,参数被修正得越猛。
  6. y = (X[:, 0] != X[:, 1]).astype(int)构造 XOR 标签:两个特征不同则为 1。这种模式线性模型无法正确划分,必须靠特征交叉。
  7. pred_fm = (fm.predict(X) > 0.5).astype(int)把 FM 输出的概率阈值化为 0/1 预测,与 LR 的预测做准确率对比。

常见误区

误区“现在都是深度学习时代了,DeepFM 里的 FM 层只是历史包袱,直接堆 MLP 就能自动学所有特征交互,没必要保留 FM。”

正解DNN 确实能拟合高阶交互,但它对“乘法型”的低阶交互并不友好——两个特征“同时为 1 才有用”这种模式,MLP 需要大量参数和样本才能勉强逼近,而 FM 用隐向量内积一步到位。DeepFM 论文的核心结论之一就是:显式低阶交叉 + 隐式高阶交叉,二者互补,缺一不可。就像一桌好菜,主厨既要懂两两搭配的配方,也要有整桌协调的全局感。

为何常见:大家被“深度模型万能”的宣传影响,忽略了结构设计对学习效率的影响,且很多博客只讲 Deep 部分,不讲 FM 为什么保留。

误区“模型离线 AUC 提升了 2%,上线后点击率肯定会涨,直接全量发布就行。”

正解离线指标是“用历史数据回放”,线上是“实时对抗未知未来”。排序列表变了,用户的注意力分配就变了;延迟变化、特征新鲜度、探索策略都会扭曲离线与在线的映射关系。正确的姿势是灰度 A/B 实验:小流量观察 CTR、转化率、GMV,再逐步放量。

为何常见:离线实验快、成本低,人们天然倾向于相信“指标涨 = 效果涨”,忽略了线上线下是两个环境。

误区“线上排序太慢,那就把模型量化到 int8、剪掉一半参数,反正精度损失一点点看不出来。”

正解模型压缩是“用精度换延迟”的交易,压缩到什么程度要看业务预算:如果排序分到的时延预算只有 20ms,先把特征读取、缓存命中、并发调度这些“周边”优化掉,往往比硬压模型更划算。压缩过度导致排序精度崩坏,用户看到的商品质量下降,省下的几十毫秒毫无意义。

为何常见:延迟好量化(ms 是显性指标),精度损失不好感知(离线 AUC 掉 0.1% 很难察觉),所以人容易偏向“看得见”的优化。

误区“多目标排序很简单,把点击 Loss 和转化 Loss 加起来一起训练不就完事了?”

正解点击和转化的样本分布差异巨大——曝光多、点击少、转化更少,直接相加会让梯度被大样本目标主导,小目标等于没学。工业界常用共享底座 + 多塔结构、不确定性加权或门控机制,让每个目标自适匹配自己的学习节奏。多目标融合时还要注意量纲:pCTR 是百分位小数,GMV 是几元到几千元,直接乘会失衡。

为何常见:因为单目标训练时“加 Loss”是常规操作,人们容易把多目标想成同款操作的简单扩展,忽略目标间的量纲和分布差异。

误区“既然要千变万化,那就每次请求都用最新数据把模型全部重训一遍,这样最实时。”

正解每次请求都全量重训既不现实也不稳定——排序请求峰值每秒上万次,全量重训会导致模型抖动和灾难性遗忘。工业界的在线学习是“样本流水线 + 小步更新”:按分钟/小时把新样本聚合,用 SGD 式的小步梯度更新;同时配合模型版本管理、回滚机制,防止坏样本把模型带偏。

为何常见:“实时”这个词太诱人,大家误以为越频繁更新越智能,忽略了稳定性、成本和一致性工程约束。

面试题

Q1. 逻辑回归模型的输出 p 表示什么?

单选题 · easy

  • A.用户购买该商品的确定概率
  • B.线性加权经 Sigmoid 的点击倾向← 正确答案
  • C.商品在端上曝光的具体顺序位次
  • D.特征重要性的全局排序加权值

答案:B。LR 的输出是特征线性加权后经过 Sigmoid 函数压缩到 0-1 的值,被解释为点击倾向概率。A 错在“确定”二字,模型给的是概率倾向而非确定结论;C 是排序阶段的事,不是 LR 输出;D 与 LR 的权重语义不符。

Q2. FM 的二阶交叉项用隐向量内积 ⟨vᵢ, vⱼ⟩ 代替独立权重 wᵢⱼ,主要好处是?

单选题 · mid

  • A.内积计算更快更节省显存
  • B.隐向量在不同组合间共享可稀疏学习← 正确答案
  • C.内积能表达任意高阶的特征交互
  • D.隐向量比标量权重更容易手工调参

答案:B。FM 的核心优势是参数共享:vᵢ 在“vᵢ×vⱼ“和”vᵢ×vₖ”里都被使用,所以冷门组合也能借助相关组合学到交叉权重,解决稀疏问题。A 不准确,计算复杂度由化简技巧保证而非内积本身;C 错误,内积只建模二阶交互;D 错误,隐向量不是用来手工调参的。

Q3. FM 交叉项复杂度从 O(n²k) 降到 O(nk) 依赖的核心技巧是?

单选题 · mid

  • A.合并所有特征对并减去对角项← 正确答案
  • B.对隐向量做随机采样近似计算
  • C.把隐向量退化为标量权重
  • D.对特征做哈希降维处理

答案:A。FM 把无序对求和改写为“所有对求和的一半减去 i=j 对角项”,得到 (Σvᵢf xᵢ)² − Σ(vᵢf xᵢ)² 的形式,先算各维累加再平方,复杂度降为 O(nk)。B 采样会引入精度损失,C 退化后就丢了向量表达能力,D 是另一类降维技巧。

Q4. DeepFM 中 FM 层的主要作用是?

单选题 · mid

  • A.只做输入特征的选择与过滤
  • B.显式建模低阶或二阶的特征交互← 正确答案
  • C.替代 Deep 层完成所有高阶交互
  • D.压缩输入特征的维度防止过拟合

答案:B。DeepFM 由 FM 和 Deep 两部分并行构成:FM 负责显式的一阶、二阶交叉,Deep 负责隐式高阶交叉。A 错误,FM 不是特征选择器;C 错误,FM 的交互阶数有限;D 错误,压缩维度不是 FM 的设计目标。

Q5. DIN 中注意力权重与下列哪个量直接相关?

单选题 · mid

  • A.候选商品与历史行为的匹配程度← 正确答案
  • B.用户历史行为序列的总长度
  • C.候选商品价格在类目中的高低
  • D.商品被全体用户点击的累计次数

答案:A。DIN 用候选商品作为 query,对每个历史行为计算匹配分,再 softmax 成注意力权重。候选商品不同,同一段历史的权重就不同。B 只是序列长度,不影响单个权重;C、D 与注意力的匹配计算无关。

Q6. 线上推荐链路中,排序环节的延迟通常要求控制在什么级别?

单选题 · easy

  • A.秒级
  • B.十到几十毫秒级← 正确答案
  • C.百秒级
  • D.微秒级

答案:B。全链路 200ms 预算中,排序只分到 20-50ms。秒级会让用户明显感觉卡顿,微秒级在现有硬件上不现实,正确答案是十到几十毫秒级。

Q7. 在线 serving 中降低排序推理耗时的常用手段有?

多选题 · mid

  • A.对模型做量化与剪枝压缩← 正确答案
  • B.特征数据提前接入实时缓存← 正确答案
  • C.无限增加深度网络隐藏层数
  • D.对预估结果按 key 做结果缓存← 正确答案

答案:ABD。量化、剪枝直接减少计算量;特征缓存避免每次请求都走完整链路;结果缓存让相同或相似请求直接命中。C 错误:增加层数会加大计算量,与降低耗时的目标背道而驰。

Q8. 多目标排序中,直接对多个目标的 Loss 求和训练,可能带来哪些问题?

多选题 · hard

  • A.各目标量纲不同导致梯度不平衡← 正确答案
  • B.模型无法同时学习点击与转化目标
  • C.样本分布不均使大样本目标主导更新← 正确答案
  • D.模型参数量会因此显著增加

答案:AC。点击和转化的样本量、数值范围差异大,直接求和会让梯度被大目标主导,量纲差异也会让小目标学不动。B 错误:模型依然能同时学多个目标,只是效果失衡;D 错误:Loss 求和不增加任何参数。

Q9. FM 相比 LR 在稀疏特征场景下优势的根本来源是?

单选题 · hard

  • A.特征 ID 的 one-hot 编码长度更短
  • B.隐向量在不同特征组合间共享参数← 正确答案
  • C.模型引入了更强的 L2 正则化约束
  • D.用深度网络结构替换了线性层

答案:B。FM 每个特征只学一个隐向量,这个向量被所有包含该特征的组合共享,因此罕见的组合也能通过共享向量获得有效估计。A 错误,one-hot 长度不变;C 不是 FM 的核心机制;D 是 DNN 做的事。

Q10. 关于推荐排序模型的描述,正确的有?

多选题 · easy

  • A.排序模型决定候选商品的最终展示顺序← 正确答案
  • B.商品必须先经过召回才能进入排序环节← 正确答案
  • C.排序模型只关心离线精度完全不关心延迟
  • D.排序排错的位置可以由重排环节完全修正

答案:AB。排序模型对召回候选打分排序,决定最终顺序;召回是排序的前置漏斗。C 错误:在线系统对延迟有硬预算。D 错误:重排只是在排序基础上做多样性和规则微调,无法完全挽回排序失误。