📱 刷抖音的时候,算法正在用 DFS 和向量"刷"你

0 阅读9分钟

写在前面:今天学了两件看似毫不相关的事——深度优先搜索(DFS)算法,和抖音推荐算法的底层原理。结果越学越发现,这两者居然有千丝万缕的联系!抖音用多模态模型把视频变成 512 维向量,再用各种算法筛选推荐——而 DFS,就是很多底层算法的"老祖宗"。


一、DFS 深度优先搜索:一条路走到黑,再回头

1.1 什么是 DFS?

老师给的定义很简洁:

"沿着一条分支一路遍历到底,回溯后再探索其余分支的图/树遍历算法。"

想象你在一个迷宫里探险:

  • 你选一条路,一直往前走,直到走不通(死胡同)。
  • 然后回头,回到上一个分叉口,选另一条路继续走。
  • 重复这个过程,直到所有路都走过一遍。

这就是 DFS——Depth First Search,深度优先搜索。

1.2 递归实现:代码只有 8 行

function dfs(root, res = []) {
    if (!root) return res; // 退出条件:走到头了
    res.push(root.val);    // 记录当前节点
    dfs(root.left, res);   // 往左走到底
    dfs(root.right, res);  // 往右走到底
    return res;
}

这段代码做了什么?

  1. 退出条件:如果当前节点为空(!root),说明走到头了,返回结果。
  2. 记录当前节点:把当前节点的值加入结果数组。
  3. 递归左子树:往左边走,重复步骤 1-3。
  4. 递归右子树:左边走完了,再往右边走,重复步骤 1-3。

这就像你逛商场:

  • 进了一家店(push 记录)。
  • 先逛左边所有分店(dfs(root.left))。
  • 左边逛完了,再逛右边所有分店(dfs(root.right))。
  • 所有店都逛完了,回家(返回结果)。

1.3 迭代实现:用栈模拟递归

递归虽然简洁,但有个问题——栈太深会爆栈。所以老师还教了迭代版本:

function dfsPreOrderIter(root) {
    if (!root) return [];
    const stack = [root];
    const res = [];
    while (stack.length) {
        const node = stack.pop();
        res.push(node.val);
        // LIFO:先右后左,这样左子树先被处理
        if (node.right) stack.push(node.right);
        if (node.left) stack.push(node.left);
    }
    return res;
}

核心思路:用栈(Stack)代替递归调用栈。

  • 栈是 LIFO(后进先出)。
  • 先把根节点入栈。
  • 出栈一个节点,记录它的值。
  • 先把右子节点入栈,再把左子节点入栈。
  • 这样下一次出栈的是左子节点——先左后右,和递归的顺序一致。

这就像你整理书桌:

  • 把书一本一本叠起来(入栈)。
  • 拿的时候从最上面拿(出栈)。
  • 最后放上去的书,最先被拿走。

1.4 DFS 和树遍历的关系

老师还提到了一个关键联系:

"先序遍历为例:A -> B -> D -> C -> E"

二叉树的前序遍历,本质上就是 DFS。

遍历方式顺序本质
前序遍历根 → 左 → 右DFS
中序遍历左 → 根 → 右DFS
后序遍历左 → 右 → 根DFS
层序遍历一层一层扫BFS(广度优先)

DFS 和 BFS 是图/树遍历的两种基本策略,前序/中序/后序遍历只是 DFS 在二叉树上的三种具体实现。


二、抖音推荐算法:你在刷抖音,抖音在"刷"你

2.1 用户画像:你被打上了无数标签

老师一句话让我脊背发凉:

"我们在刷手机,手机在刷我们。"

抖音怎么"刷"你?用户画像 + 标签系统。

你每天刷的视频,会被打上各种标签:

  • 唱跳、NBA、新闻、科技、美食、萌宠……
  • 每天几千万用户产生的新视频数据,都会被分析。

这些标签不是简单的"有"或"没有",而是多维度向量——比如 512 维:

[
    0.85,  // 科技(你很感兴趣)
    0.05,  // 幽默(不太感兴趣)
    0.03,  // 西语(几乎不感兴趣)
    ...    // 一共 512 个维度
]

每个维度代表一个兴趣标签,数值代表感兴趣的程度。 0.85 表示"非常喜欢科技类视频",0.03 表示"对西语视频无感"。

2.2 点积和余弦相似度:算你和视频的"缘分"

老师提到了两个数学概念:

  • 点积操作(Dot Product):衡量两个向量的相似程度。
  • 余弦相似度(Cosine Similarity):计算两个向量夹角的余弦值,越接近 1 越相似。

抖音用这些运算,算出你和每个视频的"匹配度"。 匹配度高的视频,优先推荐给你。

这就像相亲:

  • 你的兴趣向量是"喜欢科技、不喜欢跳舞"。
  • 视频 A 的向量是"科技类、硬核风格"→ 匹配度高 → 推荐!
  • 视频 B 的向量是"跳舞类、娱乐风格"→ 匹配度低 → 不推荐。

2.3 多模态模型:视频被"拆解"成 512 维向量

老师详细讲了抖音如何把视频变成向量——多模态模型

第一步:视觉特征提取

"逐帧提取 tensor。Vision Transformer(LLM 底层),以帧为单位去捕捉画面。"

AI 会"看"视频的每一帧:

  • 能认出是一只猫、一个程序员在写代码、一个寝室围着看世界杯。
  • 甚至通过画面的色彩、光影,判断视频的情绪基调——温暖治愈,还是冷酷硬核。

