想象一下这样的场景:你走进一个画廊,看到一位大师正在临摹一幅名画。不过,这位大师的做法很特别——他不是按顺序一笔一笔画,而是先把画切成了许多小块,随机翻起其中一些块,然后只看着周围的线索,努力猜出那些被盖住的块上画着什么。他这样做完全不需要别人告诉他答案,只需要把猜出来的结果和原画对比一下,就能知道自己猜得对不对。日复一日,这位大师练就了一双“火眼金睛”——即使只看到画面的冰山一角,也能精准还原整体结构,甚至迁移到从来没见过的画作上,画出令人惊叹的原创作品。 这个场景就是今天要讲的 BEiT(BERT Pre-Training of Image Transformers) ——一种让机器学会“看”的深度学习方法。它跟这位大师的做法如出一辙:把图像切成小块,随机盖住一部分,然后让模型根据周围可见的线索,预测被盖住区域的“图像单词”(视觉Token),从而学会理解图像的深层结构和语义。这种技术属于视觉自监督预训练,它不需要任何人工标注,只需要海量的原始图片,就能训练出强大的视觉表示——就像临摹大师不需要旁人指点,只需一屋子名画供他观摩一样。 学完本文,你将深入理解 BEiT 的图像分块掩码策略、视觉 Token 预测方法、变分自编码器(VAE / dVAE)在其中的角色、与 MAE 的对比,以及如何将预训练模型迁移到下游任务。这套知识是计算机视觉研究者必知的进阶素养,更是你驾驭 Vision Transformer 生态、开展自监督学习实践的核心能力。有了它,你就不再是一个只会调库的“调包侠”,而是一个真正懂视觉表示学习原理的工程师。 ---

岗位关联

需要学习BEiT图像Token,CV研究建立在深度学习之上,理解ViT/Diffusion是前沿。本篇涵盖CNN/RNN/Transformer、反向传播、正则化、训练技巧,帮助你理解深度模型原理与调优。

目录
  1. 可视化演示
  2. 视觉自监督预训练
  3. 图像分块与掩码
  4. 视觉Token与码本
  5. dVAE预训练
  6. BEiT预训练目标
  7. BEiT与MAE对比
  8. 下游任务迁移
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示BEiT的核心机制,通过基础/核心/应用/扩展四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

BEiT:BEiT BEiT图像分块与掩码策略详解 视觉Tokenizer与VQ- 核心机制可视化 BEiT整体架构与关键组件

视觉自监督预训练

还记得画廊里那位临摹大师吗?他学习的方式很特别——一屋子画作摆在他面前,没有老师在旁边指点“这块颜色应该更深、那条线应该更弯”,完全靠自己去观察、猜测、比对,然后自我修正。这种“无师自通”的学习方式,正是自监督学习(Self-Supervised Learning)的精髓。所谓自监督,就是从数据本身构造出“练习题”,让模型自己出题、自己答题、自己对答案,完全不需要人工标注。

在视觉领域,传统的监督学习需要给每张图片贴标签,比如“这是一只猫”“那是一条狗”。但互联网上每天产生数以亿计的图片,让人类去给它们一一标注,成本高得惊人。视觉自监督预训练的思路,是把这些海量无标注的图片直接当作学习材料,通过设计巧妙的“代理任务”(Pretext Task)——比如我们故事里的“翻块猜图”——模型在完成这个任务的过程中,被迫去理解图像的纹理、形状、语义等深层结构。这些理解被压缩成网络的参数,就形成了通用视觉表示。

这个“通用”二字至关重要。就像大师学会的不仅是一幅画的画法,而是整个绘画的底层规律——光影怎么处理、构图怎么安排、色彩怎么搭配——模型的通用表示也可以迁移到各种具体任务上。下游任务迁移(如分类、检测、分割)正是这个思路的落地:把预训练好的模型拿过来,用少量带标注的数据“微调”一下,就能在新任务上取得很好的效果,哪怕新任务和预训练任务差异很大。整个过程就像大师学完名画后去画任何原创作品都得心应手,不需要从头学起。

预训练模型的去向是下游任务。以下游任务视角理解,见“对比学习与自监督学习”篇的课程定位。

回到我们的大师故事:他花费了大量时间临摹各种名画,练就了深厚的绘画功底。这之后,无论让他画人物、风景还是静物,他都能画得比初学者好得多——因为他的“基本功”(通用视觉表示)已经扎扎实实。BEiT 的目标,就是成为这位基本功扎实的“大师”。

自监督预训练⟶通用视觉表示→微调下游任务\text{自监督预训练} \longrightarrow \text{通用视觉表示} \xrightarrow{\text{微调}} \text{下游任务}
这个流程揭示了 BEiT 的战略定位:预训练阶段通过大量无标注数据学得底层视觉规律,下游阶段以少量标注快速迁移到具体任务。
  1. 自监督预训练利用无标注图像数据,通过自构造的代理任务训练模型,是视觉模型摆脱人工标注依赖的根本途径。
    自监督预训练=代理任务(掩码+重建)\text{自监督预训练} = \text{代理任务(掩码+重建)}
  2. 通用视觉表示模型在预训练中把图像的结构和语义知识编码为参数,形成可复用的特征表达。
    通用表示⟷不是任务特化,而是通用底座\text{通用表示} \longleftrightarrow \text{不是任务特化,而是通用底座}
  3. 下游任务微调将预训练权重作为初始化,在目标任务上用少量标注数据继续训练,实现能力迁移。
    θ下游=θ预训练+少量梯度更新\theta_{\text{下游}} = \theta_{\text{预训练}} + \text{少量梯度更新}

