2022年4月8日字节跳动机抖音APP推荐实习面试题

1、AUC是什么?如何计算AUC?

    AUC:随机取一个正样本和一个负样本,正样本的预测值大于负样本预测值的概率。

    AUC计算的关键是找到所有正样本预测值大于负样本预测值的正负样本对。

    首先,需要将样本按照预测值进行从小到大排序(最小score对应的sample的rank为1,第二小score对应sample的rank为2,以此类推);

    其次,把所有的正类样本的rank相加,再减去两个正样本组合的情况。

2、AUC线上线下不一致怎么办

    线上线下效果不一致,大概率是由线上线下预估环境不一致引起。 预估环境,一般涉及2个要素:模型和特征。

    模型是否一致

    主要包括校验离线模型格式转换、serving部署,线上模型加载、预估等接口是否有问题

    特征是否一致

    准确是指,线上线下喂给模型的特征是否一致。

    与模型一致性检验一样,首先需要校验线上线下特征处理逻辑是否一致等;

    其次,与线上真实预估环境相比,离线环境更容易获取到特征,当离线使用线上获取不到的特征时,就会造成离线效果虚高的假象。

    严重点的,如特征穿越,即特征中包含标签信息,会造成训练和评估时数据泄露,导致离线评估时AUC虚高;轻一点的,如离线使用的特征比线上实时性高,同样会导致线上效果不符合预期。

    这就要求离线阶段构造样本时,需要参考线上真实预估环境获取特征时的延迟,通过严格控制离线特征拼接时的咬合时间,保证线下线下喂给模型的特征的一致性。

    更好地做法是,落地线上特征日志,直接用于离线训练。

    AUC指标不能有效刻画模型表现。可以尝试GAUC代替。

3、召回阶段的负采样是怎么做的?

    第一版i2i在batch内随机负采样,并加了bias进行修正;第二版u2i借鉴w2v,以uv曝光为权重,全局负采样,但是由于全局负彩成本太大,做了二次哈希,根据样本uv进行了分桶;

    加bias有什么用?
    答:负采样的本质是想打压高曝光item,但是由于高曝光的item本身就频繁出现在样本中,随机采可能会打压过头,因此加一个bias tower进行修正(其实就是学一个值取平衡正负样本)。

    带权负采样的逻辑?
    答:如果按照uv曝光进行带权负采样,就是先按照uv曝光排序,之后累加,最后生成一个随机数,看着随机数落到哪两个item的uv累加和(前缀和)区间,就采样哪个item。

4、FM,DeepFM跟FFM的对比

    FM主要解决了LR不能主动学习特征交叉组合问题;解决特征稀疏,特征交叉,权重矩阵稀疏学习困难问题;解决特征交叉组合,模型参数量过大,复杂度高问题。

    FFM相比FM基础上,引入了Field-aware,每个特征在每个field上有对应不同的隐向量。

    DeepFM是一个端到端的学习模型,DeepFM将FM的隐向量V VV同时作为Deep的词向量参数,两者共享,让模型自动去学习低阶与高阶的特征交互。

5、手撕FM的训练过程

def FM_function_L2_Adagrad(dataMatrix, classLabels, k, iter):
    lamda = 1 #正则化参数
    m, n = shape(dataMatrix)
    alpha = 1
    #1、初始化参数
    w = zeros((n, 1))
    w_0 = 0.
    v = normalvariate(0, 0.2) * ones((n, k))
    w0_ada = 1.
    w_ada = 1.
    v_ada = 1.
    w0_grad = 0.
    w_grad = 0.
    v_grad = 0.
    alpha_w0 = alpha
    alpha_w = alpha
    alpha_v = alpha
    
    #2、训练
    for it in range(iter):
        for x in range(m):
            inter_1 = dataMatrix[x] * v
            inter_2 = multiply(dataMatrix[x], dataMatrix[x]) * multiply(v, v)
            #完成交叉项
            interaction = sum(multiply(inter_1, inter_1) - inter_2) / 2.   
            p = w_0 + dataMatrix[x] * w + interaction  
            loss = classLabels[x] * p[0, 0] - 1        
            #加入adagrad
            w0_grad += (loss* classLabels[x] +w_0*lamda) ** 2  
            w_0 -= alpha_w0 * (loss* classLabels[x] *+w_0*lamda)          
            for i in range(n):
                if dataMatrix[x, i] != 0:                 
                    #加入adagrad
                    w_grad += (loss* classLabels[x] +w[i, 0]*lamda) ** 2  
                    w[i, 0] -= alpha_w * (loss* classLabels[x] * dataMatrix[x, i] + w[i, 0]*lamda)                    
                    for j in range(k):
                        #加入adagrad
                        v_grad += (loss * classLabels[x]* (dataMatrix[x, i] * inter_1[0, j] - v[i, j] * dataMatrix[x, i] * dataMatrix[x, i]) + v[i, j]*lamda) ** 2  
                        v[i, j] -= alpha_v * (loss  *classLabels[x] * (dataMatrix[x, i] * inter_1[0, j] - v[i, j] * dataMatrix[x, i] * dataMatrix[x, i]) + v[i, j]*lamda)  
        w0_ada = np.sqrt(w0_grad)  
        w_ada = np.sqrt(w_grad)  
        v_ada = np.sqrt(v_grad)
        alpha_w0 = alpha/w0_ada
        alpha_w = alpha/w_ada
        alpha_v = alpha/v_ada
    return w_0, w, v

6、Leetcode—64. 最小路径和

class Solution(object):
    def minPathSum(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        m = len(grid) 
        n = len(grid[0]) 
        dp = [[0] * n for _ in range(m)]
        dp[0][0] = grid[0][0]
        for i in range(1, m):
            dp[i][0] = grid[i][0] + dp[i-1][0]
        for j in range(1, n):
            dp[0][j] = grid[0][j] + dp[0][j-1]
        for i in range(1, m):
            for j in range(1,n):
                dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j]
        return dp[-1][-1]

7、剑指 Offer 10- I. 斐波那契数列

class Solution:
    def fib(self, n: int) -> int:
        cur, nxt = 0, 1
        for _ in range(n):
            cur, nxt = nxt, cur + nxt
        return cur % 1000000007

8、Leetcode—215. 数组中的第K个最大元素

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        left, right, target = 0, len(nums) - 1, k -1
        while True:
            pos = self.partition(nums, left,right)
            if pos == target:
                return nums[pos]
            elif pos > target:
                right -= 1
            else:
                left += 1
    def partition(self, nums, left, right):
        tmp = nums[left]
        while left < right:
            while left < right and nums[right] <= tmp:
                right -= 1
            nums[left] = nums[right]
            while left < right and nums[left] >= tmp:
                left += 1
            nums[right] = nums[left]
        nums[left] = tmp
        return left
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七月在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值