Vizuara-多模态大模型与-Transformers-笔记-全-
Vizuara 多模态大模型与 Transformers 笔记(全)
001:从零开始编写Swin Transformer
在本节课中,我们将从零开始编写一个Swin Transformer模型。上一节我们介绍了Swin Transformer的架构及其与Vision Transformer的区别。本节我们将专注于代码实现。
概述
Swin Transformer是一种通用的、基于Transformer的图像处理架构。论文中展示了它在图像分类、目标检测和语义分割等任务上的应用。本节课我们将聚焦于图像分类任务。
架构回顾
Swin Transformer的架构如图所示。输入图像的高度为H,宽度为W,通道数为C(例如,对于MNIST数据集,C=1)。模型首先将图像分割成不重叠的图像块。
以下是处理流程:
- 图像被分割成大小为2x2的块。
- 每个块通过一个线性嵌入层,将通道数从48投影到指定的嵌入维度C。
- 随后是多个重复的Swin Transformer阶段(Stage)。
- 每个阶段内部包含两种核心模块:常规窗口Transformer块和移位窗口Transformer块。
需要注意的是,图中未显示Transformer块之后的处理流程。实际上,上下文向量会经过全局平均池化层,然后才连接到分类头(一个全连接网络)。这部分结构会根据具体任务(分类、检测或分割)进行调整。
核心概念:注意力机制
在Swin Transformer中,注意力计算是核心。标准的注意力权重计算公式如下:
alpha_ij = softmax( (Q_i * K_j^T) / sqrt(d) )
其中,alpha_ij是查询向量Q_i和键向量K_j之间的注意力权重,d是向量的维度。上下文向量通过将注意力权重与值向量V相乘得到。
然而,Swin Transformer对此进行了修改:
- 常规窗口多头自注意力:在标准注意力公式的基础上,增加了一个相对位置偏置项
B_ij。公式变为:
alpha_ij = softmax( (Q_i * K_j^T) / sqrt(d) + B_ij ) - 移位窗口多头自注意力:在常规窗口注意力的基础上,引入了掩码项
mask_ij。这是为了阻止属于不同窗口的图像块之间相互计算注意力。公式变为:
alpha_ij = softmax( (Q_i * K_j^T) / sqrt(d) + B_ij + mask_ij )
除了注意力计算部分,Swin Transformer块的其他组件(如层归一化、多层感知机、残差连接)与标准Transformer保持一致。
输入处理流程
让我们以MNIST数据集为例,具体说明输入图像的处理过程。MNIST图像是单通道(黑白)的,尺寸为28x28。


单个图像的原始形状为 (C, H, W),即 (1, 28, 28)。在批处理中,我们会增加一个批次维度B。假设批次大小为2,那么输入张量的形状就是 (B, C, H, W),即 (2, 1, 28, 28)。
处理的第一步是图像块嵌入。这通常通过一个二维卷积层(nn.Conv2d)来实现。例如,可以使用以下代码:
nn.Conv2d(in_channels=1, out_channels=48, kernel_size=2, stride=2)
参数解释如下:
in_channels=1:输入图像的通道数(MNIST为1)。out_channels=48:输出通道数,对应Swin Transformer架构中图像块嵌入后的通道数。kernel_size=2:卷积核大小,决定了每个图像块的大小为2x2。stride=2:步长为2,确保生成不重叠的图像块。
经过这个卷积操作后,输入图像被转换为图像块。原始图像在高度和宽度上分别被分割成 H/2 和 W/2 个块,因此总的图像块数量为 (H * W) / 4。对于28x28的MNIST图像,将得到 (28*28)/4 = 196 个图像块。

每个图像块的形状从 (1, 2, 2) 变为 (48, 1, 1)。这意味着空间维度被压缩,而通道维度增加到了48。这为后续的Transformer处理做好了准备。


总结

本节课我们一起回顾了Swin Transformer的核心架构,重点讲解了其独特的窗口注意力机制(包括常规窗口和移位窗口),并详细分析了输入图像从原始格式到图像块嵌入的整个处理流程。理解这些基础概念对于后续的代码实现至关重要。下一节,我们将开始动手编写Swin Transformer的各个模块。
002:Swin Transformer 原理与代码实现
在本节课中,我们将要学习Swin Transformer架构。这是一种对之前学习的Vision Transformer和Data-efficient Image Transformer的自然扩展,旨在解决Vision Transformer在处理高分辨率图像时计算复杂度高的问题。
上一节我们介绍了Vision Transformer的基本工作原理,本节中我们来看看Swin Transformer如何通过巧妙的“窗口”和“移位”机制,在保持强大建模能力的同时,显著降低计算开销。
课程概述

Swin Transformer是微软亚洲研究院在2021年提出的重要工作,论文引用量超过38,000次。它首次令人信服地证明了Transformer架构可以作为通用视觉任务(如分类、检测、分割)的强大骨干网络。然而,原始论文内容非常密集,因此我们将花大量时间来深入理解其架构本身。

Swin Transformer是“Shifted Window Transformer”的缩写。它与Vision Transformer有许多相似之处,但也存在关键差异。其核心思想是将全局注意力计算限制在局部窗口内,从而将计算复杂度从二次方降低到线性。
Vision Transformer的计算瓶颈
在深入Swin之前,让我们先回顾Vision Transformer的计算挑战。
在Vision Transformer中,一张尺寸为 H x W、通道数为 C 的图像被分割成多个不重叠的 P x P 大小的图像块。每个图像块被视为一个“令牌”。
-
图像块总数(即令牌数
N)的计算公式为:
N = (H / P) * (W / P) -
自注意力机制的核心计算是查询向量
Q与键向量K的点积。其计算复杂度与N^2成正比,即O(N^2)。 -
由于
N与图像总像素数(H * W)成正比,因此注意力计算的复杂度实际上与图像尺寸的平方成正比。这意味着,如果将图像分辨率提高一倍(像素数变为4倍),计算复杂度将增加16倍(4的平方)。这种二次方复杂度是Vision Transformer处理高分辨率图像(如语义分割任务所需)时的主要瓶颈。
Swin Transformer的核心思想:局部窗口注意力
Swin Transformer通过将全局注意力计算限制在局部窗口内来解决上述问题。
以下是其核心思路:
- 划分窗口:将图像令牌均匀地划分为多个不重叠的局部窗口(例如,每个窗口包含
M x M个令牌)。 - 窗口内自注意力:自注意力计算仅在每个窗口内部独立进行。一个窗口内的令牌只与该窗口内的其他令牌计算注意力,而不与窗口外的令牌交互。
- 计算复杂度分析:假设每个窗口有
M^2个令牌,总共有N / M^2个窗口。那么,单个窗口内的注意力复杂度为O(M^4)。由于窗口之间计算独立,总复杂度为(N / M^2) * O(M^4) = O(N * M^2)。当窗口大小M固定时(论文中常设为7),总复杂度与令牌总数N成线性关系,即O(N)。这相比Vision Transformer的O(N^2)是巨大的改进。
局部窗口的局限性及“移位窗口”解决方案
然而,仅使用固定窗口会带来一个新问题:窗口之间缺乏信息交互。一个窗口内的模型无法“看到”或“关注”到其他窗口的内容,这限制了模型的全局建模能力。
为了解决这个问题,Swin Transformer引入了巧妙的移位窗口机制。
其工作流程如下:
- 常规窗口划分:在Transformer的某个层(如第
L层),使用标准的均匀窗口划分方式进行窗口内自注意力计算。 - 移位窗口划分:在下一层(第
L+1层),将窗口划分的起点进行偏移(例如,向右和向下各偏移[M/2]个令牌)。这使得新的窗口由上一层中不同窗口的部分令牌组成。 - 促进跨窗口连接:通过这种移位操作,上一层中相邻窗口的边界区域在下一层中被组合到了同一个新窗口中。这样,在计算新窗口的自注意力时,原本属于不同窗口的令牌之间就能建立联系,从而实现了跨窗口的信息传递。
通过交替使用常规窗口和移位窗口,Swin Transformer在保持线性计算复杂度的同时,获得了接近全局注意力的强大建模能力。
架构图示意
(此处应有一张Swin Transformer的架构示意图,展示其层级结构、窗口划分、移位操作以及特征图下采样过程。由于我无法直接显示图片,请参考原视频或论文中的图示以获取最直观的理解。)
该架构图通常会显示:
- 输入图像经过“Patch Partition”和“Linear Embedding”后变为令牌序列。
- 随后是多个“Stage”,每个Stage由若干Swin Transformer Block组成,并在Stage之间进行“Patch Merging”以降低分辨率、增加通道数,构建金字塔特征。
- 每个Swin Transformer Block内部包含基于窗口的多头自注意力模块和MLP模块,并配有层归一化和残差连接。
- 相邻的Block会分别采用“W-MSA”(常规窗口多头自注意力)和“SW-MSA”(移位窗口多头自注意力)。
关键实现细节与挑战
在下一讲的代码实现中,我们将具体面对以下几个不直观但至关重要的实现细节:
以下是几个核心挑战:
- 移位后的高效批处理:移位操作会导致窗口数量增加且大小不一,无法直接进行高效的批处理计算。论文中采用了循环移位和掩码的技巧,将移位后的特征图“卷回”成一个规整的矩形,并对不应产生注意力的区域进行掩码,从而在维持窗口规整形状的同时实现了等效的移位窗口注意力计算。
- 相对位置偏置:Swin Transformer在自注意力计算中加入了相对位置偏置
B,其公式可表示为:
Attention(Q, K, V) = SoftMax(QK^T / sqrt(d) + B) V
其中B是一个可学习的参数,其维度与注意力权重的空间维度相关。它帮助模型理解窗口内令牌之间的相对位置关系。 - 层级特征金字塔:与Vision Transformer输出单一尺度特征不同,Swin Transformer通过“Patch Merging”操作,像CNN一样构建了多尺度特征金字塔。这使得其输出特征可以直接用于需要多尺度信息的密集预测任务(如目标检测、语义分割)。
总结
本节课中我们一起学习了Swin Transformer的核心原理。我们首先回顾了Vision Transformer因全局注意力导致的二次方计算复杂度问题。接着,我们深入探讨了Swin Transformer如何通过局部窗口注意力将复杂度降至线性,并利用移位窗口机制在连续的Transformer层中实现跨窗口通信,从而兼顾了计算效率和模型表达能力。我们还简要预览了实现中的关键挑战,如高效批处理和相对位置偏置。

在下一讲中,我们将把这些理论付诸实践,从零开始编写Swin Transformer的代码,亲身体验其精妙的设计与实现细节。请务必在下次课前复习本节课内容,为接下来的代码实战做好准备。
003:VisualBERT论文解析
在本节课中,我们将学习一篇名为VisualBERT的论文。这篇论文提出了一种用于视觉与语言任务的简单而有效的基线模型。我们将详细解析其核心思想、模型架构以及训练方法。
论文概述
VisualBERT是一个用于建模多种视觉与语言任务的简单灵活框架。它由一系列Transformer层组成,通过自注意力机制隐式地对齐输入文本中的元素与关联图像中的区域。
上一节我们介绍了多模态学习的基本概念,本节中我们来看看VisualBERT如何具体实现视觉与文本的融合。

模型架构
VisualBERT的核心思想是将文本和图像信息共同输入到一个Transformer模型中。以下是其关键组成部分:
-
文本输入处理:文本首先被转换为词嵌入向量。
text_embeddings = EmbeddingLayer(text_tokens)
-
图像输入处理:图像通过一个预训练的目标检测模型(如Faster R-CNN)进行处理,提取出图像中各个区域的视觉特征。
visual_features = ObjectDetector(image)
-
模态融合:文本嵌入和视觉特征被拼接在一起,形成一个统一的输入序列,然后送入Transformer编码器。
combined_input = Concat([text_embeddings, visual_features])output = TransformerEncoder(combined_input)
-
自注意力对齐:在Transformer内部,自注意力机制允许文本标记和视觉区域标记之间进行交互,从而学习它们之间的对齐关系。


预训练任务
为了训练VisualBERT模型,论文提出了两种视觉基础的语言模型目标。以下是这两种预训练任务:
- 掩码语言建模:随机掩码掉部分文本标记,模型需要根据上下文(包括图像信息)来预测这些被掩码的标记。
- 句子-图像预测:给定一个句子和一张图像,模型需要判断该句子是否准确地描述了图像内容。
实验与结果
VisualBERT在多个视觉与语言任务上进行了评估,并取得了优异的表现。以下是其主要评估的数据集:
- VQA:视觉问答
- VCR:视觉常识推理
- NLVR2:自然语言视觉推理(使用真实图像)
- Flickr30K:图像描述数据集
实验结果表明,VisualBERT在保持模型结构相对简单的同时,其性能达到或超越了当时的先进模型。
总结

本节课中我们一起学习了VisualBERT论文。我们了解了它如何利用Transformer架构和自注意力机制来融合与对齐视觉和文本信息。通过两种特定的预训练任务,模型能够学习到跨模态的表示,进而在多个下游任务上取得优秀效果。这篇论文为后续的视觉-语言模型研究提供了一个清晰而强大的基线。
004:Swin Transformer论文精读 - 使用移位窗口的分层视觉Transformer
在本节课中,我们将要学习Swin Transformer这篇开创性论文。Swin Transformer提出了一种新的视觉Transformer架构,它通过引入分层设计和移位窗口机制,解决了标准视觉Transformer在处理高分辨率图像时计算复杂度高的问题,并成功地将Transformer确立为计算机视觉任务的通用骨干网络。
摘要
本文提出了一种名为Swin Transformer的新视觉Transformer,它能够作为计算机视觉的通用骨干网络。
将Transformer从语言领域适配到视觉领域所面临的挑战,源于两个领域之间的差异,例如视觉实体在尺度上的巨大变化。
引言
上一节我们介绍了论文的摘要和核心贡献。本节中,我们来看看论文的引言部分,了解研究背景和动机。
将Transformer从语言领域应用到视觉领域存在挑战。一个关键问题是视觉元素(如物体)的尺度变化很大,这与语言中固定尺度的词元不同。
视觉Transformer(ViT)通过将图像分割成固定大小的块(patch)来处理图像,然后在这些块上应用标准的Transformer。然而,ViT的注意力机制是全局的,其计算复杂度与图像块数量的平方成正比,这使得它难以处理高分辨率图像。
Swin Transformer通过两个主要思想来解决这个问题:
- 分层特征图:它像卷积神经网络(CNN)一样,构建了从小到大的分层特征图。
- 移位窗口自注意力:它在不重叠的局部窗口内计算自注意力,并通过在连续层之间“移位”窗口来引入跨窗口连接,从而在保持线性计算复杂度的同时获得全局建模能力。
方法
在理解了研究动机之后,我们现在深入探讨Swin Transformer的具体架构和核心组件。
整体架构概述
Swin Transformer的整体架构如下图所示。它首先将输入图像分割成不重叠的块(类似于ViT),然后通过多个“阶段”进行处理。每个阶段都由一个Patch Merging层和若干个Swin Transformer Block组成。

以下是架构的关键组成部分:
- Patch Partition:将RGB图像分割成4x4大小的小块,每个块被展平为一个特征向量。对于一个HxWx3的图像,这将产生 (H/4) * (W/4) 个特征向量,每个向量的维度是 443 = 48。
- Linear Embedding:一个线性层,将每个块的特征投影到一个任意维度(记为C)。此时的特征图尺寸为 (H/4) x (W/4) x C。
- Swin Transformer Blocks:核心计算单元。每个块包含基于窗口的多头自注意力(W-MSA)或移位窗口多头自注意力(SW-MSA),以及多层感知机(MLP),中间有层归一化(LN)和残差连接。
- Patch Merging:用于构建分层特征图。它将相邻的2x2小块特征合并,并将通道数增加一倍(类似于CNN中的池化或步幅卷积),从而在降低空间分辨率的同时增加特征维度。
基于窗口的自注意力
标准的多头自注意力(MSA)计算所有块之间的关系,其计算复杂度相对于块数量是二次方的。
为了高效建模,Swin Transformer在不重叠的局部窗口内计算自注意力。假设特征图被均匀划分为 M x M 个窗口,则基于窗口的自注意力(W-MSA)的复杂度为:
公式:
复杂度(W-MSA) = O((HW / M^2) * (M^2 * C^2)) = O(HWC^2)
其中,HW是总块数,M^2是每个窗口的块数。可以看到,复杂度与图像尺寸(HW)呈线性关系,这比全局注意力的二次方复杂度高效得多。
移位窗口自注意力
然而,仅在非重叠窗口内进行自注意力会限制跨窗口的信息交互。为了解决这个问题,Swin Transformer引入了移位窗口自注意力(SW-MSA)。
以下是其工作原理的步骤:
- 在Swin Transformer的连续两个块中,分别使用不同的窗口划分方式。
- 第一个块使用常规的窗口划分(从左上角开始)。
- 第二个块将窗口网格向左上角方向各移动 (M/2) 个块(M是窗口大小),从而产生新的、与上一层窗口有重叠的窗口划分。
- 这种移位操作引入了上一层不同窗口之间的连接,从而实现了跨窗口的信息传递。

