搜广推校招面经七十三

字节推荐算法

字节比较注重实习项目,问的很细。

一、点击率(CTR)建模中如何保证广告位自上而下 CTR 率依次递减?

见【搜广推校招面经六十六】

实际中,很多地方都需要单调性限制,比如如果我们预测广告的曝光率,不同广告位的广告肯定曝光率更高。如果预测一张券的使用率或者效果,一定是减免程度越大的效果更好。

在推荐系统或信息流广告中,广告位是有强展示位置信号的

  • 广告位越靠上,用户关注度越高,CTR 趋势越高。通常业务需要:广告位越靠上 CTR 趋势越高,越靠下越低,即 CTR递减性

1.1. 显式加入广告位特征

给模型输入一个特征如 slot_position,表示广告在页面中的位置(1代表最上,依次递增),或者用 one-hotembedding 表示广告位位置

  • 但实际来说,效果不会特别好,因为往往现实中特征会很多,一个特征的不会带来太大的效果。

1.2. 模型输出 + 人工趋势

模型输出的打分后,加上位置 bias,手动控制趋势

adjusted_score = model_output + position_bias[slot_id]
# position_bias 趋势递减,例如 [0.3, 0.1, -0.1, -0.3]

1.3. Loss 加 约束项(位置单调性约束)

1.3.1. 在 loss 中加入 soft constraint,如 保证前一个位置CTR不小于后一个

L o s s + = λ ∗ ∑ m a x ( 0 , C T R ( s l o t k + 1 ) − C T R ( s l o t k ) ) Loss += λ * ∑ max(0, CTR(slot_k+1) - CTR(slot_k)) Loss+=λmax(0,CTR(slotk+1)CTR(slotk))

1.3.2. 在 CTR 模型中加入 单调性约束(Monotonicity Constraint),确保某些特征(如广告位、价格等)对预测值(CTR)有“递增或递减的趋势”。

  • 如果 ∂ C T R / ∂ f e a t u r e > 0 ∂CTR/∂feature > 0 CTR/feature>0(特征变大,CTR 也变大) → 惩罚
  • 如果梯度小于等于目标值 → 不罚
ctr_preds = tf.nn.sigmoid(ctr_logits)
labels = new_features["labels"]
ctr_labels = labels["is_buy"]
log_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=ctr_labels,logits=ctr_logits)
log_loss = tf.reduce_mean(log_loss)
monotony_feature = all_features[monotony_name]
mono_grad = tf.gradients(ctr_preds, monotony_feature)
# 构造惩罚项:如果违反梯度方向就惩罚
mono_grad = tf.where(
	tf.greater(mono_grad, mono_grad_rate * tf.ones_like(mono_grad)),
	tf.zeros_like(mono_grad),
	mono_grad_rate * tf.ones_like(mono_grad) - mono_grad
	)
mono_loss = tf.reduce_mean(mono_grad)
loss = log_loss + mono_loss * monotony_weight

1.4. 模型结构级别控制

  • 引入 Position-aware attention
  • 或者使用特定的排序网络(如 DLRM + Position Bias 模块)

1.5. 人工后排序。

  • 模型训练不受约束,后处理阶段调整排序结果,使满足单调性
for i in range(len(scores)-1):
    if scores[i] < scores[i+1]:
        scores[i+1] = scores[i] - ε  # 强制递减

二、AUC 的两个物理意义,其公式和时间复杂度,随机采样负样本对AUC有什么影响?

见【机器学习校招面经二】
AUC 是 ROC 曲线下的面积(Area Under the ROC Curve),表示模型在 区分正负样本能力 上的总体表现。

2.1. 两个经典物理意义

2.1.1. 随机抽样意义(概率解释)

AUC 表 示:从一个正样本和一个负样本中随机各取一个,模型预测正样本的概率高于负样本的概率
换句话说:

AUC = P( score(x⁺) > score(x⁻) )

这就是为什么 AUC = 0.5 相当于“瞎猜”(模型分不清正负)。

2.1.2. ROC 曲线下的面积

ROC 曲线是以:

  • x轴:False Positive Rate(FPR)
  • y轴:True Positive Rate(TPR)

AUC 是这条曲线下面积的数值,衡量了 模型阈值从 0~1 变化时的整体表现

2.1.3. 排序法计算AUC的公式:

  1. 把所有样本按模型分数排序
  2. 用秩次排名计算正样本的秩次之和 rank_sum
  3. 套用公式:
    A U C = ( r a n k s u m − m ( m + 1 ) / 2 ) / ( m × n ) AUC = (rank_sum - m(m+1)/2) / (m × n) AUC=(ranksumm(m+1)/2)/(m×n)
  • m 是正样本数量
  • n 是负样本数量
  • rank_sum 是所有正样本的秩次之和
  • 该方法避免了 O(mn) 的双重循环,效率高且结果精确
    排序法复杂度为 O(n log n),通常用于实际场景。

