搜广推校招面经六十六

高德推荐算法

一、介绍Transformer中的位置编码(Positional Encoding)

在 Transformer 结构中,由于模型没有内置的序列信息(不像 RNN 那样有时间步的顺序依赖),需要通过**位置编码(Positional Encoding, PE)**来提供位置信息,使得模型能够区分不同 token 的相对位置。

1.1. 位置编码的作用

由于 Transformer 采用的是自注意力机制(Self-Attention),它对输入序列的排列顺序不敏感,因此需要显式地向输入中添加位置信息。位置编码的主要作用包括:

  • 提供位置信息,使模型能够捕捉顺序关系。结合词向量(Embedding)输入到 Transformer 中,以提供语义和位置信息。

1.2. 正弦-余弦位置编码(Sinusoidal Positional Encoding)

Vaswani 等人在 "Attention is All You Need" 论文中提出了一种固定的 位置编码方法,使用不同频率的正弦(sin)和余弦(cos)函数 来编码位置:
P E ( p o s , 2 i ) = sin ⁡ ( p o s 1000 0 2 i / d ) P E ( p o s , 2 i + 1 ) = cos ⁡ ( p o s 1000 0 2 i / d ) PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d}}\right) \\ \ \\ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d}}\right) PE(pos,2i)=sin(100002i/dpos) PE(pos,2i+1)=cos(100002i/dpos)

其中:

  • p o s pos pos 表示序列中的位置(Position)。
  • i i i 表示维度索引(每个位置编码有 d 维)。
  • d d d 表示编码的总维度(等于 Embedding 维度)。
  • 1000 0 2 i / d 10000^{2i/d} 100002i/d 作为不同维度的缩放因子,使得不同维度的 PE 具有不同的变化率。

1.3. 为什么使用正弦和余弦?

  • 周期性 :不同位置的编码可以通过线性组合推导出新位置的编码,有利于泛化到更长的序列
  • 不同频率:较低维度的编码变化较快,较高维度的编码变化较慢,使得模型能够学习不同粒度的相对位置信息。
  • 平滑变化:相邻位置的编码变化平滑,符合自然语言的顺序特性。

1.4. PyTorch 实现

以下是使用 PyTorch 实现的位置编码模块:

python 复制代码
import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model: int, max_len: int = 5000):
        """
        :param d_model: 词向量维度 (Embedding 维度)
        :param max_len: 序列最大长度
        """
        super(PositionalEncoding, self).__init__()

        # 创建位置编码矩阵(shape: [max_len, d_model])
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)  # [max_len, 1]
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))  # [d_model/2]

        # 计算 sin 和 cos 位置编码
        pe[:, 0::2] = torch.sin(position * div_term)  # 偶数索引
        pe[:, 1::2] = torch.cos(position * div_term)  # 奇数索引

        # 增加 batch 维度以便广播
        pe = pe.unsqueeze(0)  # shape: [1, max_len, d_model]

        # 注册为 buffer,使其不会被模型参数更新
        self.register_buffer('pe', pe)

    def forward(self, x):
        """
        :param x: 输入张量,形状为 [batch_size, seq_len, d_model]
        :return: 加入位置编码后的张量
        """
        return x + self.pe[:, :x.size(1), :]

二、如何解决CTR预估中广告位置的bias,讲讲网络中的bias net如何做

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

在广告投放中,**广告位置(Ad Placement)会对点击率(CTR)、转化率(CVR)等关键指标产生影响,导致模型学习到的特征偏向某些广告位,而不是用户真实的兴趣或广告的质量。这种位置偏差(Position Bias)**可能导致:

  • 高曝光广告位置的 CTR 过高,导致模型高估广告效果。
  • 低曝光广告位置的 CTR 过低,导致模型低估广告的潜力。
  • 难以推广新的广告位,模型可能更倾向于已经有数据的广告位。

2.1. Bias Net(偏置网络)原理

Bias Net 主要用于建模广告位置对点击率的影响 ,并将其从主模型(如 CTR 预估模型)中剥离,使主模型学习到去除位置影响后的广告真实效果。

Bias Net 主要采用 "双塔网络"(Two-Tower Model) 的思想:

  • 一个塔(主网络 MainNet):学习广告本身的影响,如广告内容、用户兴趣等。
  • 一个塔(BiasNet) :专门学习广告位置的偏置,并将其影响去除。
    最终的去偏目标
    P ( click ∣ ad, user ) = P ( click ∣ ad, user, pos ) / P ( click ∣ pos ) P(\text{click} | \text{ad, user}) = P(\text{click} | \text{ad, user, pos}) / P(\text{click} | \text{pos}) P(click∣ad, user)=P(click∣ad, user, pos)/P(click∣pos)
    其中:
  • P ( click ∣ ad, user, pos ) P(\text{click} | \text{ad, user, pos}) P(click∣ad, user, pos) 是普通 CTR 预估模型的预测值。
  • P ( click ∣ pos ) P(\text{click} | \text{pos}) P(click∣pos) 由 BiasNet 预测,建模广告位置的影响。