移位窗口的一个实际挑战是会产生大小不一的窗口。论文采用了一种巧妙的循环移位(cyclic shift)和掩码(masking) 方法来解决:
- 将移位后的特征图进行循环填充,使其能被均匀划分。
- 在计算自注意力时,使用注意力掩码来确保只有原本相邻的块之间才能进行注意力计算,而“拼接”过来的不相邻块之间则被屏蔽。
相对位置偏置
在自注意力计算中,Swin Transformer加入了相对位置偏置(Relative Position Bias),这比使用绝对位置嵌入效果更好。
公式:
Attention(Q, K, V) = SoftMax(QK^T / sqrt(d) + B) * V

其中,B 是一个可学习的矩阵,其每个元素 B_{ij} 表示查询块 i 和键块 j 之间的相对位置偏置。由于窗口大小固定(如7x7),可能的相对位置是有限的(例如,对于7x7窗口,有49种相对偏移),因此 B 是一个大小固定的可学习参数表。
实验与结果

了解了核心方法后,我们来看看作者如何通过实验验证Swin Transformer的有效性。


论文在图像分类(ImageNet)、目标检测(COCO)和语义分割(ADE20K)等多个核心视觉任务上进行了广泛的实验。
以下是主要实验结果概述:
- 图像分类:在ImageNet-1K数据集上,Swin Transformer取得了与最先进的卷积网络和Transformer模型相当甚至更好的精度,同时具有更高的计算效率。
- 目标检测与实例分割:在COCO数据集上,Swin Transformer作为骨干网络,在多种检测器框架下(如Mask R-CNN、Cascade Mask R-CNN)均大幅超越了基于ResNet的基线模型。
- 语义分割:在ADE20K数据集上,Swin Transformer同样展示了卓越的性能,证明了其作为通用视觉骨干网络的能力。

此外,论文还进行了详细的消融研究,验证了移位窗口、相对位置偏置等关键设计的必要性。
总结

本节课中,我们一起学习了Swin Transformer这篇重要的论文。我们了解到,Swin Transformer通过引入分层架构和移位窗口自注意力机制,成功地将Transformer的高效建模能力扩展到了视觉领域。它解决了全局自注意力计算复杂度高的问题,并能够像CNN一样生成多尺度特征图,从而在图像分类、目标检测和分割等多种任务上取得了卓越的性能,真正成为了计算机视觉的通用骨干网络。
尽管论文的表述较为凝练,但其核心思想清晰而强大。理解Swin Transformer是掌握现代视觉Transformer架构的关键一步。
005:从零构建Vision Transformer与NanoVLM
在本节课中,我们将首次学习Vision Transformer。我们将理解其背后的直觉,了解它与用于文本数据的Transformer有何不同。建立直觉后,我们将从零开始编写一个Vision Transformer。我们将编写所有核心部分,并在适用时使用PyTorch库。我们还将从头开始训练它。课程结束时,如果你跟着一起编码,你将拥有一个在自己选择的数据集上构建并训练好的Vision Transformer。
概述
首先,我们来看看Vision Transformer的提出者。
Vision Transformer的思想由这篇论文提出,该论文最初于2020年发布,但在ICLR会议上正式发表是在2021年。这篇论文在三个月前有65,000次引用,现在已有76,000次。可以预见,几年后它将成为AI历史上被引用次数最高的论文之一。
这篇论文在“Attention Is All You Need”论文发表三年后出现,后者同样来自Google。这里需要注意的一点是,我记得在2022年,当OpenAI推出ChatGPT时,许多人在LinkedIn等平台上评论说Google在AI领域做得不多。但Google一直在AI领域做了大量工作,只是其中许多成果不一定在消费级产品领域,而是在研究领域。他们发表了许多出色的论文,并且Google内部不同的AI团队至今仍在不断产出新成果。
这篇论文的标题是“一张图片值16x16个词”。他们提出将Transformer架构用于图像分类任务。在他们的架构中,与“Attention Is All You Need”论文中提出的原始Transformer架构相比,只有非常少的改动或修改。
这是一篇内容密集但写得非常好的论文。如果你有兴趣,可以在我们的YouTube频道上观看一篇长达三个半小时的讲座视频,专门解读这篇Vision Transformer论文。但今天,我们不会详细讲解这篇论文,而是重点探讨Vision Transformer与我们在本系列中一直在研究的文本Transformer有何不同。我们想看看关键差异在哪里,相似之处又在哪里。
文本Transformer的工作原理
一个用于文本的Transformer工作原理如下:你有一个以提示形式输入的文本。然后,这个输入被分词,基本上就是将句子分割成一个个词元。你可以将词元想象成单词,但词元也可以是单词、子词等。接着,每个词元被转换成一个向量。如果是一个类似GPT-2的小型架构,向量维度是768,所以每个向量都位于一个768维的空间中。
因此,我们输入GPT的每个句子都会被转换成n个词元,每个词元又会被转换成768维的向量。对于每个词元,我们会添加一个称为位置编码的东西,这在之前的课程中讨论过。
但是,基于文本的Transformer和Vision Transformer之间的主要区别出现在计算注意力的部分。
文本Transformer中的注意力机制
在基于文本的Transformer中,我们使用一种称为掩码自注意力的机制。我们已经讨论过为什么要进行这种掩码。假设我们有一个句子:“The cat sat on the mat.” 如果我们把句子分成单词,这里有一、二、三、四、五、六个词元。这意味着有六个查询和六个键。
我们构建一个称为注意力权重矩阵的东西。你会有六个查询(沿着行):The, cat, sat, on, the, mat。你会有六个键(沿着列):The, cat, sat, on, the, mat。
我们在上一讲中讨论过掩码自注意力和多头自注意力。在掩码中,我们阻止当前查询关注未来的键。例如,如果“cat”是当前正在查看的查询,那么“cat”只能关注它自己和“The”,而不能关注“sat”、“on”、“the”、“mat”。我们这样做的原因是因为我们试图完成的任务——GPT试图完成的任务是下一个词预测。在下一个词预测中,你的当前查询不应该关注那些尚未出现的、属于未来的键。
为了实现这一点,我们构建了一个上三角掩码。它看起来像这样,在注意力权重矩阵中,这些元素都是零。所以,只有最后一个查询,即对应于“mat”的查询,会关注所有的键,因为在“mat”之后没有更多的查询了。因此,“mat”这个查询将有六个键可以关注。这就是我们在上一讲中讨论的内容。
BERT模型中的注意力
但你也应该知道,GPT并不是唯一利用Transformer的现代架构。还有一个非常著名的架构叫做BERT。在BERT架构中,他们试图做的不是句子预测。
在BERT模型中,他们会输入一个像这样的句子:“The [MASK] sat on the [MASK].” 在BERT中,他们也利用了Transformer架构。他们不是试图做下一个词预测,而是输入句子,并试图预测这些掩码词元的值。
那么,在这种情况下,我们需要掩码注意力吗?我们应该使用像上一讲中GPT用于下一个词预测那样的因果自注意力吗?在这种情况下,我们会使用带掩码的注意力还是不带掩码的注意力?大多数人回答“不带掩码”,这是正确的。

因为在这种情况下,你不是试图预测下一个词,而是试图获取句子的完整上下文。这意味着,如果你掩码了当前查询和未来键之间的注意力,你将无法获得完整的上下文。这也是为什么,如果你打开“Attention Is All You Need”这篇论文(注意,这篇论文与GPT无关),你会看到这个架构图。



请看图的左侧部分和右侧部分。告诉我,你在哪里找到了掩码自注意力?是在左侧还是右侧?它在右侧。右侧有“掩码多头注意力”。左侧则没有掩码。
这意味着,哪个是GPT,哪个是BERT?是左侧还是右侧?本质上,这个Transformer架构同时包含编码器和解码器。但在BERT模型中,他们只使用了左侧部分。所以掩码多头注意力不存在。输入嵌入通过注意力层,再通过Transformer块,每个Transformer块包含一个不带掩码的多头注意力和一个前馈多层感知机,这个过程重复多次。
总结

本节课中,我们一起学习了Vision Transformer的起源及其与文本Transformer的核心区别。我们回顾了文本Transformer的工作原理,特别是GPT中使用的掩码自注意力机制,以及BERT中使用的非掩码自注意力机制。理解这些基础是至关重要的,因为Vision Transformer借鉴了这些思想,并将其应用于图像数据。在下一节中,我们将深入探讨Vision Transformer如何将图像转换成类似于文本词元的序列,并开始动手构建我们自己的模型。
006:二维卷积的输入、输出与滤波器维度
在本节课中,我们将深入探讨二维卷积操作,特别是PyTorch中nn.Conv2d函数的输入、输出维度以及滤波器的工作原理。理解这些概念对于构建和优化卷积神经网络至关重要。
上一节我们介绍了卷积神经网络的基本概念,本节中我们来看看二维卷积的具体维度计算。


输入与输出维度解析


首先,我们来看一个典型的二维卷积定义:
nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=0, bias=False)
以下是各参数的含义:
in_channels:输入数据的通道数。out_channels:输出数据的通道数,也等于滤波器的数量。kernel_size:滤波器(卷积核)的空间尺寸。stride:卷积操作的步长。padding:在输入数据边缘填充的像素数。bias:是否使用偏置项。
维度计算示例

让我们通过一个具体例子来理解维度如何变化。

假设我们有一张输入图像,其尺寸为 9 x 9 像素,并且有3个颜色通道(RGB)。因此,输入张量的形状为 (3, 9, 9)。
我们使用一个 3 x 3 的滤波器进行卷积,步长stride=1,无填充padding=0。
输出空间尺寸计算:
输出宽度 = (输入宽度 - 滤波器宽度 + 2 * 填充) / 步长 + 1
输出高度 = (输入高度 - 滤波器高度 + 2 * 填充) / 步长 + 1
代入数值:
输出宽度 = (9 - 3 + 2*0) / 1 + 1 = 7
输出高度 = (9 - 3 + 2*0) / 1 + 1 = 7
因此,输出的空间尺寸为 7 x 7。
输出通道数:
输出通道数完全由 out_channels 参数决定,它等于我们使用的滤波器数量。
- 如果
out_channels=1,则无论输入有多少通道,输出都只有1个通道。这是因为单个滤波器会跨所有输入通道进行计算,并将结果求和,最终生成一个单通道的特征图。 - 如果
out_channels=N,则我们使用了N个独立的滤波器。每个滤波器都会独立地在输入上滑动,生成一个对应的输出通道。因此,最终会得到N个通道的输出。
在我们的例子中,如果设置 out_channels=64,那么输出张量的形状将是 (64, 7, 7)。

滤波器结构与可学习参数

理解滤波器结构是计算参数数量的关键。
每个滤波器本身是一个多维张量。其维度为:
(in_channels, kernel_height, kernel_width)
对于我们的例子(in_channels=3, kernel_size=3),一个滤波器的形状是 (3, 3, 3),它包含 3 * 3 * 3 = 27 个可学习的权重参数。
总参数数量计算:
总参数数 = out_channels * (in_channels * kernel_height * kernel_width)

如果 bias=True,则每个输出通道还会增加一个偏置参数:
总参数数 = out_channels * (in_channels * kernel_height * kernel_width + 1)
在我们的例子中(out_channels=64, in_channels=3, kernel_size=3, bias=False):
总参数数 = 64 * (3 * 3 * 3) = 64 * 27 = 1728
这意味着该卷积层有1728个权重值会在训练过程中被优化。

总结

本节课中我们一起学习了二维卷积的核心维度概念。
- 输入维度由
(in_channels, H_in, W_in)定义。 - 输出维度由
(out_channels, H_out, W_out)定义,其中空间尺寸H_out和W_out由输入尺寸、滤波器尺寸、步长和填充共同决定。 out_channels直接决定了滤波器的数量。- 每个滤波器是一个
(in_channels, kernel_height, kernel_width)的张量。 - 整个卷积层的可学习参数总数可以通过
out_channels * in_channels * kernel_height * kernel_width(无偏置时)快速计算。

清晰理解这些关系,是设计、调试和优化卷积神经网络架构的基础。
007:Swin Transformer简介 🏗️
在本节课中,我们将要学习Swin Transformer架构。这是一种对之前学习的Vision Transformer和Data-efficient Image Transformer的自然扩展,旨在解决高分辨率图像处理中的计算效率问题。
概述
Swin Transformer是“Shifted Window Transformer”的简称。它由微软亚洲研究院团队于2021年提出,论文已获得约38,000次引用。该架构首次令人信服地证明了Transformer可以作为通用图像任务(如分类、检测、分割)的强大骨干网络。然而,其原始论文内容较为密集,因此我们将花时间深入理解其架构本身。


上一节我们回顾了Vision Transformer的基本流程,本节中我们来看看Swin Transformer如何对其进行改进。
Vision Transformer的回顾与挑战
在Vision Transformer中,处理流程可简要概括如下:
- 输入图像尺寸为
H x W x C(高 x 宽 x 通道数)。 - 图像被分割成不重叠的
P x P大小的图像块。 - 每个图像块被视为一个令牌(Token),并被展平。因此,令牌总数
N为:
N = (H / P) * (W / P) - 添加一个分类令牌(CLS Token)和位置编码。
- 整个令牌序列输入到Transformer编码器中。
- 最终,分类令牌的上下文向量被送入MLP分类头进行图像分类。
Data-efficient Image Transformer在此基础上引入了额外的蒸馏令牌(Distillation Token),用于从教师模型的预测中学习。
尽管Vision Transformer性能卓越,但它存在一个关键的计算问题:自注意力机制的复杂度。
自注意力的计算复杂度问题
自注意力机制的核心计算涉及查询(Query)和键(Key)的点积:Q · K^T。
以下是其复杂度分析:
- 假设有
N个令牌。 - 每个查询需要与所有
N个键进行计算。 - 因此,计算复杂度与
N^2成正比,即 O(N^2)。
由于 N 与图像总像素数 H * W 成正比,这意味着:
- 如果将图像分辨率(像素总数)提高至2倍,
N大约变为2倍。 - 但注意力计算复杂度将增加至原来的 4倍(即
2^2)。 - 这种二次方复杂度使得Vision Transformer在处理需要高分辨率图像的任务(如语义分割)时面临巨大挑战。
Swin Transformer的核心思想:局部窗口注意力
为了解决二次方复杂度问题,Swin Transformer提出了局部窗口注意力机制。
其核心思想是:
- 不再让图像中的所有令牌进行全局交互。
- 而是将图像划分为多个不重叠的局部窗口。
- 自注意力计算仅在每个窗口内部独立进行。
例如,一个 2x2 的令牌窗口内,只有这4个令牌之间会计算注意力。
以下是这种设计带来的优势:
- 线性复杂度:对于一个有
M个令牌的窗口,其内部注意力复杂度为O(M^2)。如果将图像均匀划分为大小固定的窗口,那么总计算复杂度与图像中的窗口数量呈线性关系,从而实现了相对于图像分辨率的近似线性复杂度。 - 效率提升:这显著降低了在高分辨率图像上的计算开销。
然而,仅使用固定窗口会带来一个新问题:窗口之间缺乏信息交互。这限制了模型建立长距离依赖关系的能力。
解决方案:窗口移位(Shifted Window)
为了解决窗口间信息隔离的问题,Swin Transformer在连续的Transformer块中采用了窗口移位策略。
其工作原理如下:
- 在第一个块中,使用常规的窗口划分方式计算局部窗口注意力。
- 在下一个块中,将窗口向对角线方向移动(例如,移动
(窗口大小/2)个像素)。 - 这种移位产生了新的、与上一层窗口重叠的新窗口。
- 在新窗口内再次计算注意力。
通过这种巧妙的移位,上一层中不同窗口的令牌在下一层就有机会在同一个新窗口内进行交互。这在不引入额外计算复杂度的前提下,实现了跨窗口的信息流通,从而能够构建全局的上下文信息。
架构图示意