图像分块与掩码

大师临摹时,并没有把整幅画当作一个不可拆分的整体来死记硬背。他观察到一个技巧:把画作均匀地切成大小一致的小方格,然后一张一张地研究每个格子里的内容。这种“切块”的做法,就是 BEiT 中图像分块(Patch)的由来。

具体来说,BEiT 首先把一张 \(224 \times 224\) 的输入图像切分成 \(16 \times 16\) 大小的图像块(Patch),一共得到 \(14 \times 14 = 196\) 个块。每个 Patch 通过线性映射(Linear Projection)展平并嵌入成一个向量,然后送入 Transformer 编码器。这个思路继承了 Vision Transformer(ViT)的设计——把图像当成“单词序列”来处理,而 Patch 就相当于视觉领域的“单词”。

有了图像块之后,关键操作来了:随机掩盖。BEiT 借鉴了 BERT 的掩码语言模型(Masked Language Model)思想,随机选择其中大约 40% 的 Patch 将其遮盖(替换为一个特殊的 [MASK] 标记向量)。模型的任务,就是只看剩余的 60% 可见块,去推断被遮盖块的内容。这里有个细节:BEiT 使用的是块状掩码(Blockwise Masking)——遮盖的区域倾向于连续成块,而不是像撒盐一样均匀稀疏分布。这样做是刻意的:如果只遮稀疏的单个小点,模型轻松用周围邻居的相似像素就能“混过去”,而块状掩码强迫模型理解更高层的语义信息,才能做出正确预测。这就像玩拼图时,如果想练真本事,就不该给你一堆几乎一模一样的蓝天碎片,而应该把一整块天空都翻过去,强迫你通过云朵、建筑等更宏观的线索来判断位置。

图像→切割196 个 Patch→随机遮盖 40%掩码图像序列\text{图像} \xrightarrow{\text{切割}} 196 \text{ 个 Patch} \xrightarrow{\text{随机遮盖 40\%}} \text{掩码图像序列}

1. 图像切割成 Patch:输入图像被均匀切分成 \(16 \times 16\) 的小块,类比书籍被拆分成一个个句子。

Patches=224×22416×16=196\text{Patches} = \frac{224 \times 224}{16 \times 16} = 196

2. 线性嵌入:每个 Patch 展平后通过线性层映射为一个高维向量,类比查词典把单词映射为词向量。

ei=Linear(Flatten(Patchi))\mathbf{e}_i = \text{Linear}(\text{Flatten}(\text{Patch}_i))

3. 随机遮盖 40%:从 196 个 Patch 中随机选约 78 个遮盖为特殊标记,类似英语完形填空中挖去部分单词。

被遮盖数≈196×40%≈78\text{被遮盖数} \approx 196 \times 40\% \approx 78

大师的策略看似简单却极其有效:他不看整幅画的全貌,而是强迫自己在信息残缺的条件下进行推理。这种“缺什么补什么”的训练,比从头到尾照抄一遍更能锻炼对画面深层结构的理解。BEiT 通过这种掩码策略,让模型学会了“脑补”缺失信息,而这个“脑补”能力,正是通用视觉理解的核心。

视觉Token与码本

大师在做“翻块猜图”的练习时,遇到一个关键问题:当他把一个格子翻过来时,究竟该猜什么?格子里的像素有成千上万个,如果要求他一模一样地画出每个像素的颜色和亮度,这是一项极其苛刻的任务——不同照片的光照、角度千差万别,精确重建像素根本没有意义。更聪明的做法是:把图像内容抽象为有限个“图案类别”,只要猜中这个格子属于哪一类图案,就算赢了。

这正是 BEiT 的核心理念——视觉 Token(Visual Token)。BEiT 首先训练一个离散变分自编码器(dVAE),将图像块映射到一组离散的编码(Token)上。学术界的标准做法是使用一个包含 8192 个条目的码本(Codebook)——一张“图像单词表”。每个图像块经过 dVAE 编码器编码后,从这 8192 个离散条目中选出自己对应的那一个。这个被选中的条目编号(比如“第 2471 号”),就是这个块的视觉 Token。

这个过程,相当于给图像做了一次“分词”。类比中文里的“词”——汉语有成千上万个字和词,但浩瀚的文章都由这些基本词汇组合而成。同样地,自然图像虽然无穷无尽,但 dVAE 的码本相当于归纳出了 8192 种“视觉单词”。任何图像块,都可以用这 8192 个单词之一来表示。当 BEiT 模型预测一个被遮盖块的 Token 时,它实际上是在做“完形填空”:这里应该是哪个词?是在 8192 个候选词中做选择——本质是一个分类问题。

所以,BEiT 预训练的目标函数不是让模型重建像素值,而是预测被遮盖 Patch 对应的离散 Token ID。这看起来像是一个简化,实则是升华:因为离散 Token 已经是在语义层面抽象过的表示,预测 Token 就是让模型做跨语义层次的推理。注意区分的是,dVAE 训练和 BEiT 预训练是两阶段:先单独训练 dVAE 拿到码本和分词能力,再用它把图像切成 Token 序列,最后在 Token 序列上做 BEiT 的掩码预测训练。