2.2. Bias Net 结构

BiasNet 通过 MLP(多层感知机)或 Embedding 方式 学习广告位置的偏置。以下是 BiasNet 的常见结构:

  1. Embedding + MLP 方式:
    • 输入:广告位 position_id
    • 处理:通过 Embedding 层将广告位转换为向量,再通过 MLP 学习其对点击率的影响。
    • 输出:广告位的偏置得分。
  2. 独立建模
    • 训练一个单独的网络,仅依赖广告位置 position_id 预测 CTR,然后归一化,使其成为位置偏置因子。

2.2.1. PyTorch 实现 BiasNet

python 复制代码
import torch
import torch.nn as nn

class MainNet(nn.Module):
    def __init__(self, ad_feature_dim, user_feature_dim):
        super(MainNet, self).__init__()
        self.fc = nn.Sequential(
            nn.Linear(ad_feature_dim + user_feature_dim, 128),
            nn.ReLU(),
            nn.Linear(128, 64),
            nn.ReLU(),
            nn.Linear(64, 1),
            nn.Sigmoid()
        )
    
    def forward(self, ad_features, user_features):
        x = torch.cat([ad_features, user_features], dim=1)
        return self.fc(x)

2.3. 去除广告位置(pos)的影响,为什么使用除法?

在去除广告位置(Position, pos)的影响时,使用除法 而不是加法的主要原因是 归一化比例调整

2.3.1. 直觉解释

假设我们要预测广告的点击率(CTR),模型的原始预测值是:
P ( click ∣ ad , user , pos ) P(\text{click} | \text{ad}, \text{user}, \text{pos}) P(click∣ad,user,pos)

但由于广告位置会影响点击率(例如,广告展示在页面顶部时点击率更高),我们需要去除 pos 的影响,使得模型的预测结果更加公正,仅反映广告内容和用户兴趣。

BiasNet 是专门用于学习 pos 对点击率影响的网络,它的输出是:
P ( click ∣ pos ) P(\text{click} | \text{pos}) P(click∣pos)
最终,我们想要的去偏点击率应该是:
P debiased ( click ∣ ad , user ) = P ( click ∣ ad , user , pos ) P ( click ∣ pos ) P_{\text{debiased}}(\text{click} | \text{ad}, \text{user}) = \frac{P(\text{click} | \text{ad}, \text{user}, \text{pos})}{P(\text{click} | \text{pos})} Pdebiased(click∣ad,user)=P(click∣pos)P(click∣ad,user,pos)

2.3.2. 为什么使用除法?

(1) 归一化(Normalization)
  • P ( click ∣ pos ) P(\text{click} | \text{pos}) P(click∣pos) 代表某个广告位置的整体点击率,它可以看作是该位置的"全局 CTR"。
  • 通过除法,我们可以消除广告位置对 CTR 的整体提升或降低的影响,使不同广告位置的 CTR 处于相同的基准水平。
(2) 避免负值
  • 如果使用加法去除位置影响,比如 P ( click ∣ ad , user , pos ) − P ( click ∣ pos ) P(\text{click} | \text{ad}, \text{user}, \text{pos}) - P(\text{click} | \text{pos}) P(click∣ad,user,pos)−P(click∣pos),可能会导致负的点击率,这不符合实际情况。
  • 而使用除法确保调整后的 CTR 始终是正数,并且仍然具有可解释性。
(3) 保持比例关系
  • 广告位的影响往往是乘法关系,而非加法关系。例如:
    • 广告 A 在顶部位置 的点击率可能是 广告 B 在底部位置 点击率的 3 倍
    • 如果使用除法,广告 A 和广告 B 的 CTR 仍然可以保持这个比例。
    • 而如果使用加法,会导致 CTR 计算失真,失去原有的相对比例。

2.4. 也可以通过多任务学习,联合优化两个loss。

  • CTR 预测的目标 : P ( click ∣ ad , user ) P(\text{click} | \text{ad}, \text{user}) P(click∣ad,user)
  • 位置偏置预测的目标 : P ( click ∣ pos ) P(\text{click} | \text{pos}) P(click∣pos)
  • 联合损失函数
    L = L CTR + λ L BiasNet L = L_{\text{CTR}} + \lambda L_{\text{BiasNet}} L=LCTR+λLBiasNet

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

在广告点击率(CTR)建模中,广告通常是按一定策略排序展示的。通常情况下,用户的注意力随广告位(Position)下降而减少,因此 CTR 也应该遵循 "自上而下递减" 的规律。然而,在实际建模过程中,CTR 可能会受到其他因素(如广告内容、用户兴趣等)的干扰,导致某些下方广告的 CTR 反而比上方广告高。

3.1. 为什么需要保证 CTR 递减?

  • 符合用户行为模式:在大多数应用场景中,用户对上方广告的关注度较高,因此 CTR 也应该较高。
  • 避免模型异常学习:如果 CTR 没有递减趋势,可能意味着模型没有正确建模广告位置的影响,或者数据存在偏差。
  • 提升广告排序的稳定性:确保 CTR 预测结果合理,有助于广告投放系统优化广告排序,提高收益。