(注:此处应有一张展示Swin Transformer层级结构、窗口划分及移位机制的示意图。图中通常会显示特征图尺寸逐渐减小、通道数增加的金字塔结构,以及相邻层之间窗口的偏移。)
总结
本节课中我们一起学习了Swin Transformer的核心理念。我们首先回顾了Vision Transformer及其存在的二次方计算复杂度问题。接着,我们探讨了Swin Transformer如何通过局部窗口注意力将复杂度降低至线性级别。最后,我们介绍了窗口移位这一关键技巧,它确保了在保持计算效率的同时,模型仍能捕获跨窗口的全局依赖关系。Swin Transformer通过这种层次化、移位窗口的设计,为Transformer在视觉任务中处理高分辨率图像铺平了道路。

在下节课中,我们将动手从零开始实现Swin Transformer,深入其代码细节。由于实现中有一些不直观的部分,请务必在课前复习本节课的内容。
008:剖析DeiT论文 - 数据高效的图像Transformer
在本节课中,我们将一起学习一篇名为《Training data-efficient image transformers & distillation through attention》的重要论文,即DeiT。这篇论文的核心贡献在于,它提出了一种方法,使得Vision Transformer模型能够在相对较小的数据集(如ImageNet-1K)上高效训练,而无需依赖海量专有数据。我们将深入探讨其提出的知识蒸馏策略和“蒸馏令牌”这一关键概念。
上一节我们介绍了Vision Transformer及其对海量数据的依赖。本节中,我们来看看DeiT论文如何解决这个问题。
论文背景与动机
这篇论文来自Facebook AI Research。先前基于纯注意力机制的神经网络(即Vision Transformer)已被证明能处理图像分类等任务。然而,这些高性能的Vision Transformer需要使用数亿张图像进行预训练,并依赖大规模计算基础设施,这限制了其广泛应用。
本工作的目标是,仅使用ImageNet数据集,在一台计算机上三天内训练出具有竞争力的、无卷积的Transformer模型。更重要的是,论文引入了一种针对Transformer的师生策略,该策略依赖于一个“蒸馏令牌”,使学生模型能够通过注意力机制向教师模型学习。
核心方法:知识蒸馏与蒸馏令牌
DeiT的核心创新在于其训练策略,而非模型架构本身。其模型架构与标准的Vision Transformer基本相同。
以下是其引入的关键组件:
- 教师-学生框架:使用一个预先训练好的、性能更强的模型(教师)来指导一个较小的模型(学生)进行训练。在DeiT中,教师模型可以是大型卷积神经网络(如RegNet)或大型Vision Transformer。
- 蒸馏令牌:这是DeiT最核心的创新点。在输入序列中,除了Vision Transformer原有的分类令牌(
[CLS]token)外,额外添加一个蒸馏令牌([DIST]token)。- 公式表示输入序列:
[CLS] + 图像块序列 + [DIST] - 在Transformer的编码过程中,这个蒸馏令牌会通过自注意力机制与分类令牌及所有图像块令牌进行交互,并专门学习模仿教师模型的输出。
- 公式表示输入序列:
- 蒸馏损失:训练学生模型时,损失函数由两部分组成:
- 标准交叉熵损失:基于学生模型自身分类令牌的预测结果与真实标签计算。
- 蒸馏损失:基于学生模型蒸馏令牌的预测结果与教师模型预测的“软标签”(经过温度参数T调整的概率分布)计算。
- 代码概念表示总损失:
Loss = λ * CE_Loss(student_cls, hard_label) + (1-λ) * KL_Div_Loss(student_dist, teacher_soft_label)
上一节我们介绍了DeiT的核心训练机制。本节中,我们来看看这种方法带来的具体优势。



主要优势与结果
通过上述方法,DeiT取得了以下关键成果:
- 数据高效性:仅使用ImageNet-1K(约130万张图像)进行训练,无需JFT-300M等超大规模私有数据集。
- 训练高效性:在一台机器上,用不到3天时间即可完成训练。
- 高性能:一个拥有8600万参数的DeiT模型,在ImageNet上达到了83.1%的Top-1准确率。
- 蒸馏的有效性:论文表明,当使用卷积神经网络(CNN)作为教师时,这种基于令牌的蒸馏方法尤其有效,使得Transformer模型能够达到与卷积网络相竞争的性能。
总结

本节课中我们一起学习了DeiT论文。这篇论文的核心贡献是提出了一种数据高效的Vision Transformer训练方案。它通过引入一个额外的“蒸馏令牌”和创新的师生蒸馏策略,使模型能够从小型公开数据集中有效学习,并快速完成训练。这项工作极大地降低了Vision Transformer的应用门槛,并为后续的模型压缩和知识迁移研究提供了重要思路。理解DeiT的蒸馏机制,对于掌握如何让大模型指导小模型、以及如何设计高效的训练目标至关重要。
009:Transformer架构精讲
在本节课中,我们将深入学习Transformer的实际架构。我们将从大型语言模型的角度出发,探讨其核心工作原理。虽然本讲聚焦于语言模型,但所学知识将直接应用于未来课程中讨论的视觉Transformer。

概述

上一节我们讨论了为何需要Transformer来捕获图像中的长距离依赖关系,这是CNN难以做到的。本节中,我们将深入探讨Transformer的实际架构。
Transformer架构总览
以下是Transformer架构中最著名的示意图,它出自2017年发表的革命性论文《Attention Is All You Need》。该论文首次提出了自注意力机制,彻底改变了自然语言处理领域。


此架构图包含编码器和解码器两部分。编码器用于如BERT等模型,而解码器则用于如GPT等模型。本节课,我们将重点讲解仅解码器架构,因为理解它就能理解GPT或ChatGPT类模型的工作原理。
然而,原图对初学者不够友好,包含大量术语和连接箭头。因此,我将使用一个修改过的简化版示意图,分步讲解解码器架构。
大型语言模型的核心任务
大型语言模型的核心任务是下一个词预测。例如,给定输入“The cat sat on the”,模型会预测下一个词(如“mat”),然后将预测词加入输入序列,继续预测下一个词,如此迭代生成完整段落。
为了理解Transformer如何完成此任务,我们将架构分为三个主要部分:
- 输入处理部分
- Transformer块(核心处理部分)
- 输出生成部分
我们将按顺序逐一讲解。首先,让我们聚焦于输入部分。
输入处理部分详解
现在,我们仅关注架构图中的输入部分。此部分主要完成以下工作:

输入句子“The cat sat on the”首先需要被转换成模型能处理的形式。这个过程主要涉及三个步骤。
1. 分词
首先,输入句子被分割成更小的单元,称为词元。为简化理解,我们可以将每个词视为一个词元。
以下是分词结果示例:
- The
- cat
- sat
- on
- the
这样,我们得到了5个词元。为了追踪Transformer内部的处理流程,我们将重点关注第二个词元:“cat”。
关于分词技术的补充说明:
实际应用中,分词并非简单按空格分割单词。常用的一种方法是字节对编码。简单的按单词分词会遇到问题,例如遇到新词(如药品名“Ozympic”)时,模型无法识别。BPE等更高级的分词方法可以更好地处理未知词汇和子词单元。
2. 词元嵌入
分词后,每个词元(如“cat”)需要被转换为一个数值向量,这个过程称为词元嵌入。你可以将其理解为在一个高维语义空间中为每个词找到一个坐标。
例如,“cat” -> [0.2, -0.5, 0.7, ...](一个长度为d_model的向量)。
在代码中,这通常通过一个嵌入查找表实现:
# 假设 vocab_size 是词表大小,d_model 是嵌入维度
token_embedding_layer = nn.Embedding(vocab_size, d_model)
# token_ids 是分词后词元对应的索引序列
token_embeddings = token_embedding_layer(token_ids)
3. 位置编码
由于Transformer本身不像RNN那样能感知序列顺序,我们需要额外添加位置编码来为词元注入其在序列中位置的信息。
位置编码向量与词元嵌入向量维度相同(d_model)。两者会直接相加。
# 假设 position_embeddings 是计算好的位置编码矩阵
combined_embeddings = token_embeddings + position_embeddings
相加后的结果就是最终输入Transformer块的表示向量,它同时包含了词的语义信息及其在句子中的位置信息。
总结
本节课我们一起学习了Transformer架构的输入处理部分。我们了解到,一个输入句子需要经过分词、词元嵌入和位置编码三个关键步骤,才能转换为包含丰富语义和位置信息的数值向量,供后续的Transformer核心块进行处理。

下一节,我们将进入Transformer的核心——Transformer块,深入剖析自注意力机制等模块是如何工作的。
010:从零开始编码数据高效图像Transformer (DeiT)
在本节课中,我们将学习数据高效图像Transformer。首先,我们将理解该模型背后的核心思想,以及它与哪些模型最为相似。在第二部分,我们将从零开始构建一个DeiT模型。
概述
我们已经介绍过Vision Transformer。本节课的优点是,如果你理解并正确编码过Vision Transformer,那么学习DeiT会感到非常熟悉,因为两者有95%的内容是相似的。然而,DeiT做了一些惊人的改进,使其在训练效率上相比Vision Transformer有了显著提升。
数据高效图像Transformer (DeiT) 简介
这篇论文大约发表于2021年,由Facebook AI Research发布。论文标题是“训练数据高效图像Transformer”。DeiT是为图像设计的,它利用了Transformer架构,并引入了一些新概念。

该论文引入的一个主要思想是蒸馏。你可能听说过深度学习中的教师-学生模型概念。今天我们将详细探讨什么是教师-学生模型,这个概念也被称为知识蒸馏,以及DeiT如何利用知识蒸馏来取得比Vision Transformer好得多的效果。
Vision Transformer的挑战
回想一下Vision Transformer,它的主要问题有:
- 需要海量数据:训练基础Vision Transformer模型使用了包含3亿张图像的JFT数据集。但JFT数据集并非公开可用,它是谷歌的内部数据。
- 参数量巨大:当时最先进的Vision Transformer模型大约有6亿个参数。
- 计算成本高昂:训练需要多天时间并使用多个GPU。

尽管存在这些问题,但使用所有这些资源训练出的Vision Transformer在当时达到了最先进的水平,甚至超越了卷积神经网络在计算机视觉领域的长期主导地位。
从CNN到Transformer的转变
从大约2012年到2020/2021年,卷积神经网络在深度学习和计算机视觉领域占据主导地位。然而,当Vision Transformer在2020年左右被引入后,Transformer架构开始流行起来。
我们讨论DeiT的原因是,在了解了Vision Transformer的工作原理后,它是逻辑上的下一步发展。
CNN有一些固有的优势,主要是归纳偏置。两个最著名的归纳偏置是:
- 局部性:特征在局部区域内存在。
- 平移不变性/等变性:无论特征在图像二维空间中的哪个位置,CNN都能捕捉到它。
卷积运算本质上做了一些假设:它假设特征是局部存在的,并且无论特征位于哪个局部区域,都可以用某种类型的滤波器检测到。
然而,这并不总是好事。例如,在自动驾驶场景中,一个行人正在闯红灯过马路。行人的像素位置和红灯的像素位置在图像中可能相距很远,但在当前语境下,这两组像素高度相关。需要一个全局注意力机制,无论像素在图像中的距离如何,都能从完整上下文中提取有意义的信息,这样自动驾驶汽车才不会因为看到绿灯就撞上行人。
这正是人们热衷于将Transformer架构引入图像处理的原因。在Transformer中,只要在上下文窗口内,输入句子的长度并不重要。一个著名的例子是:“The teacher who was teaching a difficult concept to the students smiled.” 这里,“smiled”这个动作是由“teacher”执行的,尽管这两个词在句子中相距很远,但注意力机制应该能学习到它们之间的高度相关性。
同样的概念适用于图像。当你将图像转换为图像块,再将图像块转换为令牌时,无论图像块之间的物理距离有多远,模型都可以学习到相隔很远的图像块之间的关系。这就是推动基于Transformer的架构发展的原因。
但问题在于,如前所述,Vision Transformer需要海量的数据和计算资源。



DeiT的核心改进:知识蒸馏


DeiT通过引入知识蒸馏来解决Vision Transformer对大数据集的依赖问题。其核心思想是使用一个预先训练好的、性能强大的模型作为“教师”,来指导一个较小的“学生”模型(即DeiT)进行训练。学生模型不仅学习来自真实标签的监督信号,还学习模仿教师模型的“软标签”(即概率分布),从而获得更丰富、更平滑的学习信号,提高数据利用效率和最终性能。
上一节我们介绍了DeiT的背景和核心思想,本节中我们来看看如何从零开始构建一个DeiT模型。以下是构建DeiT模型的关键步骤。
模型架构组件
-
图像分块与线性投影:将输入图像分割成固定大小的非重叠图像块,然后将每个图像块展平并通过一个线性层投影到模型维度。
# 伪代码示例 patches = image_to_patches(image, patch_size) # 形状: [batch, num_patches, patch_dim] projected_patches = linear_projection(patches) # 形状: [batch, num_patches, d_model] -
可学习的分类令牌:在投影后的图像块序列前添加一个可学习的
[CLS]令牌。这个令牌的最终输出将用于图像分类。cls_token = learnable_parameter([1, 1, d_model]) token_sequence = concatenate([cls_token, projected_patches], dim=1) -
位置编码:为序列中的每个令牌(包括
[CLS]令牌和所有图像块令牌)添加可学习的位置编码,以注入空间位置信息。position_embeddings = learnable_parameter([1, num_patches+1, d_model]) token_sequence += position_embeddings -
Transformer编码器层:堆叠多个标准的Transformer编码器层。每一层都包含多头自注意力机制和前馈神经网络。
# 单个编码器层结构 class TransformerEncoderLayer(nn.Module): def __init__(self, d_model, nhead, dim_feedforward): super().__init__() self.self_attn = MultiheadAttention(d_model, nhead) self.linear1 = nn.Linear(d_model, dim_feedforward) self.linear2 = nn.Linear(dim_feedforward, d_model) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) def forward(self, x): # 多头自注意力 + 残差连接 & 层归一化 x = self.norm1(x + self.self_attn(x, x, x)) # 前馈网络 + 残差连接 & 层归一化 x = self.norm2(x + self.linear2(F.gelu(self.linear1(x)))) return x -
分类头:从最终Transformer编码器输出的
[CLS]令牌表示中,通过一个层归一化层和一个线性分类器得到最终的分类logits。cls_output = token_sequence[:, 0, :] # 提取CLS令牌 cls_output = layer_norm(cls_output) logits = classifier(cls_output) # 形状: [batch, num_classes]
知识蒸馏的实现
DeiT的关键创新在于训练过程中同时使用真实标签和教师模型的预测进行监督。
- 准备教师模型:使用一个在大型数据集上预训练好的CNN作为教师模型。
- 计算损失:总损失是真实标签的交叉熵损失和蒸馏损失的加权和。
- 真实损失:学生模型预测与真实硬标签之间的交叉熵损失。
- 蒸馏损失:学生模型预测与教师模型输出的软标签之间的交叉熵损失。软标签是教师模型logits经过温度缩放后的概率分布。
其中,# 伪代码示例 # 学生和教师模型的输出 student_logits = model(images) teacher_logits = teacher_model(images).detach() # 不更新教师模型参数 # 真实标签损失 loss_hard = CrossEntropyLoss(student_logits, true_labels) # 蒸馏损失(带温度缩放) temperature = 3.0 soft_targets = F.softmax(teacher_logits / temperature, dim=-1) student_probs = F.log_softmax(student_logits / temperature, dim=-1) loss_soft = KLDivLoss(student_probs, soft_targets) * (temperature ** 2) # 总损失 total_loss = alpha * loss_hard + (1 - alpha) * loss_softalpha是平衡两种损失的权重系数。

总结


