搜广推校招面经十三
DeepFM 是一种结合 深度学习 (Deep Learning) 和 因子分解机 (Factorization Machine, FM) 的推荐系统模型。它能够同时学习 低阶特征交互(FM 部分) 和 高阶特征交互(DNN 部分)。在 召回阶段,UserCF(User-Based Collaborative Filtering,基于用户的协同过滤)需要计算用户相似度,以便推荐相似用户喜欢的物品。
字节推荐算法
一、介绍DeepFM,Deep 和 FM 的区别,两者的特征数量是一样的么?
DeepFM 是一种结合 深度学习 (Deep Learning) 和 因子分解机 (Factorization Machine, FM) 的推荐系统模型。它能够同时学习 低阶特征交互(FM 部分) 和 高阶特征交互(DNN 部分)。
- FM
FM 的核心思想是对特征交叉进行矩阵分解,即用向量内积代替了传统的 one-hot 乘法计算,能够学习特征之间的 二阶交互(如性别 × 购买记录)
公式:y^=w0+∑iwixi+∑i∑j>i⟨vi,vj⟩xixj\hat{y} = w_0 + \sum_{i} w_i x_i + \sum_{i}\sum_{j>i} \langle v_i, v_j \rangle x_i x_jy^=w0+∑iwixi+∑i∑j>i⟨vi,vj⟩xixj - DNN
DNN 侧负责学习高阶特征交互,结构通常是多层全连接神经网络 - 两者的特征数量没有具体说法,可以一样,也可以不一样。但是FM结构一般用于分类特征的交叉。DNN往往可以加更多的连续特征,所以一般还是不一样。
- 但是往往FM 和 DNN会共享同一个embedding,那么两者的特征数量又是一样的。
二、了解召回么,召回中 UserCF(User-Based Collaborative Filtering,基于用户的协同过滤)对应的user向量怎么生成的。
在 召回阶段,UserCF(User-Based Collaborative Filtering,基于用户的协同过滤)需要计算用户相似度,以便推荐相似用户喜欢的物品。核心问题之一就是 如何生成用户向量(User Embedding)
2.1. 基于用户行为(User-Item 矩阵)
直接将用户对物品的行为特征当作用户矩阵。缺点就是太稀疏了,因为用户往往对大部分物品没有操作。
2.2. 通过矩阵分解生成 User Embedding
由于 User-Item 矩阵通常非常稀疏,我们可以使用矩阵分解(Matrix Factorization, MF)来生成低维的用户向量。
- SVD 分解 (Singular Value Decomposition)
通过 SVD(奇异值分解),可以将 用户-物品交互矩阵A 分解成:
A≈UkΣkVkT A \approx U_k \Sigma_k V_k^T A≈UkΣkVkT
例如,一个原始的 10000 用户 × 100000 物品矩阵,可以分解成:
UUU矩阵 (10000 × 128):每个用户有 128 维 embedding
VVV矩阵 (100000 × 128):每个物品有 128 维 embedding
最终的 User Embedding 就是 矩阵 UUU 的行向量,表示每个用户的低维表示。 - ALS(交替最小二乘)
ALS (Alternating Least Squares) 是常用于 UserCF 的矩阵分解方法,它迭代优化:
R≈PQTR≈PQ^TR≈PQT- PPP 是用户矩阵
- QQQ 是物品矩阵
三、优化器了解么?介绍一下优化器
神经网络的优化器(Optimizer)是用于更新模型参数(如权重和偏差)的算法,核心目标是最小化损失函数:
3.1 基础的优化器
- 随机梯度下降(SGD, Stochastic Gradient Descent)
- 公式:θ=θ−η⋅∇L(θ)\theta = \theta - \eta \cdot \nabla L(\theta)θ=θ−η⋅∇L(θ)
- η\etaη:学习率
- ∇L(θ)\nabla L(\theta)∇L(θ):损失函数 𝐿(𝜃) 对参数 𝜃 的梯度
- 公式:θ=θ−η⋅∇L(θ)\theta = \theta - \eta \cdot \nabla L(\theta)θ=θ−η⋅∇L(θ)
3.2 带动量的优化算法
- 动量梯度下降(Momentum SGD)
- 公式:vt=βvt−1+(1−β)∇L(θ) θ=θ−ηvtv_t = \beta v_{t-1} + (1-\beta) \nabla L(\theta) \\ \ \\ \theta = \theta - \eta v_tvt=βvt−1+(1−β)∇L(θ) θ=θ−ηvt
- 通过指数加权平均(EMA)的方法,缓解震荡问题;
- 在陡峭方向收敛更快,在平坦方向减小震荡
- Nesterov 动量(NAG, Nesterov Accelerated Gradient)
- 公式vt=βvt−1+(1−β)∇L(θ−ηvt−1) θ=θ−ηvtv_t = \beta v_{t-1} + (1 - \beta) \nabla L(\theta - \eta v_{t-1}) \\ \ \\ \theta = \theta - \eta v_tvt=βvt−1+(1−β)∇L(θ−ηvt−1) θ=θ−ηvt
- 计算梯度时使用“提前一步”的权重,收敛更快
- 比普通 Momentum 具有更好的泛化能力
3.3 自适应学习率优化算法
-
Adagrad(Adaptive Gradient)
- 公式:Gt=Gt−1+∇L(θ)⊙∇L(θ) θ=θ−ηGt+ϵ∇L(θ)G_t = G_{t-1} + \nabla L(\theta) \odot \nabla L(\theta) \\ \ \\ \theta = \theta - \frac{\eta}{\sqrt{G_t} + \epsilon} \nabla L(\theta)Gt=Gt−1+∇L(θ)⊙∇L(θ) θ=θ−Gt+ϵη∇L(θ)
- 特点
- 自适应调整不同参数的学习率
- 主要问题是随着时间推移,学习率不断减小,最终趋近于 0
-
RMSprop(Root Mean Square Propagation)
- 公式:
Gt=βGt−1+(1−β)∇L(θ)⊙∇L(θ) θ=θ−ηGt+ϵ∇L(θ) G_t = \beta G_{t-1} + (1 - \beta) \nabla L(\theta) \odot \nabla L(\theta) \\ \ \\ \theta = \theta - \frac{\eta}{\sqrt{G_t} + \epsilon} \nabla L(\theta) Gt=βGt−1+(1−β)∇L(θ)⊙∇L(θ) θ=θ−Gt+ϵη∇L(θ) - 特点
- 解决了 Adagrad 学习率衰减过快的问题
- 适用于时序任务
- 公式:
-
Adam(Adaptive Moment Estimation)
mt=β1mt−1+(1−β1)∇L(θ) vt=β2vt−1+(1−β2)∇L(θ)⊙∇L(θ) mt^=mt1−β1t,vt^=vt1−β2t θ=θ−ηvt^+ϵmt^ m_t = \beta_1 m_{t-1} + (1 - \beta_1) \nabla L(\theta) \\ \ \\ v_t = \beta_2 v_{t-1} + (1 - \beta_2) \nabla L(\theta) \odot \nabla L(\theta) \\ \ \\ \hat{m_t} = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v_t} = \frac{v_t}{1 - \beta_2^t} \\ \ \\ \theta = \theta - \frac{\eta}{\sqrt{\hat{v_t}} + \epsilon} \hat{m_t} mt=β1mt−1+(1−β1)∇L(θ) vt=β2vt−1+(1−β2)∇L(θ)⊙∇L(θ) mt^=1−β1tmt,vt^=1−β2tvt θ=θ−vt^+ϵηmt^ -
AdamW(Weight Decay Adam)
- 公式:
θ=θ−η(mt^vt^+ϵ+λθ) \theta = \theta - \eta \left( \frac{\hat{m_t}}{\sqrt{\hat{v_t}} + \epsilon} + \lambda \theta \right) θ=θ−η(vt^+ϵmt^+λθ) - 特点:
- AdamW 在 Adam 的基础上增加了 权重衰减(Weight Decay)
- 公式:
3.4. 其他优化算法
- AdaDelta
进一步改进 RMSprop,使学习率自适应变化
Δθt=−Δθt−12+ϵGt+ϵ∇L(θ) \Delta \theta_t = - \frac{\sqrt{\Delta \theta_{t-1}^2 + \epsilon}}{\sqrt{G_t + \epsilon}} \nabla L(\theta) Δθt=−Gt+ϵΔθt−12+ϵ∇L(θ) - Nadam(Nesterov-accelerated Adam)
结合 Adam 和 NAG 的优化方法:
mt=β1mt−1+(1−β1)∇L(θ) mt^=mt1−β1t θ=θ−η(β1mt^+(1−β1)∇L(θ)vt^+ϵ) m_t = \beta_1 m_{t-1} + (1 - \beta_1) \nabla L(\theta) \\ \ \\ \hat{m_t} = \frac{m_t}{1 - \beta_1^t} \\ \ \\ \theta = \theta - \eta \left( \frac{\beta_1 \hat{m_t} + (1 - \beta_1) \nabla L(\theta)}{\sqrt{\hat{v_t}} + \epsilon} \right) mt=β1mt−1+(1−β1)∇L(θ) mt^=1−β1tmt θ=θ−η(vt^+ϵβ1mt^+(1−β1)∇L(θ)) - Lion(EvoLved Sign Momentum)
mt=β1mt−1+(1−β1)∇L(θ) θ=θ−η(sign(mt)+λθ) m_t = \beta_1 m_{t-1} + (1 - \beta_1) \nabla L(\theta) \\ \ \\ \theta = \theta - \eta (\text{sign}(m_t) + \lambda \theta) mt=β1mt−1+(1−β1)∇L(θ) θ=θ−η(sign(mt)+λθ)
| 优化器 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| SGD | 适用于小型数据集 | 计算简单,稳定 | 震荡大,收敛慢 |
| Momentum | 适用于梯度震荡较大的情况 | 解决震荡问题,加速收敛 | 需要调参(β 值) |
| NAG | 适用于快速收敛的场景 | 提前更新,收敛更快 | 计算量略大 |
| Adagrad | 适用于稀疏数据 | 自适应学习率 | 学习率下降过快 |
| RMSprop | 适用于非平稳目标 | 平稳收敛,适用于 RNN | 需要调 β |
| Adam | 适用于大多数任务 | 结合 Momentum 和 RMSprop | 泛化能力较差 |
| AdamW | 适用于大规模深度网络 | 加入 Weight Decay,提高泛化 | 计算量略大 |
| Nadam | 适用于 NLP 任务 | 结合 Adam 和 NAG | 计算量大 |
4、如何判断模型过拟合
- 训练集验证集效果差异大
- 交叉验证的不同折差异大
- 。。。
5、算法题1-数组中的第K个最大元素(hot100)
这是一道经典的使用快排或者堆排序的题(求TOPK)
回顾一下快排
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
import random
def quicksort(nums,left,right):
flag=nums[random.randint(left,right)]
i,j=left,right #设定从左到右的指针i,从右到左的指针j
while i<=j:
while nums[i]<flag: i+=1 #i从左往右扫,找到大于等于flag的数。
while nums[j]>flag: j-=1 #j从右往左扫,找到小于等于flag的数。
if i<=j:
nums[i],nums[j]=nums[j],nums[i] #交换左右指针下标对应的数值
i+=1 #左指针继续往右走
j-=1 #右指针继续往左走
if i<right: quicksort(nums,i,right) #递归解决flag左边的低位数组的排序
if j>left: quicksort(nums,left,j) #递归解决flag右边的低位数组的排序
quicksort(nums,0,len(nums)-1) #函数入口,将整个数组的信息传入
return nums #返回修改后的nums
那么这道题使用快排就可以写为
class Solution:
def findKthLargest(self, nums, k):
def quick_select(nums, k):
# 随机选择基准数
pivot = random.choice(nums)
big, equal, small = [], [], []
# 将大于、小于、等于 pivot 的元素划分至 big, small, equal 中
for num in nums:
if num > pivot:
big.append(num)
elif num < pivot:
small.append(num)
else:
equal.append(num)
if k <= len(big):
# 第 k 大元素在 big 中,递归划分
return quick_select(big, k)
if len(nums) - len(small) < k:
# 第 k 大元素在 small 中,递归划分
return quick_select(small, k - len(nums) + len(small))
# 第 k 大元素在 equal 中,直接返回 pivot
return pivot
return quick_select(nums, k)
更多推荐



所有评论(0)