zi=qϕ(pi)∈{1,2,…,8192}\mathbf{z}_i = q_{\phi}(\mathbf{p}_i) \in \{1, 2, \ldots, 8192\}

1. dVAE 编码器:将像素级图像块 \(\mathbf{p}_i\) 编码为连续潜在变量,再通过 Gumbel-Softmax 松弛为离散的 Token 分布。

z~i∼qϕ(zi∣pi)\tilde{\mathbf{z}}_i \sim q_{\phi}(\mathbf{z}_i \mid \mathbf{p}_i)

2. 码本查表:从码本 \(\mathbf{C} = \{\mathbf{c}_1, \ldots, \mathbf{c}_{8192}\}\) 中选出离散 Token \(\mathbf{z}_i\)。

zi=arg⁡max⁡k  z~i,k\mathbf{z}_i = \arg\max_k \; \tilde{\mathbf{z}}_{i,k}

3. Token 序列化:每个 Patch 得到一个 Token ID,整张图像就变成了一个 Token 序列——图像完成“分词”。

图像⟹{z1,z2,…,z196}\text{图像} \Longrightarrow \{\mathbf{z}_1, \mathbf{z}_2, \ldots, \mathbf{z}_{196}\}

大师对着“图像单词表”反复练习:现在他的目标不再是画出那个格子的每个像素,而是判断“这个位置是眼睛、是树皮还是羽毛”。这个“判断”的过程,让他的大脑从琐碎的像素记忆中解放出来,专注在更高级的抽象推理上。BEiT 的巧妙之处,正在于它不要求模型做最难的事(像素重建),而是让它做最有价值的事(语义推断)。

dVAE预训练

要拥有“图像单词表”,第一步是“编词典”——这就是 dVAE 的使命。dVAE(discrete Variational AutoEncoder,离散变分自编码器)是一个两段式结构:一个编码器(Encoder)把图像块映射为离散 Token,一个解码器(Decoder)再把这些 Token 还原为原始图像。它做的事情,可以类比为“先把一段话压缩成几个关键词,再根据这几个关键词还原整段话”。

训练 dVAE 时,输入是一张完整的图像。编码器将图像压缩为一个离散的隐变量网格(Token 网格),解码器仅凭这个 Token 网格重建整张图像。如果重建成功——解码器输出的图像和原图高度相似——说明 Token 网格确实保留了图像的绝大部分关键信息。这就好比让学生读一篇文章后提炼出 100 个关键词,再用这些关键词让另一个学生复述原文。如果复述得很完整,说明这 100 个关键词“信息量足够”,是一套优秀的摘要体系。

但这里有个工程难题:编码器输出的是一个离散的 Token ID,而离散变量不可导,梯度无法从解码器回传到编码器。解决方法是使用 Gumbel-Softmax 松弛(Gumbel-Softmax Relaxation)——在训练时用一个连续分布来近似离散采样,同时保持可导性。简单来说,Gumbel-Softmax 让“选词”这个看似不可微的离散操作变得可以训练,就像用逐渐冷却的硬糖代替了瞬间凝固的冰块,既保持了表面的硬度(离散),又能慢慢塑形(可导)。

dVAE 的训练目标是最大化证据下界(ELBO),其中包括两项:重建损失(像素级差异)和 KL 正则项(让 Token 分布均匀、码本利用率高)。训练完成后,dVAE 的解码器部分即被舍弃,只保留编码器和码本,作为后续 BEiT 预训练的“分词器”。

LdVAE=Eqϕ(z∣x)[−log⁡pθ(x∣z)]+β⋅DKL(qϕ(z∣x) ∥ p(z))\mathcal{L}_{\text{dVAE}} = \mathbb{E}_{q_{\phi}(\mathbf{z}|\mathbf{x})}\left[-\log p_{\theta}(\mathbf{x}|\mathbf{z})\right] + \beta \cdot D_{\text{KL}}\left(q_{\phi}(\mathbf{z}|\mathbf{x}) \,\|\, p(\mathbf{z})\right)

1. 编码器映射离散 Token:编码器网络 \(q_{\phi}\) 将图像 \(\mathbf{x}\) 映射为离散潜变量 \(\mathbf{z}\)。

z∼qϕ(z∣x)\mathbf{z} \sim q_{\phi}(\mathbf{z} \mid \mathbf{x})

2. 解码器重建图像:解码器 \(p_{\theta}\) 从离散 Token 恢复像素图像,重建损失衡量还原质量。

x^=pθ(x∣z)\hat{\mathbf{x}} = p_{\theta}(\mathbf{x} \mid \mathbf{z})

3. Gumbel-Softmax 松弛:用连续分布逼近离散采样,使梯度可以反向传播。

yi=exp⁡((log⁡πi+gi)/τ)∑jexp⁡((log⁡πj+gj)/τ)\mathbf{y}_i = \frac{\exp((\log \pi_i + g_i)/\tau)}{\sum_{j} \exp((\log \pi_j + g_j)/\tau)}

4. KL 正则项:鼓励 Token 分布均匀,避免所有图像块都集中到少数几个 Token 上。

DKL(qϕ ∥ p(z))=∑kqϕ(z=k)log⁡qϕ(z=k)p(z=k)D_{\text{KL}}(q_{\phi} \,\|\, p(\mathbf{z})) = \sum_k q_{\phi}(\mathbf{z}=k) \log \frac{q_{\phi}(\mathbf{z}=k)}{p(\mathbf{z}=k)}