本节课中我们一起学习了数据高效图像Transformer。我们首先探讨了Vision Transformer面临的挑战,即对海量数据和计算的依赖。接着,我们介绍了DeiT如何通过引入知识蒸馏技术,利用一个强大的教师模型来指导较小的学生模型训练,从而显著提高了数据利用效率和训练效果。最后,我们概述了从零开始构建DeiT模型的核心步骤,包括图像分块、Transformer编码器以及关键的蒸馏损失计算。DeiT展示了如何将Transformer架构高效地应用于视觉任务,为后续更多视觉Transformer模型的发展奠定了基础。
011:从零构建NanoVLM
概述
在本节课中,我们将学习视觉语言模型的基本概念,并了解如何从零开始构建一个名为NanoVLM的简化模型。我们将探讨如何将文本和图像这两种不同的模态数据,转换为同一语义空间中的向量表示,并让它们相互理解。
上一节我们介绍了视觉Transformer的构建,其中的一些思想将有助于理解本节的架构。


什么是视觉语言模型?


视觉语言模型是一种能够同时处理文本和图像数据的模型。
理想情况下,VLM应该能够处理文本和图像数据。
例如,当我们写下单词“苹果”,或者展示一张苹果的图片时,人类大脑会以类似的方式处理这两种信息,它们在我们脑海中都指向“苹果”这个概念。
那么,VLM应该如何理解“苹果”这个词和一张苹果的图片代表的是同一个事物呢?我们可以从多种角度思考,但最简单的思考方式之一是借鉴我们在大型语言模型中表示文本的方法。
核心思想:共享语义空间
在大型语言模型中,每个词元都被表示为一个数学上的多维向量。

我们可以在这里应用类似的想法:将“苹果”这个词转换为一个N维向量,同时也将苹果的图片转换为一个相同维度的向量。然后,找出如何使这两种表示彼此接近或相似。

下图很好地捕捉了这个核心思想。

文本“狗”的向量和图像“狗”的向量应该非常相似。理想情况下,它们应该彼此接近,因为这是一个多维语义空间。当你将一个向量指向该空间的某个区域时,它就具有特定的含义。通常,你可以认为对应动物的向量指向语义空间中的动物区域,而对应水果(如苹果、橙子)的向量指向空间中的另一个方向。


但我们希望的是,文本“狗”的向量和图像“狗”的向量是相同的。


如何量化向量相似性?
在本课程中我们已经多次讨论过,如果两个向量维度相同,我们如何量化它们之间的相似性?
我们可以使用余弦相似度。具体来说,我们可以计算点积。如果这两个向量是单位向量,那么点积就等于余弦相似度。
假设我们称文本的向量为 Z_T,图像的向量为 Z_I。如果它们不是单位向量,我们可以先除以各自的模长,再计算点积。
公式:相似度 = (Z_I · Z_T) / (||Z_I|| * ||Z_T||) = cos(θ)
其中,θ 是图像表示和文本表示之间的夹角。
如果向量非常相似,它们之间的夹角将接近零,那么 cos(0) = 1。如果向量完全不相似,它们将是正交的,那么 cos(90°) 将接近 0。这就是基本思想。
文本如何转换为向量?
我们已经学习了在大型语言模型中将文本转换为向量的一种方法。
具体是如何做的呢?以下是关键步骤:
首先,我们需要一个包含所有可能词元的词汇表。为简化起见,假设每个单词是一个词元,那么词汇表将包含所有可能的单词。每个单词都有一个ID(例如,0,1,...)。像GPT-3这样的模型,其词汇表大约有50,000个词元。
每个词元都关联一个向量。词元ID 0 有一个关联向量,词元ID 1 也有一个关联向量,以此类推。这个向量的维度取决于你的模型,例如,某些模型的向量是768维。
当你输入一个句子如“Apple is red”时,首先将其分割成词元并找到对应的词元ID。然后,查询词汇表,获取每个词元ID对应的向量。这样,我们就得到了每个词元的向量表示。
此外,我们还添加了位置编码。第一个词元对应位置0,第二个对应位置1,依此类推。我们将位置编码加到词元向量上,得到最终的输入向量表示。
然后,所有这些向量会通过多头注意力机制,为每个输入词元生成一个上下文向量,该上下文向量与输入向量具有相同的维度(例如768维)。
这就是我们为文本输入生成向量关联的过程。
图像如何转换为向量?
文本到向量的转换我们已经熟悉,那么图像如何转换为向量呢?
从上一节关于视觉Transformer的内容中,你已经知道了一种方法:将图像分割成多个图块,每个图块被转换为一个向量(即一个词元)。然后,同样添加位置编码,再通过Transformer编码器生成最终的上下文向量。
另一种方法是,你可以将图像通过一个卷积神经网络(不包含注意力机制)。图像最初可能是 32 x 32 x 3 的维度(即宽32、高32、3个颜色通道)。当图像通过每个卷积层时,空间维度(宽和高)会逐渐缩小,而通道数会增加。

这个过程最终可以将整张图像的信息压缩或表示为一系列特征向量。
构建NanoVLM的蓝图
理解了文本和图像如何分别转换为向量后,构建NanoVLM的蓝图就清晰了:
- 文本编码器:使用一个简化的小型Transformer或类似结构,将输入文本转换为一个向量序列。
- 图像编码器:使用一个简化的小型CNN或视觉Transformer,将输入图像转换为一个向量序列。
- 共享语义空间投影:设计一个投影层(通常是线性层),确保文本编码器和图像编码器输出的向量被映射到相同维度的共享语义空间中。
- 对齐目标:在训练时,我们的目标是让匹配的(文本,图像)对的向量表示尽可能相似(余弦相似度接近1),而不匹配的对的向量表示尽可能不相似(余弦相似度接近0)。这通常通过对比学习损失函数(如InfoNCE损失)来实现。
通过这种方式,模型学会了在同一个向量空间中理解文本和图像的含义,从而实现跨模态的理解和检索。
总结

本节课中,我们一起学习了视觉语言模型的核心思想。我们探讨了如何通过将文本和图像映射到同一共享语义空间中的向量,并使用余弦相似度来衡量它们的关联。我们回顾了文本通过词嵌入和位置编码转换为向量的过程,以及图像通过分块或卷积神经网络转换为向量的方法。这些概念为我们从零开始构建一个简化的NanoVLM模型奠定了坚实的基础。在接下来的实践中,我们将把这些理论付诸实施。
012:视觉语言模型的对比学习 🎯
在本节课中,我们将要学习对比学习(Contrastive Learning)的核心概念,并了解它为何在像CLIP这样的视觉语言模型中至关重要。我们将从对比学习的基本思想开始,逐步深入到其在多模态模型中的应用。



在上一讲中,我们介绍了视觉语言模型(VLM)的基础架构。本节中,我们来看看如何通过对比学习来训练这些模型,使其能够理解图像和文本之间的关联。
对比学习的重要性


CLIP模型是OpenAI提出的一个著名视觉语言模型,它成功应用了对比学习的思想。这篇论文被广泛引用。然而,对比学习在图像领域的流行,则是由另一篇更早的论文所推动的。该论文为图像-文本数据或纯图像数据集引入了一个简单的对比学习框架,并彻底改变了该领域的实现方式。
视觉语言模型回顾
在深入对比学习之前,我们先简要回顾上一讲的内容。一个基础的视觉语言模型通常包含以下部分:
- 一个用于处理图像的图像编码器。
- 一个用于处理文本的文本编码器。
- 一个可选的融合模块,用于结合图像和文本的嵌入表示。
融合模块可以是Transformer架构本身,例如对拼接后的图像和文本嵌入进行联合注意力计算,或者使用交叉注意力机制。其目标是让图像和文本的向量表示在同一个“联合嵌入空间”中对齐。在这个空间中,语义相似的图像和文本(例如“一只快乐的狗跑向相机”的图片和文字)对应的向量会非常接近,它们的余弦相似度会很高。
什么是对比学习?🤔
对比学习的核心思想非常简单:最大化正样本对之间的相似性,同时最小化负样本对之间的相似性。
为了理解这个概念,我们可以看一个例子。假设我们有一张狗的图片作为“锚点”(Anchor)。通过对这张图片进行一些变换(如转为黑白、旋转、裁剪),我们可以得到它的“正样本”。这些变换后的图片与原始锚点图片构成正样本对。而数据集中其他不同内容的图片(例如猫或汽车的图片)则与锚点图片构成负样本对。
我们的目标是训练模型,使得:
- 锚点图片与其正样本在嵌入空间中的距离尽可能小(相似度高)。
- 锚点图片与负样本在嵌入空间中的距离尽可能大(相似度低)。
以下是论文中提到的一些常见图像变换方式,用于创建正样本:
- 裁剪和调整大小
- 水平翻转
- 转换为灰度(黑白)
- 颜色抖动
- 旋转
- 随机遮挡(Cutout)
- 添加高斯噪声
通过这种方式,模型无需人工标注的精细标签,就能学习到数据中强大的、具有不变性的特征表示。
对比损失函数
为了实现上述目标,我们需要一个专门的损失函数,即对比损失。其核心公式可以简化为以下思想:
对于一个锚点样本 x,其正样本为 x⁺,负样本集合为 {x⁻}。模型通过编码器 f(·) 将样本映射为向量。对比损失鼓励以下关系:
相似度( f(x), f(x⁺) ) >> 相似度( f(x), f(x⁻) )


其中,相似度通常使用余弦相似度或点积来计算。一个具体的、广泛使用的实现是InfoNCE损失(归一化温度标度交叉熵损失),其公式如下:
L = -log( exp(sim(q, k⁺) / τ) / Σ_{i=0}^{K} [ exp(sim(q, k_i) / τ) ] )
其中:
q是锚点样本的查询向量。k⁺是正样本的键向量。k_i包括正样本和K个负样本的键向量。sim()是相似度函数(如点积)。τ是一个温度参数,用于调节分布的尖锐程度。
这个损失函数本质上是一个交叉熵损失,目的是在给定查询 q 时,从一批样本中正确识别出正样本 k⁺。
对比学习在CLIP中的应用


CLIP模型将对比学习的思想应用到了图像-文本对数据上。它的训练过程非常直观:
- 一个批次中包含
N个真实的图像-文本对。 - 图像编码器和文本编码器分别处理图像和文本,得到
N个图像向量和N个文本向量。 - 计算所有图像向量和文本向量两两之间的相似度,形成一个
N x N的矩阵。 - 矩阵的对角线位置代表了正确的(正样本)图像-文本对,其余位置都是负样本对。
- 训练目标就是最大化对角线上的相似度(正样本),同时最小化非对角线上的相似度(负样本)。这通过对称的交叉熵损失来实现。
通过在海量的互联网图像-文本对上进行这种对比训练,CLIP学会了将任意图像和文本映射到一个共享的语义空间,从而实现了强大的零样本(Zero-Shot)分类和检索能力。
总结

本节课中我们一起学习了对比学习。我们从其最大化正样本相似性、最小化负样本相似性的核心目标出发,回顾了它在视觉语言模型(如CLIP)中的关键作用。我们了解了如何通过图像变换构造正样本对,并介绍了实现对比学习目标的InfoNCE损失函数。最后,我们看到了CLIP如何巧妙地将这一框架应用于海量图像-文本数据,从而学习到一个通用的、对齐的多模态表示空间。对比学习是一种强大的自监督学习范式,它使模型能够从数据本身的结构中学习,减少了对大量人工标注的依赖。
013:视觉语言模型(VLM)入门 🖼️📖
在本节课中,我们将首次在本系列中探讨多模态大语言模型。具体来说,我们将介绍如何将大语言模型的应用背景从纯文本数据扩展到包含视觉数据,其中最简单的视觉数据就是图像。
上一节我们详细介绍了视觉Transformer。我们讨论的那个特定架构的唯一缺点是它无法处理文本。我们通过将图像转换为图像块,再将图像块标记化,然后利用这些标记进行图像分类,这依赖于分类标记。
在视觉语言模型中,其架构允许你同时创建基于文本的数据和基于图像的数据的嵌入表示。现实世界中的大多数数据集都是多模态的,意味着存在不同的模态,例如音频、文本、视觉等。视觉本身可以是图像,也可以是视频(视频被转换为帧)。任务范围可以从图像描述到视觉问答,即根据特定图像内容向模型提问,模型需要作出回应。在所有这类情况下,视觉语言模型都非常有用。
现在,VLM是一个非常宽泛的术语,并不特指某一种架构。当我们通常说“视觉Transformer”时,我们倾向于想到谷歌论文中提出的那个特定架构。但对于视觉语言模型,当我们谈论VLM时,存在许多不同的架构。当然,有些论文引用率高,有些引用率低,但并没有一个单一的架构能专门定义什么是VLM。在今天的课程中,我们将了解视觉语言模型的一些基础知识,以及它如何构成一个多模态LLM。
著名的视觉语言模型论文 📄




以下是几篇著名的视觉语言模型论文。

- CLIP论文:由OpenAI提出。这篇论文引入了对比学习的思想。虽然对比学习作为一个概念在CLIP论文之前就已提出,但该论文利用对比学习思想构建了一个视觉语言模型。这是一篇稍长的论文,算上附录共48页。作者之一是Elias Sa scver,他曾是OpenAI的成员。
- VisualBERT论文:该论文对BERT架构进行了扩展。BERT架构主要用于文本,而这篇论文展示了如何将非常相似的BERT架构扩展到从图像中学习表示。他们提出了这个架构。我不会深入细节,但会说明当你同时有输入文本和输入图像时,视觉语言模型可能是什么样子。这篇论文大约有2500次引用。
- ViLBERT论文:这篇论文可以看作是VisualBERT的扩展。两篇论文大约同时发表。他们使用了类似交叉注意力的机制。具体来说,他们独立地对视觉流和文本流应用注意力机制,但不同之处在于,图像流的查询关注文本流中的键和值,而文本流的查询关注图像流中的键和值。

如果你不完全理解所有这些术语的含义,请不要担心。我的目的不是吓唬你,只是想向你展示存在多种不同的架构,所有这些都属于不同类型的视觉语言模型。因此,当你听到“视觉语言模型”这个术语时,不要立即想到某个具体的模型架构,它可以指代许多不同的东西。相反,应该思考它能完成什么任务:它可以接收文本数据、图像数据并执行某些操作,而且它也可以是针对特定任务的。


视觉语言模型的核心思想 💡
现在,让我们从宏观上看看VLM背后的思想,以及它试图实现什么。





基本思想如下:假设我写下单词“苹果”,或者向你展示一张苹果的图片。这两件事表达的是同一个意思。当你在大脑中形成苹果的图像时,这个图像可以是通过阅读“苹果”这个文本形成的,也可以是通过观看苹果的图片形成的。归根结底,这个文本和这张图片在你的大脑中是以非常相似的方式表示的。
我们不知道大脑究竟如何精确表示文本和图像,但视觉语言模型背后的基本思想是:如果我们将文本转换为标记(即向量),同样地,如果我们也能够将图像转换为标记(即向量),那么对应于“苹果”文本的向量和对应于苹果图像的向量应该具有非常高的相似性,即非常高的余弦相似度或语义相似度。
这个想法在下图中得到了很好的展示。请看这张图,我绘制了两个坐标轴(当然我只能绘制这么多)。假设这是一个n维空间,这就是为什么我在第二个坐标轴上标注了“特征1”和“特征n”。
现在,这里有一组向量。这个向量对应于狗的图像的嵌入表示,这个向量对应于狗的文本的嵌入表示。因此,“狗”这个文本被转换成一个嵌入向量,“狗”这个图像也被转换成一个嵌入向量。理想情况下,这两个嵌入向量在这个空间中应该彼此接近。
同样的情况也适用于“猫”,其文本嵌入和图像嵌入在相同的维度空间中应该具有非常高的相似性。理想情况下,向量的模长应该大致相似,余弦相似度也应该很高。如果你有“苹果”的文本和苹果的图像,它们也应该具有良好的相似性。对于“橘子”也是如此。
现在,如果你观察所有这些向量,所有这些都是从水果的文本或图像创建的嵌入表示。因此,所有这些嵌入表示总体上应该指向一个代表水果的语义空间,这就是我通过这个绿色椭圆向你展示的。
而这四个向量是从这些动物的图像或文本创建的。因此,这四个嵌入表示总体上应该指向一个代表动物的语义空间,用这个蓝色椭圆表示。
因此,文本嵌入和图像嵌入应该以某种方式捕捉相同的含义,前提是我们认为这两个嵌入属于相同的维度空间。我们可以称之为共享特征空间。
与之前模型的对比 🔄
在通常的AI设置中,特别是我们在课程中到目前为止讨论的内容,我们研究了大语言模型,并且只考虑了基于文本的输入。我们试图进行下一个词的预测,因此下一个词预测的目标得以实现。
输入是文本,文本被标记化,然后标记化的文本用于构建注意力权重矩阵,最后注意力权重矩阵用于创建下一个词可能是什么的概率分布,输出是一个文本(基本上是从你的词典或词汇表中选取的一个标记)。
在上一讲中,我们讨论了视觉Transformer。在视觉Transformer中,输入是一张图像,我们通过创建图像块将图像转换为标记。每个图像块是图像的一部分,这些图像块是不重叠的。每个图像块的尺寸大约是16x16(取决于具体的架构)。我们在上一讲中也从头开始编写了一个视觉Transformer的代码,其中图像块尺寸是7x7,图像尺寸是28x28,因此每张图像被转换为16个图像块。这些图像块加上一个分类标记都被转换。
总结 📝

