ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ViT深度拆解:从Patch Embedding到位置编码,彻底读懂视觉Transformer

ViT深度拆解:从Patch Embedding到位置编码,彻底读懂视觉Transformer 这篇文章是2020年Google Brain团队发表在ICLR上的里程碑式工作核心就一句话把图片切成16x16的网格每个网格当作一个“词”喂给标准的Transformer encoder做图像分类。这篇博文不会停留在“翻译论文”的表面我会结合我自己啃论文、跑代码的实操体会把这篇论文从设计动机、架构细节、实验解读到复现注意点全部摊开讲顺便把论文翻译中最容易踩的术语坑也一起梳理掉。适合刚入门Transformer视觉应用的研究生、做CV工程落地的算法工程师以及想把论文真正“读懂”而不是只“读过”的同学。1. 为什么这篇论文能“封神”视觉Transformer的起点1.1 背景与动机CNN统治下的视觉江湖在VIT出现之前计算机视觉几乎是卷积神经网络CNN的天下。从AlexNet到ResNet再到EfficientNet卷积的归纳偏置——局部感受野、权重共享、平移等变性——一直被视作视觉任务的天然后验。这套设计在ImageNet这种百万级数据上表现优异似乎“卷积”就是视觉理解的不二法门。但另一边NLP领域的Transformer已经在BERT、GPT等模型上证明了自己的统治力纯注意力机制Attention能够建模长距离依赖不依赖任何序列结构先验只需海量数据配合大规模预训练就能不断变强。两边的反差很耐人寻味CV社区总觉得注意力只是卷积的“补充”——把这层理解为“CNN负责提特征、注意力负责捕捉长程关系”几乎成为当时的标配做法。VIT这篇论文的核心问题意识就是我们能不能不靠卷积直接拿一套标准的Transformer来做图像分类而且在大规模数据下取得不输甚至超过CNN的效果。这个提问在今天看来稀松平常但在2020年之前没人系统证明过。更关键的是这个做法不依赖任何图像特化的结构设计Pipeline就是“切块-展平-接Transformer”极其简洁。1.2 标题里的16x16到底是什么论文标题直接给出了答案“An Image is Worth 16x16 Words”。它把图像的“词”定义为16x16像素的图像块patch。以标准输入224x224分辨率为例切成16x16的patch后一共得到(224/16)^2 14x14 196个patch每个patch展平后送入线性投影层生成一个patch embedding。这196个“词”再加上一个用于分类的class token最终序列长度是197。这个设计最大的意义是“对齐”图像处理从此不再是卷积的二维操作而是变成了一个序列处理问题。它把NLP里被验证过的整套Transformer基建position embedding、multi-head attention、LayerNorm、MLP block原封不动搬过来相当于给视觉和语言架了一座桥。从这篇论文开始视觉和语言任务的模型架构区别几乎被抹平。2. 架构细节深度拆解VIT到底做了什么2.1 Patch Embedding图像如何变成词向量Patch Embedding是VIT的第一步也是整个架构里最应该“吃透”的模块。它的实现有两种等价的方式。第一种是直接切patch再展平。假设输入图片尺寸是224x224x3切成16x16的patch每个patch展平得到16x16x3768维的向量。接着用一个可训练的线性层把768维映射到D维比如Base模型的D768。这个线性层的权重就是论文里的E矩阵维度是(D, 768)。第二种方式更取巧直接用卷积实现。一个卷积核大小为16x16、步长stride16、输出通道数为D的卷积层一步就能得到14x14xD的特征图再展平空间维度就是196xD的patch embedding序列。两种做法数学等价但卷积实现在GPU上效率更高这也是后来很多复现代码用conv2d来做patch embedding的原因。import torch.nn as nn class PatchEmbed(nn.Module): def __init__(self, in_channels3, patch_size16, embed_dim768): super().__init__() self.proj nn.Conv2d( in_channels, embed_dim, kernel_sizepatch_size, stridepatch_size ) def forward(self, x): # x: (B, 3, H, W) x self.proj(x) # (B, D, H/p, W/p) x x.flatten(2) # (B, D, num_patches) x x.transpose(1, 2) # (B, num_patches, D) return xflatten之后多了一个维度交换很多人第一次看代码会懵但本质就是把“特征图”摊平成“序列”。需要注意的是patch切分是硬切相邻patch之间没有重叠因此不会额外引入平滑假设。这也是VIT和后来Swin Transformer做窗口重叠设计的关键区别之一。2.2 class token的定位与作用图像切成了196个patch序列进入Transformer encoder后模型该怎么输出一个图像级别的分类结果VIT借鉴了BERT里[CLS] token的做法在patch序列最前面拼接一个可学习的class token。训练时class token对应的输出向量会通过自注意力机制聚合全局信息最终接到一个MLP Head做分类。class token的初始值是可学习参数而不是从图像里“算”出来的。这意味着模型需要自己学会“怎么读取这个位置的表示”。它与所有patch做注意力交互之后就相当于一个“动态池化”的全局表征。为什么不用全局平均池化论文在消融实验里做过验证class token和全局池化两者表现接近但class token在概念上更贴近NLP语义且便于后续适配视觉-语言类任务。在实际工程里两者差距确实不大但既然论文选的是class token复现时最好保持结构一致。输入Transformer前的完整序列是class token的embedding拼接上196个patch embedding总共197个token每个token的维度是D。别看这只是“多加一个向量”它直接决定了整个序列的长度也就是自注意力的计算复杂度以序列长度的平方膨胀。2.3 Position Embedding给序列补上空间信息Transformer本身是置换等变的把输入token的顺序打乱输出的结果不会变。这在NLP里问题不大语言有语序信息但需要位置编码来补充但图像的空间结构对视觉理解至关重要——左上角的patch和右下角的patch在语义上完全不同。所以VIT必须给每个token额外加一个位置编码。VIT这篇论文使用的是“可学习的1D位置编码”也就是直接把位置索引映射为一个可训练向量。虽然patch本身是二维空间上的14x14网格但论文实验发现1D位置编码和2D位置编码把行、列拆分编码效果几乎一样。原因也很简单对于Transformer来说它只依赖绝对位置和相对位置的注意力关系而图像patch间的相对距离无论1D还是2D编码都能学习出来。这个结论后来被大量研究验证过但寸有所长2D类位置编码在后续Swin、MAE等工作里依然很流行。位置编码在后续“分辨率迁移”任务里会变成一个大坑patch数量一变预训练好的位置编码就和输入对不上了。VIT的做法是对位置编码做2D插值把14x14的grid resize到新分辨率对应的grid然后进行微小地微调。这个细节我在第5章会展开讲。2.4 Transformer Encoder内部细节核心block结构是LayerNorm - Multi-Head Self-Attention - 残差 - LayerNorm - MLP - 残差。这个顺序叫Pre-LN和原始Transformer的Post-LN有个明显的区别LayerNorm放在子层之前。Pre-LN的梯度更稳定深层模型训练时不容易出现梯度爆掉的问题VIT的Large、Huge模型能稳定训练到位很大程度上得益于这个设计。Multi-Head Self-Attention的计算不复杂输入序列经过三个线性层得到Q、K、V然后计算Q和K的点积、缩放、softmax得到注意力权重再对V加权求和。head数量在Base模型里是12每个head的维度为64head拼接后过一层输出线性层。自注意力的计算复杂度是O(n^2·d)n197对日常分类完全没问题但到了检测、分割这种需要高分辨率特征图的任务上n会变成几千几万复杂度就会爆炸。这也是为什么后续Deformable DETR要设计稀疏注意力Swin要搞窗口注意力。MLP block里包含两个线性层和GELU激活hidden size通常是embedding dim的4倍。Base模型的D768hidden就是3072。这个比值的直觉解释是先让模型在更高维空间做非线性变换再压缩回原维度类似一个“思考再总结”的过程。Dropout在MLP和注意力里都加了默认是0.1左右。3. 论文翻译的核心难点术语、长句与图表表达3.1 关键术语的翻译与取舍对照表翻译论文最怕的不是句子长而是术语处理不当。中文社区对同一术语的翻译其实长期没有统一标准这里给出我自己的处理方案同时兼顾学术准确性和阅读流畅性英文术语建议翻译说明Patch图像块 / 图块尽量不要音译成“补丁”在视觉Transformer语境下“图像块”更顺后续说“切块”也自然Token词元 / 标记如果追求和NLP统一用“词元”视觉语境里“标记”同样常见关键是一篇博文里别混用Embedding嵌入向量 / 嵌入不必强行翻译成“向量化”在中文论文笔记里保留“embedding”原词也非常常见Inductive Bias归纳偏置经典翻译不要翻成“先验偏好”容易引起误解Class Token分类标记保留token也行但中文说明里搭配“分类token”最好懂Position Embedding位置编码和位置嵌入混用均可推荐“位置编码”简洁且沿用NLP界习惯Fine-tuning微调不要翻成“精调”术语统一更重要Transfer Learning迁移学习无争议Mixed Resolution混合分辨率指预训练低分辨率、微调高分辨率的训练策略Few-shot少样本近年来常见“小样本”也越来越多建议紧跟最新习惯Image Recognition图像识别但更精确地说VIT当前做的其实是“图像分类”翻译时按上下文选择End-to-End端到端无争议翻译原则上有几条硬要求所有模型名VIT-Base、VIT-Large、ResNet、数据集名ImageNet、JFT-300M一律保留原文不翻译所有“层”Layer、Block、Head在首次出现时给中文注释后续统一用英文缩写或者中文都行但必须全局一致。3.2 长难句实战拆解以论文摘要为例论文翻译最痛苦的是遇到长难句尤其NLP和CV论文经常出现嵌套从句。拿VIT摘要里最典型的这句“当在中等规模数据集如ImageNet上训练时如果不使用强正则化VIT的准确率会比同等规模的ResNet低几个百分点这是可以理解的Transformer缺少CNN固有的归纳偏置例如平移等变性和局部感受野因此在数据量不足时难以有效泛化。”翻译这句的逻辑是先拆出主干“VIT的准确率比ResNet低”再补条件“在中等规模数据集上训练且不强正则化”最后解释原因“缺少归纳偏置”。翻译成中文时要把因果链条理顺不能按照英文定语从句的顺序逐字翻。再举一个Intro里的经典句子“仅将标准Transformer直接应用于图像块在中等规模数据集上表现不如预期。” 这里的“directly applied”语气很重要翻译时不能丢“直接”二字因为这句话其实是在暗示“我们并没有做额外的图像特化设计”这正是论文的卖点。实际翻译过程中我习惯先断句再用中文讲故事的方式重排绝对不要被英文语序绑架。翻译的目的不是字对字的机械对应而是把“作者为什么这么说”的逻辑准确传达出来。3.3 图表表述图1、图4和表2的信息转译论文翻译只翻文字是远远不够的好的翻译还包括对图表的信息转译。比如图1是VIT的架构总览图左半部分是Patch Embedding流程中间是Transformer Encoder模块右半部分是MLP Head。翻译时不能只说“图1展示了VIT结构”应把关键信息用文字提炼出来——输入图如何变为序列、序列长度是多少、每个模块的职责是什么。这样才能帮助不看图的读者建立完整心理模型。图4更重要它可视化了训练好的位置编码。把位置编码向量按每个patch还原成空间grid然后观察不同位置编码之间的相似度。VIT学出来的位置编码具有明显的空间平滑性相邻patch的编码相似度高远处位置编码相似度低同时还有明显的行、列结构。这说明模型确实在位置编码里学到了“二维空间邻近性”——尽管训练时使用的是1D编码。这个图的信息翻译成文字就是“模型自发学会了空间结构且编码按行、列呈现规律性”。表2不同模型在ImageNet上的效果对比表在翻译时建议整理成更适合中文读者阅读的简化表格模型名、预训练数据、分辨率、Top-1 Accuracy四列即可。重点不是逐列翻而是提炼“同规模下Transformer超过CNN”这个增量信息。4. 实验与结论为什么VIT能在大规模数据下赢4.1 从ViT-Base到ViT-Huge模型规模怎么配数据规模VIT论文本身提供了三种模型配置区别主要是embedding维度、层数和head数量模型层数(L)隐层维度(D)Head数参数量预训练数据ViT-Base127681286MImageNet-1k / 21k / JFTViT-Large24102416307MImageNet-21k / JFTViT-Huge32128016632MJFT-300M这里最核心的实验结论是“三档数据的cross结果”在ImageNet-1k约128万张图上直接训练VIT的效果不如同规模的ResNet。因为Transformer缺少卷积的归纳偏置小数据量下学不到足够的视觉先验。在ImageNet-21k约1400万张图上预训练后迁移到ImageNet-1kVIT和ResNet旗鼓相当。在JFT-300M约3亿张图上预训练后迁移VIT-Large和ViT-Huge全面超越ResNet族包括BiT-L等强基线并且在多个下游数据集上刷新SOTA。这组实验给出了一个非常明确信号Transformer的“可扩展性”是它的核心优势。CNN在数据量增大时性能提升会逐渐变缓而VIT似乎还远没有到饱和。所以VIT的贡献不只是一个新backbone更是在告诉整个视觉社区如果你们能搞到海量数据纯Transformer会成为视觉识别的最强架构。4.2 训练细节与超参数隐含的工程经验论文里还有很多容易忽略的训练细节。VIT在ImageNet-1k上直接训练时用了90个epoch学习率warmup cosine decay优化器是AdamWbatch size是4096weight decay相对较大。在ImageNet-21k上预训练是30个epochJFT上则只训了7个epoch因为数据量太大。这些数字看起来平平无奇但实际复现时直接影响收敛效果。比较关键的工程细节是“混合分辨率微调”预训练分辨率通常是224x224微调分辨率可能提到384x384或512x512。分辨率提高后patch数量增加模型需要插值位置编码并微调。TensorFlow实现里有专门的“resize_pos_embed”逻辑PyTorch复现时也要处理这个插值。这个技巧后来几乎所有视觉Transformer工作都继承了算是VIT留下的“遗产”之一。另一个关键细节是数据增强。论文强调VIT在中等数据上训练时对强正则化非常敏感包括RandAugment、Mixup、CutMix等。从直觉上解释Transformer比CNN更需要数据多样性来弥补归纳偏置不足所以强增强对VIT既是“解药”也是“毒药”——如果不能配合足够的训练轮数模型很容易过拟合但一旦配好效果提升非常明显。4.3 和Deformable DETR的横向对比同一条技术路线的不同方向在做论文翻译和整理的时候很多人会把VIT和Deformable DETR放在一起看。前者解决图像分类后者解决目标检测但背后是同一个核心思路“用注意力替代/改造卷积的多层级结构”。Deformable DETR引入了可变形注意力只在稀疏的关键采样点上做attention大幅降低特征图高分辨率下的计算量。它和VIT的注意力机制有一个本质区别VIT做的仍然是“全token密集注意力”而Deformable DETR是“稀疏可变形采样”。这两篇论文放在一起对比能看到Transformer在视觉任务上演进的两种典型路径一种是“尽量沿用标准Transformer用数据弥补先验”另一种是“针对视觉任务特点修改注意力机制”。后来的DeiT、Swin、DINO、MAE基本都没走出这两条路。所以翻译VIT时如果能顺带理解Deformable DETR的设计动机对整个Transformer视觉应用脉络会掌握得更牢。5. 实操心得从“翻译完”到真正学会VIT5.1 我总结的高效论文阅读与翻译流程很多人拿到论文就从头逐字翻译结果翻到方法部分就崩溃了。我的习惯是“三遍法”第一遍只读标题、摘要、结论和所有图表标题搞懂这篇论文做了什么、效果如何、图和表分别对应什么信息。这一遍花20分钟足够判断这篇论文是否值得细读。第二遍细读方法部分同时画架构草图。不用翻译全文只需要把关键模块、关键公式、结构图用自己的话复述一遍发现哪里说不清楚再回原文去查。这一遍是真正“理解论文”的阶段。第三遍再回到实验部分把图表和正文结合着读分析结论为什么成立有没有消融实验支撑。翻译工作放在第二遍和第三遍之间做方法部分精细翻译实验部分可以先做可视化和表格整理结论部分翻译大意即可。这样既保证翻译质量又不至于陷入逐句翻的低效陷阱。5.2 复现VIT时最常踩的坑直接抱一个开源的VIT代码库跑好像很简单但真要自己动手还是有一些需要注意的第一位置编码插值的实现要小心。从224分辨率迁移到384时14x14的位置编码要先变成16x16或者24x24很多人直接resize结果空间形状和patch grid对不上模型效果断崖式下跌。正确做法是先用F.interpolate在grid维度上做双线性插值再flat成序列。第二class token在注意力计算时不能混淆。许多初学者会在patch embedding之后直接加class token但忘记调整attention mask或者位置编码的数量。好在这篇论文用的是全连接注意力没有mask问题但后续接Detection头时容易出bug。第三数据增强策略不要拍脑袋。直接在ImageNet-1k上按论文里的超参强增强大批量大weight decay跑loss会降到一定程度后不收敛而且validation曲线会出现震荡。最稳妥的方式是先从轻量增强RandAugment强度低一点、无Mixup开始跑通流程再加复杂度。第四VIT对小学习率更敏感。因为需要在大batch下保持泛化推荐warmup至少设10个epochcosine decay周期要覆盖完整训练轮数。我试过直接上0.003的学习率从头训练ViT-Baseloss前期非常不稳定只有降到0.001附近才恢复正常。5.3 延伸阅读VIT开启的后续版本迭代学完VIT之后顺着这条线往下看会非常“丝滑”DeiT解决数据量不足的问题引入知识蒸馏和更强的数据增强在ImageNet-1k上直接训练也能超越CNN。Swin引入层次化设计和窗口注意力解决高分辨率场景下自注意力复杂度爆炸的问题成为检测分割任务的事实标准主干。DINO自监督版本的VIT通过自我蒸馏学习特征在密集任务和图像检索上表现极强。MAE遮挡自编码器用75%的patch masked重建策略把VIT的自监督潜力发挥得淋漓尽致。如果想把VIT论文笔记做得更深建议把位置编码可视化、注意力头部行为的分析也一起做了如果是为了工程落地则优先关注distillation和Swin这些“更擅长小数据高分辨率”的方向。这几次实践下来我最大的感觉是翻译一篇论文真正的收获不在于把英文变成中文而在于逼着自己把每个概念讲清楚。VIT之所以值得精读恰恰是因为它“结构简单、思想明确”——翻译一遍基本就能把Transformer在视觉上的核心逻辑吃透之后再读任何变体都会轻松很多。
返回列表