编词典的过程是枯燥但必要的。大师花费大量时间反复做“压缩与还原”训练,最终得到了那本 8192 个单词的“图像词典”。之后,这本词典就被固定下来,成为他日后拼图练习的参考工具。dVAE 在 BEiT 中扮演的正是“词典编纂者”的角色——它本身不是主角,但没有它,后面的掩码预测训练就无从谈起。

BEiT预训练目标

编剧们常说,最好的剧本是“意料之外,情理之中”。BEiT 的预训练目标与此异曲同工:它给模型一张被挖去 40% 的残缺图像,让模型用可见部分去推断被掩码区域的 Token。这个任务需要模型综合全局上下文——物体的形状、纹理、空间关系、颜色一致性——才能产生正确的预测。一个纯靠“抄邻居像素”的小把戏在这个任务上行不通,因为被遮盖的是整个图像块,而不是零星像素。

在架构上,BEiT 使用 Vision Transformer(ViT)作为骨干网络。输入序列由三部分组成:被掩码块的 [MASK] 向量、可见块的 Patch 嵌入向量,以及每个位置的位置编码(Position Embedding)。这些向量一起送入 L 层 Transformer 编码器,编码器通过多头自注意力(Multi-Head Self-Attention)在序列内部交换信息——每个位置都能“看到”其他所有位置的信息。最终,每个 [MASK] 位置对应输出一个特征向量,这个向量被送入一个分类头(Classification Head),输出一个 8192 维的分布向量,表示每个 Token 被选中的概率。

训练目标采用交叉熵损失(Cross-Entropy Loss):让模型对每个被掩码位置的预测分布,尽可能匹配 dVAE 提前给出的真实 Token ID。

LBEiT=−∑i∈Mlog⁡pθ(zi∗∣x\M)\mathcal{L}_{\text{BEiT}} = -\sum_{i \in \mathcal{M}} \log p_{\theta}(\mathbf{z}_i^{\ast} \mid \mathbf{x}_{\backslash \mathcal{M}})

其中 \(\mathcal{M}\) 是被掩码的位置集合,\(\mathbf{z}_i^{\ast}\) 是第 \(i\) 个 Patch 的真实 Token ID。直观理解:对每个被遮盖的位置,模型输出的概率分布中,“正确答案”那一项的概率应该尽可能高。

pθ(zi∗∣x\M)=Softmax(Head(TransformerL(E\M+⊕e[MASK])))p_{\theta}(\mathbf{z}_i^{\ast} \mid \mathbf{x}_{\backslash \mathcal{M}}) = \text{Softmax}\left(\text{Head}\left(\text{Transformer}_L\left(\mathbf{E}_{\backslash \mathcal{M}}^+ \oplus \mathbf{e}_{[\text{MASK}]}\right)\right)\right)

1. 输入序列拼接:可见 Patch 嵌入和 \([MASK]\) 嵌入混合排列,加上位置编码后送入编码器。

H0=[e1+p1,…,e[MASK]+pi,…]\mathbf{H}_0 = \left[\mathbf{e}_1 + \mathbf{p}_1, \ldots, \mathbf{e}_{[\text{MASK}]} + \mathbf{p}_i, \ldots\right]

2. L 层 Transformer 编码:每层执行多头自注意力(MHA)和前馈网络(FFN),使每个位置聚合全局信息。

Hl=FFN(MHA(Hl−1))\mathbf{H}_{l} = \text{FFN}\left(\text{MHA}\left(\mathbf{H}_{l-1}\right)\right)

3. 分类头预测:每个掩码位置的输出特征经过线性层映射到码本大小维度,再经 Softmax 得到概率。

pi=Softmax(Wh⋅hiout)\mathbf{p}_i = \text{Softmax}\left(\mathbf{W}_h \cdot \mathbf{h}_i^{\text{out}}\right)

4. 交叉熵损失:对每个掩码位置,计算真实 Token 的负对数概率并求和。

L=−∑i∈Mlog⁡pi[zi∗]\mathcal{L} = -\sum_{i \in \mathcal{M}} \log \mathbf{p}_i\left[\mathbf{z}_i^{\ast}\right]

大师反复进行“翻块猜词”的练习:每次翻开 40% 的块,看着剩下的 60% 线索,从那本 8192 词的词典中选出最合适的单词。刚开始他经常猜错,但每次对答案时,他逐渐总结了规律——天空的块往往对应某个 Token,毛发的纹理对应另一个 Token。成千上万次训练之后,他一看到零散的拼图线索,脑海中就自动浮现出完整的画面。此时,模型内部已经沉淀了丰富的视觉语义知识,这正是 BEiT 想获得的通用视觉表示。

BEiT与MAE对比

拼图训练法在 AI 圈子里迅速流行起来,但不同“门派”对于“猜什么”有着截然不同的观点。其中最有名的一派就是 MAE(Masked Autoencoder,掩码自编码器)。MAE 与 BEiT 共享“掩码重建”的基本框架,但在关键的“预测目标”上分道扬镳。

BEiT 预测的是离散 Token(“这里应该填哪个单词”);MAE 预测的是原始像素值(“这里应该填什么颜色”)。两者的差异可以直接类比为两种学习方式:BEiT 的学生回答问题“这幅画的局部属于哪种意象类别?”,而 MAE 的学生回答问题“这个方格里的 RGB 值是多少?”——前者更高层、更语义化,后者更底层、更像素化。此外,MAE 通常使用 75% 的高掩码比例,并且采用非对称编码器-解码器设计(编码器只处理可见块,解码器处理完整序列),而 BEiT 使用 40% 掩码,编码器直接处理全部序列。