本节课中,我们一起学习了视觉语言模型的基础知识。我们了解到VLM是一个宽泛的术语,涵盖多种能够同时处理文本和图像输入的架构。其核心思想是在一个共享的特征空间中,让相同语义的文本嵌入和图像嵌入彼此接近。我们还回顾了几篇重要的VLM论文,并将VLM与之前学习的纯文本LLM和视觉Transformer进行了对比,明确了VLM在多模态任务中的定位和作用。
014:Vision Transformer论文精读
在本节课中,我们将一起精读一篇具有里程碑意义的论文——Google于2020年提出的Vision Transformer。这篇论文展示了Transformer架构在无需卷积操作的情况下,如何有效地完成图像分类任务。它至今已获得超过75,000次引用。本教程旨在分享我在录制精讲视频过程中的一些思考与建议,帮助你更有效地阅读和理解这篇论文。
论文精读的挑战与策略
上一节我们介绍了本节课的目标。本节中,我们来看看在深入研读这篇长达22页(含参考文献)的论文时,可能遇到的挑战以及应对策略。
我意识到,试图将一篇完整的论文精读压缩到30分钟内是不现实的。如果目标是单纯讲解Vision Transformer模型,那会容易得多,但作为系列课程中的论文精读环节,我必须深入细节,这导致讲解时间不可避免地变长。
另一个显著的问题是精力消耗。长时间集中精神阅读、处理和讲解论文内容,在生理和心理上都极为疲惫。我预计你在观看学习时也会遇到同样的疲劳和思维饱和问题。
因此,我为自己制定了策略,也强烈建议你采用:
以下是应对长时间深度学习的建议:
- 分段学习:不要期望一次完成整篇论文的研读。我在录制时也采取了分段方式,并在需要时休息。你也应该如此,合理安排休息。
- 使用纸质版:我准备了一份论文的打印稿,并用笔进行标记和批注。手持实体论文逐行阅读的感受完全不同。如果你有条件,也打印一份,并可以边看论文边听视频讲解。
- 创造深度工作环境:我深受Cal Newport《深度工作》一书的影响。书中假设,深度工作是在无干扰状态下进行的专注职业活动,它能将你的认知能力推向极限。为了录制,我关闭房门、手机调至飞行模式,确保零干扰。这种努力能创造新价值、提升技能且难以复制。阅读研究论文这类困难任务,需要你投入时间并克服过程中的疲惫感。
本课程的设计理念与期望
上一节我们讨论了学习策略,本节我们来明确本课程的核心设计理念以及对学习者的期望。
我的目标不仅是讲解概念,更是要“精读”论文。这意味着我需要逐行阅读论文文本,剖析其写作本身,而不仅仅是其背后的思想。因此,我选择保持论文原有的结构,而非将其转化为更简短的概述或精美的PPT。虽然后者对多数观众可能更方便,但这违背了“精读”的初衷。
在准备过程中,我不断反思这样做的意义:
- 为了培养并提升我自身阅读论文的习惯,并希望将其转化为终身技能。
- 希望引导你也培养起这种习惯。
我提醒自己,也提醒你:感到疲惫和思维饱和是完全正常的,我们不应为此过于苛责自己。关键在于认识到困难并找到克服的方法,例如充分利用休息时间。
此外,我假设本课程的观众是具备自我驱动力的成年人。你们知道自己为何而来——是为了学习如何阅读科研论文并培养相关能力。因此,课程不会进行“填鸭式”教学,但会在必要时提供激励。
高效研读的具体工具与方法
明确了理念后,本节我们来看看能提升研读效率的具体工具和方法。
一个核心建议是:充分利用ChatGPT等工具。论文信息密度高,首次阅读能理解一半内容已属幸运。遇到不理解的段落或句子时,请坦然接受自己知识的局限。
以下是利用工具辅助理解的具体操作:
- 对不明确的内容进行截图。
- 将其提交给ChatGPT并提问。
- 关键在于主动提出疑问,这标志着你承认知识缺口并愿意借助工具(如AI、搜索引擎或他人)来填补它。
在精读过程中,我采用了在论文打印稿上做笔记的方式。为了在视频中复现这一过程,我将论文页面复制到数字白板软件中进行标注和讲解。
最后,关于视频形式的考量:我曾犹豫是否将内容分割为多个短视频。但最终决定保持为一个完整的长时间视频,因为人为地将论文分割成几部分可能破坏其连贯性,无法完全体现精读的完整性。
总结
本节课中,我们一起探讨了精读Vision Transformer这篇重要论文时可能面临的挑战,并分享了一系列应对策略与学习理念。核心要点包括:接受长时间深度学习的必然性并学会分段休息、使用纸质论文辅助精读、创造无干扰的深度工作环境、明确精读而非泛读的目标、以及善用AI工具解决理解障碍。记住,阅读科研论文是一项需要刻意练习的技能,感到困难是过程的一部分。希望这些经验能帮助你在论文精读的道路上更从容、更高效。
015:从零构建视觉Transformer (ViT) - 直觉与代码
在本节课中,我们将学习Transformer架构如何处理视觉输入。我们将深入理解视觉Transformer (ViT) 背后的核心思想,并从头开始用Python实现它。这是本系列课程中首次探讨图像作为Transformer的输入。


概述
到目前为止,我们已经探讨了Transformer的工作原理、注意力机制,以及单个token在大语言模型中的旅程。我们了解了Transformer如何处理基于文本的数据。现在,我们将看到当输入是图像时,它是如何工作的。本节课将聚焦于一篇著名论文提出的视觉Transformer。首先,我们将理解Transformer处理视觉数据的直觉,然后完全从零开始用Python实现一个视觉Transformer。
视觉Transformer的诞生
这篇题为《An Image is Worth 16x16 Words》的论文提出了视觉Transformer。这篇论文同样来自谷歌。原始Transformer论文《Attention Is All You Need》也出自谷歌。这清楚地表明谷歌在人工智能领域进行了大量开创性研究。
这篇论文所做的是在原始Transformer架构上进行极小的修改,从而扩展了其能力。他们想探究视觉Transformer的能力与卷积神经网络相比如何。卷积运算非常擅长捕捉图像中的二维特征,因为卷积滤波器本身就是二维的。但Transformer处理token的方式并非如此,因为token是序列,然后添加了位置嵌入,因此二维位置信息默认并不可用。虽然它可以被视为可训练参数,但默认情况下Transformer无法直接获取。卷积神经网络因卷积滤波器而享有的许多优势,在基于Transformer的架构中并不存在。这篇论文实际上讨论了所有这些内容,并指出对CNN的依赖并非必要,尤其是在拥有大规模数据集时。他们表明,对于大规模模型,视觉Transformer在计算上甚至比卷积神经网络更高效。这篇论文写得非常出色,我曾在另一个系列中对其进行过详细解读,强烈推荐大家查阅。
事实上,过去我曾做过一讲关于从零开始编写Transformer的课程,但那个课程的背景非常不同,它不属于“多模态LLM中的Transformer”系列。而现在这个背景非常完美,因为我们已经讨论了Transformer的所有相关内容,现在我们已经准备好完全理解图像是如何被处理的。
文本与图像处理的差异
首先,我们来理解Transformer处理文本和图像的差异。
在文本处理中,你有一个句子,它被分词成token。这些token本质上是向量。在这些向量上,你还添加了位置嵌入。分词过程负责将文本转换为token,然后将token转换为输入嵌入。通过添加位置嵌入,初始的文本嵌入被转换为输入嵌入。
在像GPT这样的模型中,有一种称为掩码自注意力的机制。之所以需要这种掩码,是因为正如我们在系列早期讨论过的,如果你试图预测下一个词,当前的查询不应该看到未来的token,即当前查询不应该关注未来的token。例如,如果我们有一个句子“The cat sat on the mat”,如果GPT将其视为下一个词预测任务,并且输入只有“The cat sat on”,那么最后两个词是不可用的,需要被预测。给定这四个词,GPT必须预测下一个词,给定输入的前四个词加上预测出的一个词,它可以预测再下一个词。观察生成的上下文向量,每个词(或token)都会有一个关联的上下文向量。用于预测下一个词的是最后一个token(例如“on”)的上下文向量。
在构建上下文向量时,如果我们的查询是“on”,那么序列中的所有词(“The”、“cat”、“sat”、“on”)都是键。实际上,如果看整个句子(包括输入和预测),有很多键。但关键是,查询不应该关注那些未来将要出现的键。因此,“on”应该只关注“The”、“cat”、“sat”和“on”本身。“sat”应该只关注“The”和“cat”。因为“on”只有在“sat”之后才会出现。为了预测下一个词,当前查询无法关注未来的token,这就是所谓的掩码自注意力,我们在上一讲中详细讨论过。
这种掩码是GPT类架构的重要特征,它是一个生成模型,旨在生成文本。这种掩码在BERT中并不需要,尽管BERT有不同类型的掩码。BERT是双向编码器,它有一个掩码token,任务是预测这个掩码token的值。为了构建上下文向量,注意力会关注序列中的每一个token,而不仅仅是之前的token,因为这里的目的是预测下一个词。
现在思考一下这个下一个词预测任务,它本质上是一个softmax分布。如果你的词典有5万个词或token,你将得到一个类似这样的softmax分布。其中一个token可能具有最高的概率。这几乎就像一个分类任务,类别数量是5万。如果是10分类任务,你会有一个跨越10个不同类别的概率分布;如果是5万分类任务,你会有一个跨越5万个类别的softmax概率分布。这正是GPT中发生的情况,因为它有一个特定的词典大小。GPT只需要说出词典中可用的5万个token中哪一个最有可能成为下一个token。这与分类任务非常相似。
视觉Transformer的任务
那么视觉Transformer做什么呢?视觉Transformer做的事情非常相似。
它输入一张图像,然后对图像进行分词。我将详细说明这种分词具体是如何发生的。想象一下,你以某种方式将图像转换成一堆token,token就是向量,就像你将文本输入句子转换成token一样,那些token也是向量。
但在图像中,你的任务不是预测下一个token。你不是试图预测下一个词或任何类似的东西。你不是在预测...
视觉Transformer的主要任务是图像分类。它输入图像,输出一个类别标签。其核心思想是将图像分割成固定大小的块(例如16x16像素),将这些块线性投影成向量(即“图像token”),然后像处理文本token序列一样,将这些向量序列输入到标准的Transformer编码器中。最后,使用一个特殊的“[CLS]” token的表示来进行分类预测。
总结

本节课中,我们一起学习了视觉Transformer的基本概念。我们了解了其诞生的背景,以及它如何将处理序列的Transformer架构应用于图像分类任务。核心在于将图像视为一系列“视觉token”的序列。下一节,我们将深入探讨如何具体实现这种图像到token的转换,并开始动手编写代码。
016:手动计算GPT-3的1750亿参数
在本节课中,我们将学习一项非常具体的任务:手动计算GPT-3模型是如何达到总计1750亿个参数的。这个练习将帮助我们深入理解大型语言模型(LLM)的架构本身,并让我们清楚地了解这些参数是如何在架构内部分布的:有多少在神经网络的输入部分,有多少在Transformer层中,又有多少在输出部分。
如果你不了解大型语言模型的架构,我强烈建议你先观看至少一个详细解释架构的视频。因为在本课中,我不会深入讲解Transformer架构的所有细节,那会使课程变得冗长。相反,我会假设你对大型语言模型架构和Transformer块有基本的了解。然后,我将逐步引导你如何精确计算这些参数。
如果你忘记了LLM架构的具体样子,也不用担心,我会提供一个简短的回顾来帮你复习。
现在你可能会想,GPT-3的架构与基于视觉的任务有何关联?我解释这个内容的原因,是希望你能将本节课获得的直觉,同样应用到学习和理解视觉与Transformer结合的案例中。这就是我引入本节课的原因。
架构概览
首先,让我们看看LLM的整体架构图。



这是整体的图形架构。看到多个模块不必担心,我会将其划分为有意义的几个部分。

我们可以将整个LLM架构分为三个模块:
- 第一个模块是处理输入的部分。你提供一个输入或提示,然后对这个输入进行一些处理,包括分词和位置嵌入。我会解释这些含义,但请先记住这个概念。
- 然后是Transformer块,其中包含两个层归一化(图中两个蓝色块),在两个位置有Dropout操作,还有一个前馈神经网络,以及核心组件——多头注意力机制。
- 最后一个模块是输出块,大型语言模型在这里进行下一个词的最终预测,它包含一个归一化层和一个输出层。
在GPT-3架构中,这个Transformer块会串联重复96次。这是你会听到数字“96”的第一个地方。第二个你会听到“96”的地方是多头注意力机制内部头的数量,即并行有96个头。这两个“96”是不同的数字,请不要混淆。
我们的目标是计算这1750亿个参数是如何分布在这些模块以及各个子模块中的。让我们尝试计算一下。
GPT-3 175B 架构规格
一个拥有1750亿参数的GPT-3模型具有以下架构规格:
- 它有 96层。这意味着有 96个Transformer块 串联在一起。
- 每个词元(可以是一个词或子词)由一个 12,288维 的向量表示。
- 在每个Transformer层中,最重要的组件之一是多头注意力机制。每个多头注意力机制有 96个头。
- 在这些多头注意力机制内部,每个头负责处理输入词元维度的 1/96。这意味着
12288 / 96 = 128。因此,词元在这些注意力头内部不是以12,288维空间表示,而是在每个单独的注意力头中以128维空间表示,然后它们被拼接回一起,重新构成12,288维的词元。 - 此外,还有一个前馈神经网络。它的作用是将经过变换的12,288维词元,投影到一个维度扩大4倍的空间(即
12288 * 4 = 49152维),然后再投影回来。稍后计算参数时我会解释具体的数字,现在只是介绍架构相关的数字。 - 模型有一个词表,大小为 50,257。这意味着词表中存在这么多独特的词元。每个词元由一个12,288维的向量表示。
- 上下文长度,即可以输入GPT-3架构的词元数量,是 2048。
以上就是GPT-3 175B模型的一般架构规格。基于这些信息,让我们尝试计算参数数量,最终所有这些数字加起来应该等于1750亿。
参数计算:输入部分
词表嵌入参数
如前所述,输入词元是一个12,288维的向量。词表包含50,257个这样的词元。每个词元向量中的每个数字都是需要训练的参数,以便为每个词元获得良好的表示。
因此,词表中的参数数量为:
词表大小 * 词元维度 = 50,257 * 12,288
计算这个数字:
50,257 * 12,288 = 617,550,000 (约6.1755亿)
所以,在我们的输入嵌入中,有大约 6.1755亿 个参数。
位置嵌入参数
我们的上下文窗口大小是2048个词元。每个词元当然是12,288维的向量。但我们不会直接使用从词表中取出的词元值,而是在其上添加一个位置嵌入。
为什么位置嵌入很重要?例如,在句子“The dog chased another dog”中,“dog”这个词出现了两次,但第一次出现在位置2,第二次出现在位置5。因此,这两个“dog”的表示方式应该有所不同,这就是为什么需要为输入嵌入添加位置信息。
你需要的位置嵌入向量的数量,等于上下文窗口中的词元数量,即2048个。
因此,位置嵌入的参数数量为:
上下文长度 * 词元维度 = 2,048 * 12,288
计算这个数字:
2,048 * 12,288 = 25,165,824 (约2516万)
所以,在位置嵌入中,有大约 2517万 个参数。