如果模型未能正确学习广告位的影响,CTR 预测可能出现异常。

3.2 保证广告位 CTR 递减的方法

(1) 在模型输入中添加广告位置信息

  • 显式建模广告位特征 :在模型中添加广告位 pos 作为一个重要特征,并确保其影响符合期望:
    P ( click ∣ pos ) 递减 P(\text{click} | \text{pos}) \text{ 递减} P(click∣pos) 递减
  • 位置编码方式
    • Embedding 方式 :使用 pos_embedding = nn.Embedding(n_pos, embedding_dim),让模型学习广告位的影响。
    • 数值归一化方式 :直接使用 pos / n_pos 作为一个数值特征输入。

(2) 在模型优化中添加单调性约束

为了确保 P ( click ∣ pos ) P(\text{click} | \text{pos}) P(click∣pos) 递减,可以对模型进行约束:

  • 位置影响单调递减

    • 约束 ∂ P ( click ) ∂ pos ≤ 0 \frac{\partial P(\text{click})}{\partial \text{pos}} \leq 0 ∂pos∂P(click)≤0,即广告位 pos 越大(排名越靠后),CTR 预测值不会上升。
    • 在神经网络中,可通过 单调性网络(Monotonic Neural Networks)权重约束 来实现。
  • 使用单调递减的变换函数

    • 例如在 MLP 层中,使用 S o f t p l u s ( − x ) Softplus(-x) Softplus(−x) 或 − R e L U ( x ) -ReLU(x) −ReLU(x) 来确保输出单调递减:
python 复制代码
  class MonotonicLayer(nn.Module):
      def __init__(self, input_dim):
          super().__init__()
          self.linear = nn.Linear(input_dim, 1)
      
      def forward(self, x):
          return -torch.relu(self.linear(x))  # 保证单调递减
  • 使用排序损失(Ranking Loss)**:
    • pos_1pos_2 之上,则 P(\text{click} | \text{pos_1}) 应该大于 P(\text{click} | \text{pos_2})

(3) 在数据处理阶段去除位置偏差

如果数据中广告位的 CTR 没有遵循递减规律,可以通过以下方法调整:

  1. 分层归一化(Layer-wise Normalization)

    • 在训练数据中,对不同广告位的 CTR 进行归一化,避免数据不均衡带来的问题。
    • 例如,对每个广告位 pos 计算均值 CTR μ_pos,然后对 y 进行调整:
      y ′ = y μ pos y' = \frac{y}{\mu_{\text{pos}}} y′=μposy
  2. 逆倾向采样(Inverse Propensity Weighting, IPW)

    • 由于广告位较高的曝光量远大于广告位较低的曝光量,可以使用 P(\text{pos}) 作为权重,对样本进行重新加权:
      w i = 1 P ( pos i ) w_i = \frac{1}{P(\text{pos}_i)} wi=P(posi)1
    • 在损失函数中加入权重:
python 复制代码
 loss = torch.mean(weight * loss_function(y_pred, y_true))

(4) 在预测阶段调整 CTR

如果模型仍然预测出了不符合递减规律的 CTR,可以在后处理时进行 排序约束调整

  • 强制后验排序修正
    • 对每个广告列表的 CTR_pred 进行 Sort,确保 P(\text{click} | \text{pos}) 递减:

ctr_pred_sorted, _ = torch.sort(ctr_pred, descending=True)

  • 加权平均平滑
    • 使用滑动窗口平滑方法,确保预测的 CTR 递减:
python 复制代码
def smooth_ctr(ctr_pred):
    for i in range(1, len(ctr_pred)):
        ctr_pred[i] = min(ctr_pred[i], ctr_pred[i-1])
    return ctr_pred
相关推荐
橙色小博25 分钟前
PyTorch中的各种损失函数的详细解析与通俗理解!
人工智能·pytorch·python·深度学习·神经网络·机器学习
小森77671 小时前
(三)机器学习---线性回归及其Python实现
人工智能·python·算法·机器学习·回归·线性回归
-XWB-1 小时前
【LLM】使用MySQL MCP Server让大模型轻松操作本地数据库
人工智能·python·自然语言处理
PacosonSWJTU2 小时前
python基础-13-处理excel电子表格
开发语言·python·excel
James. 常德 student3 小时前
深度学习之微调
人工智能·深度学习
小军要奋进3 小时前
httpx模块的使用
笔记·爬虫·python·学习·httpx
Johnny_Cheung3 小时前
字符串、列表、元组、字典
开发语言·python
独行soc3 小时前
2025年渗透测试面试题总结- 某四字大厂面试复盘扩展 一面(题目+回答)
java·数据库·python·安全·面试·职场和发展·汽车
Mr_LeeCZ3 小时前
PyTorch 深度学习 || 7. Unet | Ch7.1 Unet 框架
人工智能·深度学习·机器学习
不要天天开心3 小时前
Scala集合
图像处理·算法·机器学习·scala