BEiT 与 MAE 在损失函数、组件与掩码比例上的对比总结:

两种方法各有侧重:BEiT 因为预测 Token,更早地在语义层面做推理,在需要高层语义的任务(如图像分类)上常常表现优异;MAE 因为预测像素,保留了更细粒度的空间信息,在需要精确重构的领域也很有优势。在实际评测中,BEiT 在 ImageNet 分类上表现出色,而 MAE 在分割、检测等任务上也非常强大。

LMAE=1∣M∣∑i∈M∥x^i−xi∥2\mathcal{L}_{\text{MAE}} = \frac{1}{|\mathcal{M}|}\sum_{i \in \mathcal{M}} \left\| \hat{\mathbf{x}}_i - \mathbf{x}_i \right\|^2

大师的两名学徒分别实践了两种策略:一个学“看局部猜类别”(BEiT),一个学“看局部猜像素”(MAE)。多年之后发现,前者形成了更好的人脸识别能力(语义层面),后者在临摹笔触纹理时表现得更加细腻(细节层面)。两者都说不上绝对优劣,关键看你想让模型成为“理论派”还是“写实派”。如果目标是小样本分类的快速学习,BEiT 通常更值得选择;如果要像素级精确生成和密集预测,MAE 可能更贴合需求。

BEiTMAE预测目标离散 Token(dVAE)原始像素(连续值)损失函数交叉熵均方误差掩码比例40%75%编码器输入全部 Patch仅可见 Patch解码器轻量分类头轻量 Transformer\begin{array}{lcc}\hline& \text{BEiT} & \text{MAE} \\\hline\text{预测目标} & \text{离散 Token(dVAE)} & \text{原始像素(连续值)} \\\text{损失函数} & \text{交叉熵} & \text{均方误差} \\\text{掩码比例} & 40\% & 75\% \\\text{编码器输入} & \text{全部 Patch} & \text{仅可见 Patch} \\\text{解码器} & \text{轻量分类头} & \text{轻量 Transformer} \\\hline\end{array}
简单说:BEiT 背“词汇表”,MAE 背“像素值”。两者都在预训练中学习环境规律,但“学什么”的取舍决定了各自特有的优势。
  1. 预测目标差异BEiT 最小化 Token 交叉熵——答案是离散的类别;MAE 最小化像素均方误差——答案是连续的数值。
    LBEiT=−log⁡p(z∗)vs.LMAE=∥x^−x∥2\mathcal{L}_{\text{BEiT}} = -\log p(z^{\ast}) \quad \text{vs.} \quad \mathcal{L}_{\text{MAE}} = \|\hat{x}-x\|^2
  2. 掩码比例差异BEiT 用 40% 块状掩码,MAE 用 75% 高比例随机掩码,后者让模型面对更大的信息缺失挑战。
    Mask Ratio: 40%(BEiT)    vs.    75%(MAE)\text{Mask Ratio: } 40\% \text{(BEiT)} \;\; \text{vs.} \;\; 75\% \text{(MAE)}
  3. 架构分工差异BEiT 在完整序列上端到端计算;MAE 将可见部分编码后再补全解码,架构不对称。
    \text{BEiT: Encoder(全序列)} \quad \text{MAE: Encoder(可见)\to Decoder(全序列)}

下游任务迁移

大师学成之时,画廊迎来了一批新画作——有肖像素描、有山水油画、还有现代艺术拼贴画。这些画作与大师此前临摹的名画风格迥异,但大师依然能够应对自如。这就是预训练模型在下游任务中的真实写照:预训练阶段学到的是通用的视觉规律,下游任务只需要在这套规律之上做“针对性微调”。

在图像分类任务中,我们将 BEiT 预训练好的模型去掉分类头,换上一个随机初始化的类别预测头,然后在目标分类数据集上用较小的学习率微调整个网络。在目标检测任务中,BEiT 常与 Faster R-CNN 等检测框架结合作为骨干网络,通过端到端微调同时优化检测头与骨干。在语义分割任务中,BEiT 的 Transformer 架构天然适合作为分割模型(如 SETR)的编码器,每个 Patch 位置的特征经过解码器即可生成逐像素类别图。同时,也有研究者用线性探测(Linear Probing)来评估预训练质量——冻结骨干网络参数,只训练一个线性分类头。如果线性头就能达到高准确率,说明预训练特征是真正线性可分的,质量极高。

ftask(x)=(Headtask∘BackboneBEiT)(x)f_{\text{task}}(\mathbf{x}) = \left( \text{Head}_{\text{task}} \circ \text{Backbone}_{\text{BEiT}} \right)(\mathbf{x})

1. 换头:移除预训练的分类头,替换为适应目标任务的新分类/检测/分割头。

Headnew=RandomInit\text{Head}_{\text{new}} = \text{RandomInit}

2. 微调骨干:在目标任务上以较小学习率继续更新骨干参数,使之前的通用特征适配目标域。

θbackbone←θbackbone−η∇Ltask\theta_{\text{backbone}} \leftarrow \theta_{\text{backbone}} - \eta \nabla \mathcal{L}_{\text{task}}