上一节我们计算了输入部分(词表嵌入和位置嵌入)的参数。接下来,我们将深入Transformer块内部,看看参数是如何在多头注意力机制和前馈神经网络中分布的。
017:使用张量实现多头注意力
在本节课中,我们将学习如何高效地实现多头注意力机制。上一节我们介绍了通过循环遍历不同注意力头来朴素地实现多头注意力。本节中,我们将探讨一种称为“权重分割”的技术,它能让大型语言模型实现更好的可扩展性。我们将重点关注张量的维度,包括批次大小、令牌数量、每个令牌的维度以及注意力头的数量。课程结束时,你将清晰地理解多头注意力在实践中的数学原理和实现方式。

回顾多头注意力

上一节我们介绍了多头注意力的基本概念。在多头注意力中,我们拥有不止一个查询矩阵、键矩阵和值矩阵。下图很好地总结了上一讲的核心思想。
假设输入是一组维度为3的向量。我们需要使用查询权重矩阵、键权重矩阵和值权重矩阵,将这些输入向量转换到查询-键-值空间。
在单头注意力中,你只有一个权重矩阵。但在多头注意力中,如图所示,这里有两个查询权重矩阵 WQ1 和 WQ2,它们分别作用于输入,生成第一组查询 Q1 和第二组查询 Q2。因此,对于每个输入向量,你都有两个对应的查询向量。同样的逻辑也适用于键和值。这是具有两个注意力头的多头注意力的最简化形式。


维度转换与矩阵乘法



现在,因为你有两个注意力头,你将得到两个对应的注意力分数矩阵。



如何得到第一个查询矩阵 Q1?Q1 是你的输入 X 与 WQ1 的乘积:Q1 = X * WQ1。同理,Q2 = X * WQ2。这是一个矩阵乘法过程。




假设 X 是一个 6x3 的矩阵,这意味着有6个令牌,每个令牌有3个维度。同时,假设查询-键-值空间的维度为2。这意味着转换后,每个令牌的维度将变为2。

如何将一个 6x3 的矩阵转换为一个 6x2 的矩阵?只需将其与一个 3x2 的矩阵相乘。因此,你的 WQ1 和 WQ2 都是 3x2 的矩阵。这个 3x2 的矩阵会将你的 6x3 矩阵(6个三维令牌)转换为 6x2 矩阵(6个二维令牌)。这样,由于有两个注意力头,每个输入令牌将对应两个查询向量。


计算注意力分数与权重

要计算注意力分数,通常需要计算查询和键的点积,即 Q 乘以 K 的转置:Q * K^T。



现在,你有了两个注意力分数矩阵,而不仅仅是一个。每个矩阵的维度应该是 6x6(如果我们有6个令牌)。第一个矩阵是 Q1 和 K1 点积的结果:Q1 * K1^T。第二个矩阵是 Q2 和 K2 点积的结果:Q2 * K2^T。第一个矩阵代表了头1中查询和键之间的注意力分数,第二个矩阵则代表了头2中的注意力分数。

接下来,需要将注意力分数转换为注意力权重。这个过程分为三步:

- 缩放:将分数除以键空间维度的平方根。在我们的例子中,键空间维度为2,所以除以
sqrt(2)。 - 掩码:将上三角区域(未来时刻)的元素设置为负无穷大(
-inf)。这样,在后续应用Softmax时,这些位置会变为0。 - Softmax:对每一行应用Softmax函数,确保每一行的和都为1,从而得到注意力权重。


应用Dropout




在得到注意力权重后,通常会应用Dropout进行正则化。例如,如果Dropout概率 p = 0.5,则会随机“掩码”(置零)注意力权重矩阵中大约一半的元素。

未被掩码的剩余元素需要按 1/(1-p) 的比例进行放大。这样做的原因是,平均而言,我们只使用了一半的参数来计算输出。为了保持输出值的期望幅度不变,剩余有效权重的值需要相应放大。
应用Dropout后,我们得到了最终的、经过Dropout处理的注意力权重矩阵。

计算上下文向量



最后一步是计算上下文向量 Z。将经过Dropout的注意力权重矩阵与对应的值矩阵 V 相乘即可得到:Z = AttentionWeights * V。



在我们的例子中,有两个注意力头,因此有两个值矩阵 V1 和 V2,以及两个对应的注意力权重矩阵。每个权重矩阵(例如 3x3)与对应的值矩阵(例如 3x2)相乘,会得到一个上下文向量矩阵(例如 3x2)。最终,来自所有头的上下文向量会被拼接起来,形成最终的输出。







本节课中我们一起学习了多头注意力机制的高效实现方法。我们回顾了多头注意力的基本结构,详细讲解了通过矩阵乘法进行维度转换、计算注意力分数与权重、应用Dropout以及最终计算上下文向量的全过程。理解这些维度的变化和矩阵操作,是掌握现代Transformer模型如何并行处理多个注意力头的关键。
018:多头注意力机制介绍
在本节课中,我们将要学习多头注意力机制。我们将首先回顾之前课程的核心内容,然后深入探讨多头注意力的工作原理。你会发现,基于我们上节课学习的因果注意力知识,多头注意力其实非常简单。

课程回顾

上一节我们介绍了Transformer架构的整体视图,并将其分为输入、Transformer块和输出三部分进行讨论。然而,我们当时并未深入多头注意力的细节。



随后,我们开始学习注意力机制。首先,我们在神经机器翻译的背景下讨论了Bahdanau注意力。接着,我们讨论了自注意力机制。
在实现自注意力时,我们首先实现了一个简化版本,它不使用任何可训练权重,仅计算两个输入向量之间的点积作为注意力分数。
之后,我们讨论了带有可训练权重的自注意力。在这里,我们首次引入了用于查询(Query)、键(Key)和值(Value)的权重矩阵 WQ、WK 和 WV。其核心思想是将输入嵌入向量转换到查询、键、值空间,然后进行计算。
其核心公式如下:
- 计算注意力分数:
Attention Scores = (Q * K^T) / sqrt(d_k) - 应用Softmax得到注意力权重:
Attention Weights = softmax(Attention Scores) - 计算上下文向量:
Context Vector = Attention Weights * V
上节课,我们重点学习了因果自注意力(或称掩码自注意力)。它的核心是在计算注意力时,阻止查询(Query)关注未来时间步的键(Key),这通过将注意力分数矩阵的上三角部分设置为负无穷(-inf)来实现,这样在应用Softmax后,对应的注意力权重就会变为0。


我们还介绍了在注意力权重上应用Dropout,以随机丢弃部分连接,防止过拟合。
多头注意力:拼接方法

本节中我们来看看多头注意力。多头注意力的核心思想是并行运行多个独立的“注意力头”,每个头学习关注输入序列的不同方面,然后将所有头的输出组合起来。

在本系列课程当前讲座中,我们将讨论通过拼接每个注意力头输出的上下文向量矩阵来实现多头注意力的方法。



以下是多头注意力的实现步骤:



- 定义多个注意力头:首先,我们定义多个独立的注意力头。每个头都有自己独立的可训练权重矩阵
WQ_i、WK_i、WV_i,用于将输入投影到各自的子空间。假设有h个头,每个头的查询/键/值维度为d_k。





- 并行计算:对于每个注意力头
i,我们独立地执行完整的自注意力计算(包括缩放点积、掩码、Softmax等),得到一个上下文向量矩阵head_i。


- 拼接输出:将所有
h个注意力头计算出的上下文向量矩阵在特征维度上进行拼接。如果每个头输出的维度是(序列长度, d_v),那么拼接后的矩阵维度为(序列长度, h * d_v)。


- 线性投影:将拼接后的大矩阵通过一个可训练的线性投影层
W_O,将其映射回期望的输出维度。这一步允许模型整合来自所有头的信息。



其过程可以用以下伪代码描述:
# 假设输入 x 的维度为 (batch_size, seq_len, d_model)
# h 是注意力头的数量
def multi_head_attention(x, h):
heads = []
for i in range(h):
# 每个头有独立的权重
Q_i = x @ WQ_i # (batch_size, seq_len, d_k)
K_i = x @ WK_i
V_i = x @ WV_i
# 计算单个头的注意力
head_i = scaled_dot_product_attention(Q_i, K_i, V_i, mask)
heads.append(head_i) # head_i 维度: (batch_size, seq_len, d_v)
# 拼接所有头的输出
concatenated = concatenate(heads, axis=-1) # 维度: (batch_size, seq_len, h*d_v)
# 线性投影
output = concatenated @ W_O # 维度: (batch_size, seq_len, d_model)
return output

这种方法直观且易于理解,它明确地展示了多个独立注意力模块的并行计算与结果融合。


总结




本节课中我们一起学习了多头注意力机制。我们首先回顾了从Transformer架构、自注意力到因果注意力的知识路径。然后,我们重点讲解了多头注意力的第一种实现方法——拼接法。其核心在于并行运行多个独立的注意力头,每个头学习输入的不同特征表示,最后通过拼接和线性投影整合信息,从而增强模型的表示能力。在下一讲中,我们将探讨现代大语言模型采用的、更为统一的多头注意力实现方法。
019:理解因果注意力机制
在本节课中,我们将学习因果注意力机制,这是GPT等模型中实际使用的注意力机制。我们将了解其工作原理,特别是它与标准自注意力的区别。虽然我们将在下一讲中实现多头注意力,但今天我们将专注于理解掩码自注意力(也称为因果注意力)的核心概念。

自注意力机制回顾



在深入探讨因果注意力机制的细节之前,我们先快速回顾一下注意力机制的基本思想。
注意力机制的目标是为每一个输入嵌入向量生成一个对应的上下文向量。输入嵌入向量是每个词元(token)的直接向量表示,而上下文向量则包含了该词元周围其他词元的信息,因此信息更加丰富。


例如,对于句子“The cat sat on the mat”,如果简单地将词元“cat”转换为输入嵌入向量,它可能只代表“猫”这个词本身。然而,在句子中,“cat”与“sat”、“on”、“the”、“mat”等词元相关联。上下文向量就是为了将这种关联信息编码到“cat”的表示中。



如果句子有6个词元,那么输出就需要6个上下文向量。这些上下文向量比原始的输入嵌入向量包含更丰富的信息。

简化的自注意力
在两讲之前,我们实现了一个简化版本的自注意力。其核心思想是计算两个向量之间的点积,作为注意力分数的代理。


如果两个向量在语义空间中指向相似的方向,它们的点积就大,意味着它们应该更多地关注彼此。反之,如果向量正交(点积为0),则意味着它们之间关联不大。
然而,这种方法存在一个问题。考虑句子“The dog chased the ball, but it could not catch it.”中的最后一个词元“it”。“it”应该更多地指代“ball”而不是“dog”。如果直接使用输入嵌入向量的点积,可能会发现“it”与“ball”和“dog”的点积相似,无法有效区分。



引入可学习的变换


为了解决上述问题,我们在上一讲中引入了可学习的变换矩阵。我们不再直接使用输入嵌入向量计算点积,而是先将它们变换到查询(Query)、键(Key)、值(Value)空间。

以下是引入的三个变换矩阵:
- 查询矩阵
W_Q:用于将当前关注的词元(如“it”)变换到查询空间。 - 键矩阵
W_K:用于将所有词元(如“dog”、“ball”)变换到键空间。 - 值矩阵
W_V:用于将所有词元变换到值空间,用于最终生成上下文向量。

通过使用W_Q和W_K矩阵进行变换,再计算变换后向量的点积,模型可以学习到更复杂、更准确的注意力模式。例如,经过训练,变换后的“it”与变换后的“ball”的点积可以大于与变换后的“dog”的点积,从而正确捕捉“it”指代“ball”的语义关系。

因果注意力机制
上一节我们回顾了标准自注意力如何通过变换来捕捉词元间的关联。本节中,我们来看看因果注意力机制,它在此基础上增加了一个关键约束。


因果注意力,也称为掩码自注意力,是GPT等自回归语言模型的核心。它的核心思想是:在生成或处理一个词元时,模型只能“看到”或“关注”该词元之前(左侧)的词元,而不能“看到”未来的词元。


这模拟了人类阅读或生成文本的过程:我们写下一个词时,只知道前面已经写下的内容,而不知道后面将要写什么。对于语言模型来说,这确保了它在预测下一个词时,只基于已生成的上下文,从而保持生成过程的自回归特性。

工作原理

假设我们有一个包含5个词元的序列。在标准自注意力中,每个词元都可以关注序列中的所有其他词元(包括自身和未来的词元)。计算出的注意力分数矩阵是一个完整的矩阵。

在因果注意力中,我们需要对这个过程进行修改,以确保位置i的词元只能关注位置0到i的词元(包括自身)。这通过应用一个因果掩码来实现。


因果掩码是一个上三角矩阵(主对角线及以上为1,主对角线以下为负无穷大或一个非常大的负数)。在计算注意力分数后,将这个掩码加到分数矩阵上。

以下是应用因果掩码的关键步骤:
- 计算注意力分数:像标准自注意力一样,通过查询向量
Q和键向量K的点积计算原始注意力分数矩阵S。S的维度为[序列长度, 序列长度]。 - 应用因果掩码:创建一个掩码矩阵
M,其中M[i, j] = 0如果j <= i(允许关注),否则M[i, j] = -inf(禁止关注)。将M加到S上。- 公式表示为:
S_masked = S + M
- 公式表示为:
- 计算注意力权重:对掩码后的分数矩阵
S_masked的每一行应用softmax函数。由于被掩码的位置分数为负无穷,经过softmax后其权重变为0。- 公式表示为:
Attention Weights = softmax(S_masked, dim=-1)
- 公式表示为:
- 计算上下文向量:使用得到的注意力权重对值向量
V进行加权求和,得到最终的上下文向量。
通过这种方式,模型在生成每个词时,其上下文向量仅由它之前(包括自身)的词元信息聚合而成。


代码示例


以下是一个简化的伪代码,展示因果掩码的应用:


import torch
import torch.nn.functional as F
# 假设序列长度 seq_len = 5
seq_len = 5
# 1. 计算原始注意力分数 (S)
# S shape: [seq_len, seq_len]
S = ... # 通过 Q @ K.T 计算得出


# 2. 创建因果掩码 (M)
# 使用 torch.triu 生成上三角矩阵,对角线偏移为1,即主对角线为0,上三角部分为1
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()
# 将 mask 中为 True(即上三角)的位置设置为一个非常大的负数(如 -1e9)
causal_mask = torch.where(mask, torch.tensor(-1e9), torch.tensor(0.0))

# 3. 应用掩码
S_masked = S + causal_mask
# 4. 计算注意力权重
attention_weights = F.softmax(S_masked, dim=-1)



# 5. 计算输出
context_vectors = attention_weights @ V
总结

本节课中,我们一起学习了因果注意力机制。



首先,我们回顾了自注意力的核心目标:为每个输入词元生成富含上下文信息的向量。我们指出了直接使用输入嵌入点积的局限性,并回顾了通过可学习的查询、键、值矩阵进行变换以解决该问题的方法。

接着,我们深入探讨了因果注意力。我们了解到,因果注意力是标准自注意力的一个变体,它通过应用一个上三角掩码矩阵,强制模型在生成每个词元时只能关注它之前的词元。这种机制是GPT等自回归语言模型能够进行连贯文本生成的关键。



下一讲,我们将在此基础上,实现更强大的多头注意力机制。
020:可训练权重的自注意力机制
在本节课中,我们将深入学习自注意力机制。与上一讲我们通过向量点积实现简化版自注意力不同,这次我们将实现带有可训练权重的自注意力机制。这里所说的可训练权重,特指与键(Key)、查询(Query)和值(Value)相关的权重矩阵。这些术语在大语言模型(LLM)的语境中非常常见,因此,本节课旨在帮助你深入理解键、查询和值的概念。像GPT这样的大语言模型所使用的自注意力机制,也称为缩放点积注意力。



通过今天的学习,你将理解“注意力就是你所需要的一切”这篇论文中提到的这个公式背后的直觉。




现在这个公式可能看起来有些令人生畏,但请放心,在本节课结束时,你将从直觉层面很好地理解这个公式究竟在表达什么。