2.2. 随机采样负样本对 AUC 的影响

  • 真实业务中正负样本极不平衡(正样本远远少于负样本),完整地计算 AUC 代价太高(尤其是当负样本非常多时)

2.2.1. 采样负样本会导致什么?

  1. 估计误差变大
    • 采样得到的负样本集合可能并不代表整体负样本分布
    • 若采样偏向“易区分”或“难区分”负样本 → AUC 高估或低估
  2. 方差上升
    • 每次采样结果不同,AUC 不稳定
  3. 建议采样策略
    • 尽量 分布均衡地采样 负样本(stratified sampling)
    • 或者多次采样后 平均多个 AUC

三、scaling law(扩展定律)了解多少?哪一项提升对模型的帮助最大?公式了解多少?

Scaling Law 描述的是:当模型的规模(参数量)、数据量、计算量逐渐提升时,模型性能(损失/误差)如何随之变化的规律。
主要由 OpenAI 在 2020 年的论文《Scaling Laws for Neural Language Models》中系统提出。

3.1. 核心公式(经验性拟合)

L ( N ) = A ⋅ N − α + B L(N) = A \cdot N^{-\alpha} + B L(N)=ANα+B

  • L(N):损失(Loss)或误差
  • N:表示参数规模 / 训练 FLOPs / 数据量(视具体分析角度而定)
  • A, B, α:拟合常数

不同维度的 scaling:

维度 变量 对应含义 典型指数 α
模型大小 N = 参数数 #params α ≈ 0.076
训练数据量 D = tokens #tokens α ≈ 0.095
训练 FLOPs C 参数量 × 步数 α ≈ 0.05~0.07

3.2. 哪项提升对性能最有帮助?

结论:增加训练数据量相对收益最大,其次是模型规模,最后是训练步数。

来自 OpenAI 的原始结论:

提升维度 性能收益(以 log-log 曲线斜率衡量) 备注
训练数据量(tokens) 最大(α ≈ 0.095) 最优投资方向
模型规模(参数量) 中等(α ≈ 0.076) 显著但次之
训练时间(FLOPs) 相对较低(α ≈ 0.05) 收益递减

举个例子:

  • 在相同的计算预算下,如果模型过大而数据不足,会导致“过拟合”甚至“欠训练”(undertrained)。
  • 合理策略是:按比例平衡三者,找到 loss 最优组合点

3.3. Chinchilla Scaling Law(2022 DeepMind)

Chinchilla 提出新的 scaling 观点:在固定计算预算下,训练中小模型+大数据,效果更优!

模型 参数量 训练 tokens 性能
Gopher 280B 300B tokens AUC较差
Chinchilla 70B 1.4T tokens 击败 Gopher(性能更优)

说明:盲目堆大模型,不如喂足够的数据!

四、C++ 中指针(Pointer)和引用(Reference)的区别

4.1. 基本定义

概念 定义
指针(Pointer) 是一个变量,存储另一个变量的地址
引用(Reference) 是一个变量的别名/别称,和原变量共用同一块内存
int a = 10;

// 指针
int* p = &a;  // p 是 a 的地址

// 引用
int& r = a;   // r 是 a 的别名

4.2. 主要区别对比

比较项 指针(Pointer) 引用(Reference)
是否必须初始化 否,可以为 nullptr ✅ 是,必须初始化
是否可变更指向 ✅ 可以重新指向其他地址 ❌ 一经绑定不可更改
是否支持空值 ✅ 可以为 nullptr ❌ 不存在 null 引用
解引用操作 需要显式 *p 隐式,直接使用引用即可
运算 支持指针算术运算(如 p++ ❌ 不支持运算
用于函数参数 需要传地址 &a 直接传变量,语法更简洁
存储 是一个变量(占用内存) 仅是变量别名(不额外占内存)

引用是语法糖,更安全、更直观,但功能受限;指针更灵活,但容易出错。
两者都重要,理解其本质和使用边界是 C++ 编程的核心。

五、200. 岛屿数量

这道题是我第一次看到有被问到。
搜广推校招面经七十三_第1张图片

  • 思路:
    遍历每个点,并以该点为基础,访问上下左右。如果该位置被访问、越界、是水就跳出。
  • 代码:
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        m,n = len(grid), len(grid[0])
        def dfs(i, j):
            if i<0 or i>=m or j<0 or j>=n or grid[i][j] != '1':
                return
            grid[i][j] = '2'
            dfs(i, j-1)
            dfs(i, j+1)
            dfs(i-1, j)
            dfs(i+1, j)
        ans = 0
        for i, row in enumerate(grid):
            for j, c in enumerate(row):
                if c=='1':
                    dfs(i, j)
                    ans +=1
        return ans 

你可能感兴趣的:(搜广推面经,机器学习,人工智能,深度学习,推荐算法,搜索算法,算法)