3. 端到端联合训练:骨干与任务头同时训练,让特征与任务互相适应。

min⁡θB,θHLtask(HeadθH(BackboneθB(x)),y)\min_{\theta_{B}, \theta_{H}} \mathcal{L}_{\text{task}}\left(\text{Head}_{\theta_H}\left(\text{Backbone}_{\theta_B}(\mathbf{x})\right), y\right)

大师之所以能驾驭新画风,靠的不是对某一种画风的记忆,而是对绘画底层规律的深刻理解。BEiT 的预训练特征同样如此:它吸取的是跨任务的通用视觉知识,因此在面对新的分类类别、新的检测目标时,只需要极少量的标注数据就能快速适应。对于 AI 从业者来说,学会利用 BEiT 这类预训练模型进行迁移,意味着少标注、快迭代、高精度——事半功倍。

---

AI 应用场景

医学影像分类

阶段:预训练与迁移学习

解决的问题:医学影像标注依赖专家,成本极高,且分布差异大。传统监督学习需要成千上万张带标注的病理图像,这在医疗场景中常常不可得。

具体案例:一家 AI 医疗公司使用 BEiT 在 100 万张公开的未标注胸部 X 光片上做自监督预训练,然后用仅 2000 张标注乳腺癌图像微调。结果,微调模型的 F1 分数比从零训练的 ResNet 高出 12%。放射科专家可以快速获得一个“已经懂影像”的得力助手。

通用物体检测骨干

阶段:端到端微调

解决的问题:目标检测任务需要模型同时理解“是什么”和“在哪里”,传统预训练(如 ImageNet 分类)学到的特征对位置信息不够敏感。BEiT 的掩码重建预训练让模型天然具备更强的空间推理能力。

具体案例:某自动驾驶公司的感知团队以 BEiT 预训练模型作为 Faster R-CNN 的骨干网络,在 Cityscapes 数据集上微调。相比从零训练的基线,mAP 提升 4.8 个百分点,特别是在行人、自行车等小物体上的召回率显著提高。

智能农作物的语义分割

阶段:预训练 + 语义分割解码器

解决的问题:农业遥感图像的标注需要专家逐像素标注,极其耗时。同时,遥感图像与自然图像分布差异大,直接迁移 ImageNet 预训练模型效果有限。

具体案例:某农业科技公司用 BEiT 在 5000 张未标注的无人机遥感图像上继续预训练,然后使用 SETR 分割框架在 500 张标注图像上微调,实现了对农田中作物与杂草的精确分割,mIoU 达到 87.3%,远超从零训练的效果。

Python 演示

python91 行
"""BEiT-like 自监督掩码Token预测的简化演示 (NumPy实现核心思路)"""import numpy as np class SimpleBEIT:    def __init__(self, num_patches=16, vocab_size=128):        self.num_patches = num_patches        self.vocab_size = vocab_size        self.W_embed = np.random.randn(num_patches, 64) * 0.02        self.W_head = np.random.randn(64, vocab_size) * 0.02     def tokenize_image(self, image_patches, codebook):        """模拟 dVAE 分词: 每个 patch 找到最相近的码本项"""        tokens = []        for patch in image_patches:            dists = np.linalg.norm(codebook - patch, axis=1)            tokens.append(int(np.argmin(dists)))        return np.array(tokens)     def mask_patches(self, mask_ratio=0.4):        """随机遮盖 40% 的 patch 位置"""        num_masked = int(self.num_patches * mask_ratio)        mask_idx = np.random.choice(self.num_patches, num_masked, replace=False)        mask = np.zeros(self.num_patches, dtype=bool)        mask[mask_idx] = True        return mask     def forward(self, visible_tokens, visible_idx):        """简化前向: 用可见Token的均值池化预测掩码位置"""        if len(visible_tokens) == 0:            return np.zeros(self.vocab_size)        visible_embeds = self.W_embed[visible_idx]        pooled = np.mean(visible_embeds, axis=0)        logits = pooled @ self.W_head        return logits     def compute_loss(self, image_patches, codebook, mask_ratio=0.4):        """计算交叉熵损失: 预测被掩码的 Token"""        true_tokens = self.tokenize_image(image_patches, codebook)        mask = self.mask_patches(mask_ratio)        visible_idx = np.where(~mask)[0]        visible_tokens = true_tokens[visible_idx]        loss = 0.0        correct = 0        total = 0        for idx in np.where(mask)[0]:            logits = self.forward(visible_tokens, visible_idx)            probs = np.exp(logits - np.max(logits))            probs = probs / np.sum(probs)            pred = int(np.argmax(probs))            loss += -np.log(probs[true_tokens[idx]] + 1e-8)            correct += (pred == true_tokens[idx])            total += 1        return loss / total, correct / total  def synthetic_images(num=200, patch_dim=32, num_patches=16):    """生成合成图像(随机噪声+语义块)"""    images = []    for _ in range(num):        base = np.random.randn(patch_dim) * 0.5        patches = []        for _ in range(num_patches):            if np.random.rand() < 0.7:                patches.append(base + np.random.randn(patch_dim) * 0.1)            else:                patches.append(np.random.randn(patch_dim) * 1.0)        images.append(np.array(patches))    return np.array(images)  def main():    np.random.seed(42)    images = synthetic_images()    codebook = np.random.randn(128, 32) * 0.5    model = SimpleBEIT(num_patches=16, vocab_size=128)     for epoch in range(5):        total_loss = 0.0        total_acc = 0.0        for img in images:            loss, acc = model.compute_loss(img, codebook, mask_ratio=0.4)            total_loss += loss            total_acc += acc        avg_loss = total_loss / len(images)        avg_acc = total_acc / len(images)        print(f"Epoch {epoch+1}: loss={avg_loss:.4f}, acc={avg_acc:.4f}")    print("训练完成: 模型已学会根据可见Patch预测被掩码Patch的Token")  if __name__ == "__main__":    main()
目的:用 NumPy 实现 BEiT 的核心流程——dVAE 分词(简化版为最近邻码本匹配)、随机掩码 40% 的 Patch、交叉熵损失计算,演示自监督掩码 Token 预测的训练过程。
  1. def tokenize_image(self, image_patches, codebook)模拟 dVAE 的“图像分词”:每个 Patch 向量在 128 个码本项中找最近邻居,得到离散 Token ID
  2. def mask_patches(self, mask_ratio=0.4)实现 40% 随机遮盖策略,返回布尔掩码数组
  3. def forward(self, visible_tokens, visible_idx)用可见 Patch 的嵌入平均池化代表全局上下文,预测掩码位置的 Token 分布
  4. def compute_loss(self, image_patches, codebook, mask_ratio=0.4)对每个被掩码位置计算交叉熵损失,并统计预测准确率
  5. synthetic_images()生成带语义结构的合成图像(每个图像含一个“主题”加上部分噪声块),模拟真实图像中的语义一致性
  6. main()5 个训练轮次,观察损失下降与准确率上升,展示模型“学会预测”的过程