那么,让我们开始今天的课程。
课程回顾与背景
首先,让我们回顾一下本课程到目前为止讨论的内容。在上一讲中,我们讨论了简化的自注意力机制,通过使用词向量嵌入之间的点积来构建注意力分数。在那之前,我们从2014年引入的Bahdanau注意力开始讨论。
我们知道,Bahdanau注意力主要用于神经机器翻译的编码器-解码器架构中。在解码器中,每一个隐藏状态都可以访问编码器中的每一个隐藏状态。这些H1、H2、H3是编码器的隐藏状态,在引入注意力机制之前,解码器无法访问所有这些状态。由于注意力机制,解码器不再仅仅依赖于编码器输出的单个上下文向量,而是可以依赖于每一个隐藏状态,并构建解码器应对每个隐藏状态给予的相对重要性。这样,就减轻了最终上下文向量的压力。
如果你不记得循环神经网络中的编码器-解码器架构,也不必担心,这对今天的课程并不重要,我只是想做一个简要的回顾。如果你真的想了解Bahdanau注意力在2014年神经机器翻译背景下的出现,可以回顾我们讨论RNN如何从编码器-解码器架构开始,最终引入注意力机制的那一讲。
自注意力机制的目标
然而,在自注意力机制中,我们尝试做的事情有所不同。我们有一个输入序列,例如“Dream big and work for it”。我们想要为输入序列中的每个标记(token)构建对应的上下文向量。为简化起见,我们现在认为每个标记是一个单词,尽管在像GPT这样的模型中,它使用字节对编码,所以一个单词不一定是一个标记,可能包含字符和子词。
在这个序列中,我们有六个标记。对于每一个标记,我们都想生成一个对应的上下文向量。如果这是在神经机器翻译任务的编码器-解码器架构中,我们只会在序列末尾、编码器输出处产生一个上下文向量,并希望该上下文向量能嵌入序列中的所有信息。但随着自注意力机制的出现,我们不再需要这样做。我们可以计算序列中的每个单词应该“关注”或“注意”同一序列中的每个单词的程度,这就是“自注意力”这个名字的由来。
简化自注意力回顾
在今天的课程中,我们将把这些标记视为三维向量,以便于绘图。在上一讲中,我们以简化的方式实现了自注意力。我们有输入和嵌入向量,例如“Dream”、“big”、“and”、“work”、“for”、“it”。这是“Dream”的原始输入嵌入向量,这是“big”的嵌入向量,等等。
为了计算“Dream”应该给予“big”多少注意力,或者“work”应该给予“big”多少注意力,我们取了这两个向量之间的点积,并根据这些点积的大小构建了注意力分数。因此,如果有六个单词,并且我们将“big”视为查询(即我们当前正在查看的标记),我们可以构建六个注意力分数:一个在“big”和“Dream”之间,一个在“big”和它自身之间,一个在“big”和“and”之间,依此类推。
这些注意力分数没有归一化。我们在上一讲中讨论过,我们使用softmax函数对这些注意力分数进行归一化,使得对应于任何查询的六个注意力分数之和为一。因此,如果我们考虑查询是“big”,将会有六个对应于每个键的注意力分数。假设它们是0.1, 0.2, 0.2, 0.1, 0.3, 0.1。这些数字加起来等于1。
你可以将这些视为百分比。对于句子“Dream big and work for it”,这意味着“big”应该给予“Dream”10%的注意力,“big”应该给予自身20%的注意力,“big”应该给予“and”20%的注意力,等等。通过拥有这些归一化的注意力分数,我们可以直观地了解每个查询对同一序列中每个键的关注百分比。因此,注意力分数的归一化产生了所谓的注意力权重,这些由softmax计算得出的数字就是注意力权重。
为了构建上下文向量,我们将原始输入向量与对应的注意力权重相乘,然后将它们相加。例如,对于单词“big”,我们取注意力矩阵中对应于“big”查询的那一行权重,对输入向量进行加权求和,就得到了“big”的上下文向量。如果我们将这个上下文向量绘制出来,这就是我们在上一讲结束时得到的“big”标记的上下文向量。
引入可训练权重
但你可能已经注意到一件事:我们知道在大语言模型中,训练模型是至关重要的。然而,在这个注意力计算、这个自注意力计算中,没有涉及任何训练。没有可训练的权重。点积只是在我们已有的向量之间进行,标记化后我们有了对应于标记的向量,之后就没有更多可训练的权重参与了。我们只是通过点积得到注意力分数,然后使用softmax进行归一化得到注意力权重,然后取对应于任何给定查询的键的加权和,得到该特定查询的上下文向量。这就是我们在上一讲中所做的。
如果你真的想花些时间了解简化的自注意力,并且你是第一次观看本系列课程,请返回上一讲,花些时间学习简化的自注意力,以便更好地理解我们为什么对构建上下文向量感兴趣。简单来说,上下文向量非常重要,因为它嵌入了更好的含义,因此它更加丰富。

本节课总结

在本节课中,我们一起回顾了自注意力机制的基本目标,并与早期的Bahdanau注意力进行了对比。我们重点分析了上一讲中简化的自注意力实现,它通过点积和softmax归一化来计算注意力权重,并以此构建上下文向量。同时,我们指出了该简化版本的关键局限:缺乏可训练的权重。这为我们下一讲引入键(K)、查询(Q)、值(V)矩阵以及可训练的缩放点积注意力公式做好了铺垫。
021:自注意力机制简介与简化实现
在本节课中,我们将首次深入探讨自注意力机制的核心概念。为了简化理解,我们将考虑一个没有可训练权重的自注意力机制,并解释其含义。首先,我们将理解什么是自注意力,以及如何计算注意力分数以获得上下文向量。我们还将通过代码实现来加深数值层面的理解。


回顾:RNN与长距离依赖问题


在上一节关于神经机器翻译的讲座中,我们讨论了使用编码器-解码器架构的模型。我们以一个短句翻译为例:输入英文句子“This is a car”,编码器输出一个上下文向量,该向量承载了整个输入序列的含义。然后,这个上下文向量作为解码器的输入,解码器输出对应的法语句子。

然而,这种模型在处理长距离依赖时存在困难。什么是长距离依赖?

考虑一个更长的句子:“The teacher who was teaching a difficult concept to the students smiled.”。在这个句子中,“teacher”一词在开头,“smiled”在结尾。从逻辑上看,“smiled”这个动作与“teacher”之间存在长距离依赖关系,并且“smiled”应该更多地关注“teacher”而不是“students”。但在没有注意力机制的RNN中,解码器只能访问编码器输出的单一上下文向量,而无法直接访问编码器中间的所有隐藏状态,这使得模型难以学习这种长距离的依赖关系。
从Bahdanau注意力到自注意力
在上一讲中,我们介绍了2014年提出的Bahdanau注意力机制。它允许解码器的每一个隐藏状态都能访问编码器的所有隐藏状态。这意味着,在生成输出序列的每一个词时,模型可以基于加权的方式,关注输入序列中的每一个词,而不仅仅是最终的上下文向量。


Bahdanau注意力关注的是两个不同序列(编码器输入和解码器输出)之间的关联。其生成的注意力权重矩阵不一定是方阵,因为输入和输出序列的长度可能不同。


自注意力则泛化了Bahdanau注意力的概念。它不比较输入和输出序列,而是在同一个序列内部,计算序列中每个词对其他所有词(包括自身)的关注程度。例如,在句子“Americans speak English”中,自注意力机制可以帮助确定“English”这个词应该对序列中其他词(包括“Americans”和“speak”)赋予多少重要性。自注意力矩阵是一个方阵。
本节课重点:简化版自注意力机制
为了理解自注意力的基本原理,本节课我们将重点讨论一个简化版的自注意力机制,它不包含任何可训练的参数。
后续课程中,我们将深入讲解GPT等模型中使用的、包含可训练权重的实际自注意力机制,以及其衍生概念掩码自注意力和多头注意力。理解了基础的自注意力,这些高级概念将更容易掌握。

现在,让我们回到自注意力的核心思想。

自注意力的计算过程


假设我们有一个句子:“Dream big and work for it.”。在自注意力机制中,我们提出的问题是:对于序列中的某一个词(例如“big”),它应该对序列中的每一个词(包括它自己)赋予多少注意力或权重?

首先,我们需要知道,在自然语言处理中,词语通常被表示为词向量嵌入。每个词都被映射到一个高维向量空间中的一个点,这个向量是词语的数学抽象表示,承载了语义信息。语义相近的词,其向量在空间中的位置也相近。

以下是计算简化版自注意力的步骤:

- 获取词向量:将输入序列中的每个词转换为其对应的词向量。假设我们的词向量维度是3。对于句子“Dream big and work for it”,我们得到6个向量。
# 示例:假设的3维词向量 dream = [1, 0, 1] big = [0, 1, 0] and = [1, 1, 0] work = [0, 0, 1] for = [1, 0, 0] it = [0, 1, 1]


-
计算注意力分数:为了计算词
i对词j的注意力分数,一个简单的方法是计算它们词向量的点积。点积值越大,通常表示两个向量在语义上越相关。- 公式:
score(i, j) = vector_i · vector_j(点积) - 例如,计算“big”对“dream”的注意力分数:
score(big, dream) = [0,1,0] · [1,0,1] = 0*1 + 1*0 + 0*1 = 0
- 公式:
-
构建注意力分数矩阵:为序列中每一对词都计算点积,形成一个方阵。这个矩阵就是注意力分数矩阵。
dream big and work for it dream 2 0 1 1 1 1 big 0 1 1 0 0 1 and 1 1 2 0 1 1 work 1 0 0 1 0 1 for 1 0 1 0 1 0 it 1 1 1 1 0 2(注:此矩阵数值为示例,非严格由上例向量计算得出)
-
将分数转换为权重:直接使用点积分数可能数值范围不稳定。为了获得一个概率分布(所有权重之和为1),我们通常对每一行应用Softmax函数。
- 对“big”对应的行
[0, 1, 1, 0, 0, 1]应用Softmax。 - Softmax公式:
weight(i, j) = exp(score(i, j)) / sum_k(exp(score(i, k))) - 应用后,我们得到注意力权重矩阵。该矩阵中,“big”这一行的数值表示“big”这个词应该分配给序列中每个词的注意力权重。
- 对“big”对应的行

- 计算上下文向量:对于序列中的每一个词(例如“big”),其上下文向量是序列中所有词向量的加权和,权重即来自上一步计算出的注意力权重。
- 公式:
context_vector_i = sum_j(weight(i, j) * vector_j) - 这样,“big”的上下文向量就不再仅仅是它自己的词向量
[0,1,0],而是融合了它根据语义关系所关注的“dream”、“and”、“it”等其他词的信息的新向量。
- 公式:
通过这个过程,序列中的每个词都获得了一个新的、富含上下文信息的表示。这个新表示能够捕捉词与词之间的依赖关系,包括长距离依赖。

总结


本节课我们一起学习了自注意力机制的基础。我们从RNN处理长距离依赖的局限性出发,回顾了Bahdanau注意力如何连接编码器与解码器。接着,我们引入了自注意力的概念,它在一个序列内部计算词与词之间的关联。

为了理解其核心计算逻辑,我们重点探讨了一个简化版的自注意力机制。其关键步骤包括:
- 将词表示为向量。
- 通过点积计算任意两个词之间的注意力分数。
- 使用Softmax函数将分数归一化为概率分布的注意力权重。
- 对词向量进行加权求和,为每个词生成一个融合了上下文信息的上下文向量。



这个简化版本帮助我们清晰地看到了自注意力如何让模型动态地关注输入序列的不同部分。在下一讲中,我们将在此基础上,学习实际Transformer模型中使用的、包含可学习参数Q、K、V矩阵的完整自注意力机制。
022:从RNN到Transformer - 注意力机制导论
在本节课中,我们将学习注意力机制的演进过程。我们将了解循环神经网络中的编码器-解码器机制如何发展到2014年引入的注意力机制,并最终在2017年《Attention Is All You Need》论文中催生了自注意力机制。注意力机制不仅彻底改变了自然语言处理领域,也对计算机视觉产生了深远影响。
上一节我们讨论了在长句子或段落中,注意力机制如何有效捕捉长距离依赖关系。例如,句子中的第一个词和最后一个词可能高度相关,尽管它们相隔很远。同样的情况也发生在图像中,左上角的像素块和右下角的像素块可能高度相关,而注意力机制正是能够为你捕捉这种长距离依赖关系的工具。因此,本节内容在当前课程中具有非常重要的背景意义。
序列到序列模型
你或许听说过“序列到序列模型”这个术语。在这种模型中,你可以输入任何类型的序列,例如句子中的单词、单个字母,甚至是图像中的特征,而序列到序列模型能够将其转换为另一个序列。
这种模型最初主要用于机器翻译,因为翻译本质上就是将一种语言的序列转换为另一种语言的序列。例如,将英文句子“This is a car”转换为法文版本。
这种用于神经机器翻译的序列到序列模型非常流行,并且对于短句效果很好。当然,在处理长句时它也存在一些问题,我们稍后会讨论其原因。但首先,让我们理解序列到序列模型的工作原理,以及其内部结构。

编码器-解码器架构
这个神经机器翻译器本质上是一个编码器-解码器架构。你也会在Transformer的上下文中遇到这两个术语。《Attention Is All You Need》论文中提出的Transformer架构就采用了编码器-解码器架构。此外,像U-Net这样的语义分割模型也采用了类似的架构,它将输入图像编码为更小的空间维度和更多的通道数,然后在解码器部分进行重建。

编码器-解码器架构的核心思想是:编码器接收输入序列(例如英文句子),并将其编码为一个抽象的表示;解码器则接收这个表示,并将其解码为目标序列(例如法文翻译)。输入和输出都是按顺序处理的。




编码器的工作原理
现在,让我们聚焦于编码器部分,暂时忽略解码器。
编码器的任务是接收一个输入序列。我们之所以称之为序列,是因为你可以将一个句子视为一系列单词或标记。以“This is a car”为例,它可以被拆分为四个单词的序列。
这些单词被顺序输入到编码器中。在处理完整个序列后,编码器会输出一个称为“上下文向量”的东西。
这个上下文向量是一个单一的输出向量。它拥有N个维度(例如768维),其目标是捕获输入英文句子中包含的所有上下文信息或全部含义,并将其压缩到这一个向量中。
这个上下文向量作为编码器的输出,随后被馈送到解码器中。输入句子并不直接进入解码器,而是先被编码成上下文向量的格式。然后,解码器尝试将这个上下文向量转换为最终的目标语言(例如法文)。
这些输出单词也是按顺序生成的,就像输入被顺序送入编码器一样。为了生成这三个单词,解码器的输入仅仅是这一个上下文向量。
你可以这样想象这个过程:你有一种语言的输入序列,将其转换为上下文向量形式的抽象表示。你希望这个抽象表示能捕获输入句子的某些含义,但这个表示本身不属于任何人类语言,它属于数学语言,只是一串数字。然后,你尝试从这个抽象表示(即上下文向量)转换回另一种人类语言(法语)。这就是解码器的工作。你可以认为编码器将输入转换到另一个向量空间,而解码器则将该向量空间转换回你的目标语言。
从序列到上下文向量
接下来的问题是:如何从英文输入序列得到这个抽象的数学概念——上下文向量?
具体做法是:首先将单词转换为向量。单词“This”、“is”、“a”、“car”被转换为四个输入向量。这些向量是这些单词的数学表示。
通常,这些向量承载着含义。我们可以将其想象成一个特征空间。假设每个向量有768个维度(这个数字只是举例,实际取决于词向量转换方法)。这个想法是,向量的方向承载着特定的语义。
例如,代表“apple”和“orange”的向量可能指向空间中语义相似的区域,这个区域代表“水果”的语义空间。另一方面,代表“dog”和“cat”的向量可能指向代表“动物”的语义空间的另一个方向。
因此,将单词转换为向量的核心思想是:单词对人类来说承载意义,同样地,这些向量也承载意义,它们编码了这些单词的语义含义,而不是随机数字。
一旦你有了这四个输入向量,你就有了编码器的输入基础。
总结

本节课中,我们一起学习了注意力机制的演进背景。我们介绍了序列到序列模型及其核心的编码器-解码器架构。我们详细探讨了编码器如何将输入序列(如单词)转换为数学向量,并最终压缩成一个承载整个句子语义的上下文向量。这个过程是理解后续注意力机制如何解决传统编码器-解码器模型(特别是处理长序列时)局限性的重要基础。下一节,我们将深入探讨这种传统架构的短板,以及注意力机制是如何作为其自然演进而出现的。
023:单个Token的旅程 - LLM入门
在本节课中,我们将深入探讨Transformer架构的核心工作原理。我们将从一个完全初学者的视角出发,通过追踪单个“Token”在模型中的旅程,来理解Transformer如何运作。无论您之前是否了解Transformer,本节课的内容都将为您打下坚实的基础。


