搜广推校招面经四

字节

  • 一、手撕DIN
python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
class DIN(nn.Module):
    def __init__(self, num_users, num_items, embedding_dim, history_size):
        super(DIN, self).__init__()
        
        self.user_embedding = nn.Embedding(num_users, embedding_dim)
        self.item_embedding = nn.Embedding(num_items, embedding_dim)
        self.history_embedding = nn.Embedding(num_items, embedding_dim)
        
        self.attention_layer = nn.Linear(embedding_dim * 2, 1)
        self.fc_layer = nn.Sequential(
            nn.Linear(embedding_dim * 2, 128),
            nn.ReLU(),
            nn.Linear(128, 1)
        )
    def forward(self, user_id, item_id, history_ids):
        user_emb = self.user_embedding(user_id)
        item_emb = self.item_embedding(item_id)
        history_emb = self.history_embedding(history_ids)
        
        # 计算兴趣提取:使用注意力机制加权历史行为嵌入
        # 计算历史行为与目标物品的相似度 (比如使用点积)
        combined_emb = torch.cat((history_emb, item_emb_expanded), dim=-1)  # 拼接历史行为和物品嵌入
        # 计算注意力权重
        attention_weights = F.softmax(self.attention_layer(combined_emb), dim=1)
        weighted_history_emb = torch.sum(attention_weights * history_emb, dim=1)

        fusion_emb = torch.cat((item_emb, weighted_history_emb), dim=-1)
        output = self.fc_layer(fusion_emb)
        return output
model = DIN(num_users, num_items, embedding_dim, history_size)
  • 二、手撕NCE loss
    NCE Loss 是一种用于训练概率模型的损失函数,最初在学习词向量(Word2Vec)时提出。NCE Loss 的核心思想是通过将目标分布与噪声分布进行对比,来简化模型的训练过程,从而避免了传统的 softmax 计算中昂贵的归一化步骤。NCE Loss 适用于训练大规模语言模型和推荐系统等。

    NCE 通过将原始任务转换为二分类任务:对于每个真实的样本,判断它是来自目标分布还是来自噪声分布(负样本)。这样,我们不再需要计算所有词汇的总和,而是只需要根据噪声词和正样本来训练模型。具体来说,NCE 会为每个正样本 w w w和上下文词 c c c生成一组负样本 w 1 , . . . . . w k w_1,.....w_k w1,.....wk (噪声词),然后训练模型区分正样本和负样本。
python 复制代码
import torch
import torch.nn.functional as F
def nce_loss(pos_score, neg_scores, num_neg_samples):
    """
    计算NCE损失
    :param pos_score: 正样本的得分(来自目标分布)
    :param neg_scores: 负样本的得分(来自噪声分布)
    :param num_neg_samples: 负样本数量
    :return: NCE损失
    """
  
    # 正样本的损失,sigmoid对正样本得分
    pos_loss = F.logsigmoid(pos_score)
    
    # 负样本的损失,sigmoid对负样本得分,取负
    neg_loss = F.logsigmoid(-neg_scores).sum(dim=-1)
    
    # 计算总损失
    total_loss = -(pos_loss + neg_loss) / num_neg_samples
    return total_loss.mean()  # 返回平均损失
 
# 假设 pos_score 是正样本得分,neg_scores 是负样本得分(来自噪声分布)
pos_score = torch.randn(batch_size, 1)  # 正样本得分
neg_scores = torch.randn(batch_size, num_neg_samples)  # 负样本得分
num_neg_samples = 5  # 负样本数量
# 计算NCE损失
loss = nce_loss(pos_score, neg_scores, num_neg_samples)
  • 三、手撕AUC
预测为1 预测为0
真实label=1 (正类) True Positive (TP) False Negative (FN)
真实label=0 (负类) False Positive (FP) True Negative (TN)

精确率(Precision) : Precision = T P T P + F P \text{Precision} = \frac{TP}{TP + FP} Precision=TP+FPTP
召回率(Recall) : Recall = T P T P + F N \text{Recall} = \frac{TP}{TP + FN} Recall=TP+FNTP
F1分数(F1-Score) : F1-Score = 2 × Precision × Recall Precision + Recall \text{F1-Score} = 2 \times \frac{\text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}} F1-Score=2×Precision+RecallPrecision×Recall
真正率(TPR)/ 召回率 : T P R = T P T P + F N TPR = \frac{TP}{TP + FN} TPR=TP+FNTP
假正率(FPR) : T P R = F P F P + T N TPR = \frac{FP}{FP + TN} TPR=FP+TNFP

通过绘制不同阈值下TPR 和 FPR 就可以得到ROC曲线,AUC就等于ROC曲线和X轴之间的面积。但实际上AUC有一个更为常用的定义:随机从正样本和负样本中各选一个,分类器对于该正样本打分大于该负样本打分的概率。基于计算AUC的代码可以写为

python 复制代码
def cal_auc_1(label, pred):
    numerator = 0    # 分子
    denominator = 0  # 分母
    for i in range(len(label) - 1):
        for j in range(i, len(label)):
            if label[i] != label[j]:
                denominator += 1
                # 统计所有正负样本对中,模型把相对位置排序正确的数量
                r = (label[i] - label[j]) * (pred[i] - pred[j])
                if r > 0:
                    numerator += 1
                elif r == 0:
                    numerator += 0.5
    return numerator / denominator
  • 四、算法题:力扣53题 最大子数组和
    这道题可以直接双循环暴力求解,考试想不起还是可以用用的
python 复制代码
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        ans = nums[0]
        for i in range(len(nums)):
            for j in range(i, len(nums)):
                ans = max(ans, sum(nums[i:j+1]))
        return ans
        
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        size = len(nums)
        if size == 0:
            return 0
        dp = [0 for _ in range(size)]

        dp[0] = nums[0]
        for i in range(1, size):
            if dp[i - 1] >= 0:
                dp[i] = dp[i - 1] + nums[i]
            else:
                dp[i] = nums[i]
        return max(dp)   
相关推荐
databook4 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar5 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780515 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_5 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
CoovallyAIHub7 小时前
开源的消逝与新生:从 TensorFlow 的落幕到开源生态的蜕变
pytorch·深度学习·llm
数据智能老司机12 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机13 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i13 小时前
drf初步梳理
python·django