常见误区

误区BEiT 就是一个高级的“图像补全”工具,它的目标是把被掩码的部分恢复成和原图一模一样的像素值,类似于 Photoshop 的内容感知填充。

正解BEiT 并不预测像素,而是预测离散的视觉 Token。就像做英语完形填空时你要选出空白处的单词(Token),而不是一笔一画地描出字母(像素)。Token 是 dVAE 提前抽象好的语义类别(8192 选一),模型的任务是分类而非回归。像素层面的精确重建既困难又缺乏语义意义,而 Token 预测让模型集中精力在理解上下文关系上。这是 BEiT 与 MAE 最关键的区别之一。

为何常见:很多人把“自编码器”和“像素重建”先入为主地画上等号,忽视了“离散 Token 分类”这一中间抽象步骤。

误区dVAE 是 BEiT 的双塔结构之一,在预训练时和 Transformer 一起端到端联合优化。

正解dVAE 和 BEiT 是两阶段训练。先单独训练 dVAE(编码器+解码器),训练完成后抛弃解码器,只保留编码器和码本作为“分词工具”。BEiT 的 Transformer 编码器是在固定的 Token 序列上训练的,dVAE 的参数冻结不参与更新。这就像先请一位词典编纂者独立编好词典,再用这本固定的词典来教学生阅读——编词典阶段和教阅读阶段是分开的。

为何常见:神经网络常用“联合训练”范式深入人心,加之部分论文图示把 dVAE 和 BEiT 画在同一个流程中,容易让人误以为它们是端到端的一体化结构。

误区BEiT 和 MAE 在架构上几乎一样——编码器只处理可见 Patch,另外用一个小解码器来恢复被掩码的部分。

正解BEiT 的 Transformer 编码器直接处理包含 [MASK] 标记的完整序列,没有独立的解码器。被掩码位置的输出特征直接接一个轻量分类头预测 Token。相比之下,MAE 的编码器只处理可见 Patch,用一个轻量解码器在完整序列上重建像素。这个架构差异源于预测目标的不同:BEiT 的 Token 预测任务需要全局上下文做语义推理,所以让编码器直接看到掩码位置有助于学习位置相关特征;MAE 的像素重建更注重细粒度解码。

为何常见:BEiT 和 MAE 经常被放在一起讨论,很多人在迁移 MAE 的“不对称”架构印象时产生了混淆。

误区40% 和 BERT 的 15% 差不多是拍脑袋定的,换成 30% 或 50% 也差不多。

正解掩码比例是一个经过细致权衡的超参数。BEiT 使用 40% 的块状掩码,是因为:掩码过少(如 15%)会让任务过于简单,模型可以利用局部像素相似性轻易猜中,学不到语义;掩码过多(如 75%)会让可见信息不足以支撑语义推断,学习信号变弱。40% 是一个“恰到好处的缺口”——足以强迫模型推理,又不至于让任务不可解。相比之下,MAE 选择 75% 是因为其像素重建任务对信息量的需求与 Token 预测任务不同。

为何常见:超参数在论文中通常只占一行,小白容易忽视背后大量的消融实验(Ablation Study),误以为是随意设定。

误区视觉 Token 就是 Patch 经过线性投影后得到的嵌入向量,只是换了个名字。

正解两者有本质区别。Patch 嵌入(Patch Embedding)是把 \(16 \times 16\) 像素块经过线性层投影得到的连续向量,它是 Transformer 的输入;视觉 Token 是 dVAE 编码器把 Patch 映射到码本(8192 项)后的离散 ID(一个整数),它是预训练阶段的目标标签。打个比方:Patch 嵌入是机器翻译里的“源语言词向量”,视觉 Token 是“目标语言单词”。模型读入源语言词向量,输出目标语言单词——两者处在不同的语义空间。