抖音视频数据量最大,机器学习 + 大数据训练,让 AI 越来越懂视频。

第二步:音频特征提取

"通过 ASR 技术,把配音变成文本。文本 NLP 自然语言处理,语义分析。声音大小、情绪。"

AI 还会"听"视频的声音:

  • ASR(自动语音识别)把语音转成文字。
  • NLP 分析文字的语义和情绪。
  • 分析背景音乐的风格、节奏。

最终输出:512 维向量

视觉特征 + 音频特征,最终合并成一个 512 维的向量。这个向量就是视频的"DNA"——包含了视频的所有关键信息。


三、推荐漏斗:从 1000 万视频到 10 条推荐

3.1 第一步:召回——双塔模型广撒网

"双塔模型广撒网,千人千面。1000 万视频 → 1000 条。"

召回阶段的目标:从海量视频里,快速筛出可能感兴趣的 1000 条。

怎么做?

  • 用户的兴趣向量 和 视频的向量 做点积运算。
  • 计算余弦相似度,找出最相关的 1000 条。

这就像大海捞针——先拿磁铁在海边扫一扫,把含铁的东西都吸上来。

3.2 第二步:粗排——轻量模型快速筛选

"用相对轻量的机器学习模型,算一些粗的内部特征。从 1000 条筛选为 300 条。"

粗排阶段用更精细的模型,考虑更多因素:

  • 视频质量、作者权重、发布时间……
  • 从 1000 条进一步筛选到 300 条。

3.3 第三步:精排——预测你的行为

"预测点不点击、完播的概率、点赞、评论、分享。"

精排阶段是最核心的,用一个公式算"推荐分":

score = w1 × 点击 + w2 × 完播 + w3 × 点赞 + w4 × 评论 + w5 × 分享
  • w1w5 是权重,表示每个行为的重要性。
  • 模型预测你对每个视频的这些行为概率。
  • 得分最高的视频,排在最前面。

这就像老师给你打分:平时作业 30%、期中考试 30%、期末考试 40%——加权算总分。

3.4 第四步:重排——防止你"审美疲劳"

"如果前十名都是你爱看的 AI 视频,重排机制会强制打散。每两个硬核内容,强制加入一个跳舞视频,防止产生疲劳。"

重排阶段有两个策略:

策略说明比喻
Explore(探索)偶尔推荐一些你平时不看的类型野外求生,多停留 3 秒,一个全新的兴趣标签被记录下来
Exploit(利用)主要推荐你感兴趣的内容投其所好,让你刷得停不下来

Explore 和 Exploit 的平衡,是推荐系统的艺术。 太 Exploit 了,你会审美疲劳;太 Explore 了,你会觉得"抖音怎么老给我推我不爱看的东西"。

这就像你吃饭:

  • 天天吃你最爱吃的菜 → 吃腻了(需要 Explore)。
  • 天天给你吃没见过的菜 → 你可能不喜欢(需要 Exploit)。
  • 最好的方案: mostly 爱吃的 + occasionally 新尝试。

四、DFS 和推荐算法的联系:看似无关,实则相通

学到这里,我突然发现一个有趣的联系:

DFS 算法抖音推荐算法
沿着一条分支走到底沿着一个兴趣标签深挖
回溯后探索其他分支Explore 机制引入新兴趣
用栈/递归实现用向量运算 + 机器学习实现
遍历所有节点遍历所有视频

推荐算法的本质,也是一种"搜索"——在海量内容中,搜索最适合你的那部分。 DFS 是计算机科学中最基础的搜索算法之一,而推荐系统则是搜索算法在工业界的"超进化版"。


五、总结:算法正在悄悄改变你的世界

知识点说明
DFS深度优先搜索,一条路走到黑再回头
递归 DFS代码简洁,但有爆栈风险
迭代 DFS用栈模拟递归,更安全
用户画像用多维度向量描述用户兴趣
多模态模型视觉 + 音频 → 512 维向量
余弦相似度衡量用户和视频的匹配度
推荐漏斗召回 → 粗排 → 精排 → 重排
Explore/Exploit探索新内容 vs 利用已知兴趣

刷抖音的时候,你以为自己在选择内容,实际上算法正在选择你。 512 维向量、双塔模型、精排公式、重排机制……这些冷冰冰的算法,正在决定你每天看到什么、喜欢什么、甚至成为什么样的人。

但了解这些算法的原理,至少能让你从"被刷"变成"懂刷"——知道为什么抖音总给你推某种视频,也知道自己该如何主动探索新内容。


写在最后

今天最大的收获,是理解了推荐系统的全貌。从 DFS 这种基础算法,到抖音这种工业级推荐系统,底层逻辑都是"搜索"和"匹配"。算法本身没有好坏,关键在于怎么用。

下次面试官问你:"DFS 和 BFS 有什么区别?"

你可以淡定地说:

"DFS 是深度优先,沿着一条分支走到底再回溯,适合找路径、解迷宫;BFS 是广度优先,一层一层遍历,适合找最短路径。在二叉树中,前序/中序/后序遍历都是 DFS,层序遍历是 BFS。实际工程中,递归实现 DFS 代码简洁但可能爆栈,迭代实现用栈模拟更安全。"

然后看着面试官满意的表情,心里默念:这波,又稳了。


本文所有代码示例均来自课堂学习资料,真实可运行。