在上一讲中,我们讨论了为什么需要Transformer来捕捉图像中的长距离依赖关系,这是CNN难以做到的。本节中,我们将首次深入探讨Transformer的实际架构。
我们将从大型语言模型的角度进行讨论,而不是视觉Transformer。然而,我们今天学到的所有知识,在后续讨论视觉Transformer时都将直接适用。
我以完全适合初学者的方式安排了今天的课程。您无需事先了解Transformer。我们将尝试从单个Token的视角来理解Transformer的运作方式。我会定义什么是Token,并通过观察这个Token的旅程来了解Transformer的操作。
我相信大家都熟悉2017年发表的著名论文《Attention Is All You Need》。这篇论文由谷歌发布,彻底改变了人工智能领域。它首次提出了“自注意力”的概念,我们将在本课程中讨论这一点。这改变了人们实现自然语言处理的方式。Transformer是这篇论文的核心部分,其中引入了自注意力机制。后来出现了许多其他变体,如Flash Attention等,但基础模型仍然是那篇论文中提出的。
让我们看看Transformer架构是什么,以及它究竟如何工作。请准备好深入其中,如果需要可以暂停视频并重看某些部分。请保持高度专注,因为我们将实际讨论Transformer中每个模块的具体工作原理。
这可能是互联网上目前最著名的Transformer架构图。我在图像上叠加了两个东西:一个浅红色的框和一些文本符号。但您看到的核心内容,是《Attention Is All You Need》论文中的Transformer架构图。
在今天的课程中,我们不会看整个架构,因为它由两部分组成:编码器和解码器。编码器存在于像BERT这样的模型中,BERT基本上是仅编码器架构。解码器存在于像GPT这样的模型中,GPT是仅解码器架构。因此,如果您理解了解码器的工作原理,您就基本理解了GPT或ChatGPT的工作原理。我们今天课程的重点将放在仅解码器架构上。不过不用担心,如果您理解了这部分的工作原理,您就理解了整个Transformer架构,其余部分非常简单。
这就是我们的起点。现在的问题是,虽然这张图包含了一切,并且对初学者来说是最著名的图,但它并不十分友好,因为其中发生了太多事情,有太多术语和连接不同模块的箭头。除非您有特定的视角或一些先验经验,否则很难读懂图中发生了什么。因此,我将向您展示我构建的同一张图的不同版本,并引导您了解仅解码器模型的不同模块。
大型语言模型是做什么的?大型语言模型简单地预测下一个词。您可以打开ChatGPT并提问,观察它回答的方式:它一次打印一个词。大型语言模型执行的基本任务称为下一个词预测。一旦您得到下一个词,您可以将其添加到已有的词序列中,现在您有了另一个输入,然后尝试预测下一个词,再将其添加到现有序列中,并迭代执行此过程以产生长的回答。因此,输入或提示是您给出的句子或序列。模型是大型语言模型,可以是GPT或任何其他模型。输出在某一时刻是预测出的下一个词,这个过程被重复以产生整个段落。
因此,如果我们能理解Transformer架构内部如何进行下一个词预测,我们就能基本理解像ChatGPT或GPT这样的模型是如何工作的。
现在让我们看看这个简化的图在现实中如何运作。这里我向您展示的是一个显示仅解码器架构的简化或修改后的图。当我说仅解码器时,我指的是上图右侧的部分。这个右侧部分有一堆东西,我用稍微不同的方式画了出来。
我知道这里也有一堆事情在进行,这可能对初学者不太友好。因此,我不会要求您一次性看完整张图。我们将分部分查看整个架构。请关注三个主要部分:我们可以将整个架构分为三部分。第一部分是处理输入的部分,基本上是将输入转换为某种格式。输入是序列“The cat sat on the”。第二部分或第二个块称为Transformer块。第三部分是产生输出的地方,即进行下一个词预测的地方。
因此,我们将一次只看这些块中的一个。首先,我们将专注于输入部分。一旦我们完全理解了输入会发生什么,我们将转向Transformer块。然后,一旦我们完全理解了那里发生的事情,我们将转向输出部分。我们将以非常顺序化的方式剖析这个架构。
现在忽略右侧的所有内容,暂时忽略第2和第3部分。让我们只想想一旦您输入了提示,在Transformer的输入部分会发生什么。
现在我们只关注这一部分。您可以看到写了三样东西:第一是输入句子,第二是分词后的文本,然后我写了类似“词嵌入”和“位置嵌入”的东西。这些是什么?什么是Token?我们所说的词嵌入是什么意思?位置嵌入又是什么意思?
这部分您可能知道,这被称为提示或输入:“The cat sat on the”。现在,如果我们分别理解我标记为A、B、C的每一件事,我们就能理解Transformer架构的输入部分在做什么。
让我们先考虑一个输入。这个句子首先被拆分成单词。您可以将每个单词视为一个Token。这是一种简化的说法。在实际的Transformer架构中,您不会像这样将句子拆分成单词,还有子词和其他可以构成Token的字符。但为了简单起见,您可以说这个句子被分成了五个Token:The、cat、sat、on、the。我们将只关注一个Token,以便跟踪它在通过Transformer架构时发生的变化。因此,我们将关注“cat”这个Token,它是这个序列中的第二个Token。
如果您有兴趣了解这种分词具体是如何发生的,这种将输入拆分成Token的过程称为分词。分词的一种方法称为字节对编码。人们并非随机想出字节对编码,还有其他选择。您可以像我刚才展示的那样,仅基于单词进行分词:The、cat、sat、on、the。这样您就有了简化的Token。逻辑很简单:只要识别出一个单词,就将其转换为一个Token。这样做的问题是,如果词汇表中引入了一些新词,比如某种药物的名称或“Zic”这样的词,模型将无法识别它,因为它从未见过这个Token。因此,字节对编码是一种更复杂的分词方法,它试图将单词分解成更小的单元,以便模型能够处理未知词汇。但为了本课程的目的,我们将假设每个单词都是一个Token。

在本节课中,我们一起学习了Transformer架构的入门知识。我们从大型语言模型执行“下一个词预测”的基本任务开始,并引入了“Token”的概念。我们通过追踪单个Token(如“cat”)在模型中的旅程,来理解Transformer的工作流程。我们首先关注了架构的输入部分,介绍了将句子拆分成Token的“分词”过程,并简要提到了“词嵌入”和“位置嵌入”的概念,这些将在后续课程中详细展开。通过这种分步、聚焦于单个元素的方法,我们为深入理解Transformer的核心模块奠定了清晰的基础。在下一讲中,我们将继续探索Token在Transformer块内部的旅程。
024:Transformer为何在计算机视觉中超越CNN?


在本节课中,我们将要学习Transformer架构为何能在某些方面以优于卷积神经网络(CNN)的方式工作。我们将探讨CNN的局限性,并为理解Transformer在视觉任务中的应用奠定基础。
计算机视觉的三个时代
上一节我们介绍了计算机视觉的发展历程,本节中我们来简要回顾一下。在2012年AlexNet出现之前,是手工特征时代,特征被输入到SVM等机器学习模型中。随后是CNN革命时代,卷积神经网络迎来了黄金时期。自2020年谷歌提出Vision Transformer以来,我们进入了基于Transformer架构执行几乎所有视觉任务的时代。
CNN的优势与工作原理
在探讨CNN的局限性之前,我们应该先理解卷积操作在从图像中提取特征方面的优势。
以下是CNN架构的本质流程:
- 输入图像通过一系列卷积和ReLU激活函数操作。
- 可能包含池化操作(如最大池化、平均池化),以降低图像的空间维度(宽度和高度)。
- 随着图像通过层层处理,其空间维度越来越小,而通道深度(Z轴堆叠)越来越深。
- 最终,原始的RGB图像被转换为一个抽象的向量表示。这个向量中的值代表了图像中与当前任务相关的内容。


核心操作:卷积神经网络通过可训练的卷积核(滤波器)来提取特征。例如,一个3x3的滤波器会同时观察九个像素,并将它们的信息组合成一个输出像素。公式上,对于一个输入区域 I 和滤波器权重 W,输出值计算为:
output = sum(I[i,j] * W[i,j]) for all i, j in filter
在训练过程中,滤波器内的数值(权重)通过反向传播进行学习和调整。


CNN的局限性


理解了CNN如何工作后,我们现在来看看它的局限性,这些正是Transformer能够更好克服的地方。





CNN的核心局限在于其归纳偏置,特别是局部连接性和平移不变性。虽然这使得CNN能高效提取局部特征(如边缘、纹理),但也限制了其处理长距离依赖关系的能力。

一个3x3的卷积核每次只能看到其感受野内的像素。为了获取图像中两个遥远部分之间的关系信息,需要堆叠许多卷积层,让信息通过多层网络缓慢传递。这个过程效率较低,且可能丢失或模糊全局上下文信息。



相比之下,Transformer架构中的自注意力机制允许模型在单层内直接计算图像中任意两个位置(或“补丁”)之间的关系,无论它们相距多远。这使其天生擅长建模全局依赖。



总结


本节课中我们一起学习了CNN的基本工作原理及其优势,并重点分析了其在处理长距离依赖关系上的局限性。这种局限性源于卷积操作的局部特性。而Transformer凭借其自注意力机制,能够直接建立图像全局的关联,这正是它在许多复杂视觉任务中开始超越传统CNN的关键原因。在接下来的课程中,我们将深入探讨Transformer架构本身及其在视觉领域的应用模型。
025:课程介绍与讲师背景 🎯
在本节课中,我们将介绍全新的“视觉与多模态大语言模型中的Transformer”训练营。我们将了解课程的目标、内容结构、适用人群以及讲师的背景。


欢迎来到全新的训练营。这是“视觉与多模态大语言模型中的Transformer”系列课程的第一讲。
我是Sriad Pant博士。我拥有麻省理工学院博士学位,本科毕业于印度马德拉斯理工学院。
我也是Vizuara公司的三位联合创始人之一,并将担任本课程的讲师。
课程议程 📋
作为系列课程的第一讲,我计划介绍几个关键事项。


首先,我会向还不认识我的同学简单介绍一下自己。

其次,我会详细说明这个训练营的具体内容。从课程名称可以看出,它与Transformer架构密切相关。自ChatGPT问世以来,Transformer架构已经彻底改变了我们看待人工智能的方式。

我会明确说明这个训练营是否适合你,无论你的背景如何,是学生还是行业专业人士。
我将提及课程的先修要求、详细的课程大纲。


以及关于后续讲座如何进行的一些安排。

最后,我会说明你从这个训练营中可以收获什么。


讲师背景介绍 👨🏫
我是Sriad Pant博士,于2017年至2022年在麻省理工学院攻读博士学位。

我的专业领域是机械工程,但这是一个非常跨学科的项目。
因此,我参与了多个具有现实世界影响力的高影响力项目。
以下是我博士期间参与的一些有趣工作。
这是我在麻省理工学院实验室工作的照片。

我的一个论文项目与自主太阳能电池板清洁有关。

该项目的一个方面涉及计算机视觉,特别是卷积神经网络。这是我博士研究中直接应用计算机视觉和人工智能的部分。



但在攻读博士之前,我还参与过其他一些有趣的项目。
我想向大家展示我的工作。

我的研究成果在麻省理工学院的YouTube频道上有一个专题视频,目前已有近30万次观看。我会在描述中分享这个链接,你可以随时打开观看。
视频展示了我的最终实物成果。这是一个由机械臂驱动的机器人太阳能电池板清洁器,配有一个高压装置。施加的电压(以千伏计)取决于灰尘颗粒的大小。

灰尘颗粒有一个尺寸分布,你无法预知是10微米、20微米还是30微米等。因此,我们使用了一个带有可放大40-50倍摄像头的计算机视觉系统来收集脏污太阳能电池板的图片。然后,我使用卷积神经网络将这些图像分类到不同微米级别的颗粒尺寸桶中。
根据这个颗粒尺寸,我可以决定所需的除尘电压,因为颗粒尺寸和除尘电压之间存在直接关联,从而可以自动相应地调整电压。这就是我工作的核心。这在现实生活中有巨大的意义,可以防止目前用于太阳能电池板清洁的高达500亿甚至1000亿加仑淡水的使用。随着太阳能装机容量的增加,这个数字预计将呈指数级增长。

这是一个非常有趣的项目,我从中学习到了很多东西。
毕业后,我与Rajat博士和另一位联合创始人共同创立了Vizuara AI Labs。
自此,我们一直致力于让每个人都能接触和使用人工智能的使命。
我第一次在计算机视觉领域的研究经验远在麻省理工学院之前。


那大约是10年或更久以前,如果我没记错的话,大概在2015年初。当时我在印度马德拉斯理工学院工作,研究一个关于大米品种分类的问题。

问题是,我们拥有以各种方式拍摄的不同品种大米的图片。


有时图片是这样的,米粒分布稀疏,没有堆叠。
有时在图片中,这些米粒会堆叠起来,因此你完全看不到背景,只能看到一堆米粒。
我们致力于创建一个算法,该算法首先能够拍摄图片,在米粒周围创建边界。有时米粒会接触,有时边界会重叠,因此你必须找出不同的条件并调整你的逻辑。

最后,在这些米粒周围拟合椭圆,并使用这些椭圆的平均长度和平均宽度来判断这是Ponni米、Basmati米、茉莉香米等。
简单的逻辑是:你拍一张照片,如果米粒分布稀疏,你可以很容易地得到一个好的阈值分割。这些阈值分割技术是经典的计算机视觉技术,你可以创建执行阈值分割的滤波器,或者定义条件来消除低于某个数值的像素。
一旦你有了阈值图像,就可以执行边缘检测算法。这些算法同样使用滤波器执行,类似于卷积神经网络中使用的滤波器,尽管这些滤波器可能是手工设计的。一旦检测到边缘,逻辑就是在这些边缘周围拟合一个最小二乘椭圆,然后我将使用这个最小二乘椭圆的长和宽来表征米粒的大小。这就是基本思路。


在这种情况下,逻辑很简单,但存在边缘情况,例如两个米粒接触。在这种情况下,检测到的边界是一个单一的边界,其中包含了两个米粒。
然后我们必须添加逻辑,在这两个米粒之间绘制分界线。
接着,我们必须找到以最小二乘方式分别拟合这两个米粒的两个椭圆。否则,你可能只拟合一个像这样的椭圆,这是不正确的。因为这里有两个米粒。有时可能有三个、四个米粒,取决于方向,非常随机。因此,需要一个鲁棒的手工设计逻辑来分别检测米粒边界。

这个逻辑更加细致,但你可以看到,到目前为止,我没有提到任何关于深度学习的内容,也没有提到任何关于神经网络的内容,所有这些都是手工设计的逻辑。一旦我们收集了大量图片,并在这些米粒周围拟合了椭圆,我们就可以绘制它们。当我们绘制时,忽略这些名称和圆圈,忽略这个区域边界,但基本上我们会看到这些米粒会形成聚类:有些米粒宽度更大,有些米粒长度更长,有些介于两者之间。通过观察这些聚类,我们会知道我们有五个品种的大米,这里是五个聚类。现在,如果一个新的米粒出现,我可以执行一个机器学习算法,比如K均值聚类,或者其他简单的机器学习算法,比如K近邻算法等。这就是我们研究的问题陈述的核心。

我们将这篇论文提交给了在法国尼斯举行的第九届机器视觉国际会议,论文被接收,我们在那里展示了我们的工作。
那时是AlexNet模型(2012年提出,彻底改变了我们今天所见的深度学习)问世的三年后。
不同大学的教授们仍在研究用于识别米粒各种特征的手工设计特征。深度学习正在变得流行,但也有人像我们在马德拉斯理工学院的团队一样,致力于手工设计特征。

但在那次会议报告中,我非常清楚地认识到,深度学习正在完全接管计算机视觉领域。这种转变非常明显,因为手工设计特征和逻辑极其困难。如果我们用大量数据训练一个神经网络(卷积神经网络),这将会变得无限容易。

因此,从一个完全基于规则、不涉及深度学习的系统,你可以轻松地转向一种输入到输出的映射。你拥有对应的输入图像。


本节课中,我们一起学习了“视觉与多模态大语言模型中的Transformer”训练营的课程介绍、目标以及讲师的背景。我们了解到,从手工设计特征的经典计算机视觉方法到基于深度学习的现代方法,技术已经发生了深刻的变革。在接下来的课程中,我们将深入探讨Transformer架构如何进一步推动视觉和多模态领域的发展。

浙公网安备 33010602011771号