为何常见:两者都在描述“图像块变成某种表示”,名称里又都带"Token",极易混淆。许多教程对这两个概念的区分不够醒目。

面试题

Q1. BEiT 的预训练目标本质上是以下哪种任务?

单选题 · mid

  • A.像素级回归任务
  • B.离散 Token 分类任务← 正确答案
  • C.图像风格迁移任务
  • D.图像检索排序任务

答案:B。BEiT 对每个被掩码的 Patch,从 8192 个视觉 Token 中预测正确的那一个,这是标准的分类任务。A 是 MAE 的像素回归策略;C 和 D 与 BEiT 毫无关系。

Q2. 下列哪些属于 BEiT 的两阶段训练流程?

多选题 · mid

  • A.先训练 dVAE 获得码本← 正确答案
  • B.再用 dVAE 对图像分词生成 Token← 正确答案
  • C.Transformer 在 Token 序列上掩码预测← 正确答案
  • D.在 Token 序列上做像素重建

答案:ABC。BEiT 先训练 dVAE,随后用它的编码器把图像块映射为离散 Token,之后 Transformer 在这些 Token 序列上做掩码预测。D 是 MAE 的做法,不是 BEiT 的目标。

Q3. BEiT 中的视觉 Token 是什么?

单选题 · easy

  • A.Patch 的像素平均值
  • B.码本中的离散条目编号← 正确答案
  • C.Transformer 最后一层输出
  • D.图像的高频纹理特征

答案:B。视觉 Token 是 dVAE 将 Patch 映射后,在 8192 项码本中匹配到的离散条目 ID,相当于图像的“单词”。B 正确。A 是粗暴降采样,C 是编码器的输出特征,D 是信号处理概念。

Q4. BEiT 使用的掩码比例和掩码方式是什么?

单选题 · mid

  • A.75%,随机散点
  • B.15%,连续块状
  • C.40%,块状掩码← 正确答案
  • D.50%,间隔带状

答案:C。BEiT 采用约 40% 的块状掩码(Blockwise Masking),强迫模型用高层语义线索推理。75% 随机散点是 MAE 的设置,15% 是 BERT 的设置,带状掩码并非 BEiT 采用的方法。

Q5. dVAE 在 BEiT 中扮演什么角色?

单选题 · easy

  • A.最终分类器
  • B.图像分词器← 正确答案
  • C.特征增强器
  • D.掩码生成器

答案:B。dVAE 训练完成后其编码器与码本被用作“图像分词器”,把连续像素块转为离散 Token ID。它不参与最终的分类决策,也不做特征增强或掩码生成。

Q6. 关于 BEiT 与 MAE 的区别,以下哪些说法正确?

多选题 · hard

  • A.BEiT 预测离散 Token,MAE 预测连续像素← 正确答案
  • B.BEiT 使用交叉熵损失,MAE 使用均方误差损失← 正确答案
  • C.BEiT 编码器输入含掩码块,MAE 编码器仅输入可见块← 正确答案
  • D.BEiT 掩码比例高于 MAE

答案:ABC。BEiT 预测离散 Token(交叉熵),MAE 预测像素(MSE),两者掩码比例分别是 40% 和 75%,因此 D 错误。BEiT 的编码器直接处理含掩码标记的完整序列,MAE 编码器只接收可见块,C 正确。

Q7. 为什么 BEiT 采用块状掩码而非均匀散点掩码?

单选题 · hard

  • A.块状掩码更容易实现
  • B.散点掩码可以被邻近像素“蒙混过关”← 正确答案
  • C.块状掩码能提升训练速度
  • D.散点掩码会导致模型退化

答案:B。散点掩码下模型可通过插值邻近相似像素来猜中,无需理解语义。块状掩码遮住大片连续区域,迫使模型从更宏观的上下文线索推理,学到语义级表征。A、C、D 都与实际动机不符。

Q8. BEiT 预训练后的模型如何用于图像分类任务?

单选题 · easy

  • A.直接输出分类结果,无需修改
  • B.更换分类头后微调整体网络← 正确答案
  • C.冻结所有层,仅用随机特征
  • D.重新从零训练全部参数

答案:B。标准迁移流程是移除预训练分类头、换上新的分类头并对整个网络在小学习率下微调。A 不可能(类别数不匹配),C 是线性探测的做法,D 丢弃了预训练的价值。

Q9. 以下哪些是 BEiT 的视觉码本特征?

多选题 · mid

  • A.包含 8192 个离散条目← 正确答案
  • B.通过 dVAE 学习得到← 正确答案
  • C.直接随机初始化固定
  • D.提供离散视觉词汇← 正确答案

答案:ABD。码本包含 8192 个可学习的离散条目(A),通过 dVAE 训练得到(B),提供图像的“离散词汇表”(D)。码本不是随机固定的(C 错误),它经过训练优化。

Q10. BEiT 的最终预训练损失函数形式是?

单选题 · hard

  • A.对所有 Patch 计算 MSE 损失
  • B.仅对被掩码 Patch 计算交叉熵← 正确答案
  • C.对所有 Patch 计算交叉熵
  • D.对被掩码 Patch 计算 KL 散度

答案:B。BEiT 只对被掩码位置(40% 的 Patch)计算交叉熵损失,督促模型将正确 Token 的概率最大化。A 是 MAE 的损失形式,C 的比例不对,D 的 KL 散度用于 dVAE 正则项而非 BEiT 主损失。