这真是一段疯狂的时光。人工智能研究领域再次涌现诸多进展,两项诺贝尔奖授予了AI相关研究,还有多篇有趣的研究论文发表。
其中,Meta AI发布了最新的Llama 3.2模型,包括1B和3B参数规模的开源大语言模型版本,以及两个多模态模型。
在本文中,我将解释多模态大语言模型的工作原理。此外,我还会回顾并总结近期(包括Llama 3.2在内)大约十几篇多模态论文和模型,以比较它们的技术路线。
(要查看目录菜单,请点击左侧的堆叠线条图标。)

但在开始之前,我也有一些个人方面的激动人心的消息要分享!我的书《从头构建大语言模型》现在终于可以在亚马逊上购买了!
写这本书付出了巨大的努力,我非常感谢过去两年里所有的支持和激励性的反馈——尤其是在最近几个月,许多热心的读者分享了他们的反馈。谢谢大家,作为作者,没有什么比听到这本书对你们的职业生涯产生影响更令人鼓舞的了!
对于那些已经读完这本书并渴望更多内容的人,请保持关注!我将在未来几个月内为GitHub仓库添加一些额外内容。
P.S. 如果你已经读过这本书,我非常感激你能留下一个简短的评论;这对我们作者来说真的很有帮助!
什么是多模态大语言模型?正如引言中所暗示的,多模态大语言模型是能够处理多种类型输入的大语言模型,其中每种“模态”指的是一种特定类型的数据——例如文本(如传统大语言模型)、声音、图像、视频等。为简单起见,我们将主要关注图像模态以及文本输入。
多模态大语言模型的一个经典且直观的应用是图像描述:你提供一张输入图像,模型会生成对该图像的描述,如下图所示。

当然,还有许多其他用例。例如,我最喜欢的一个是从PDF表格中提取信息,并将其转换为LaTeX或Markdown格式。
构建多模态大语言模型主要有两种方法:
-
方法A:统一嵌入解码器架构方法;
-
方法B:跨模态注意力架构方法。
(顺便提一下,我不确定这些技术是否有官方术语,但如果你见过的话请告诉我。例如,更简洁的描述可能是“仅解码器”和“基于交叉注意力”的方法。)

如上图所示,统一嵌入-解码器架构 使用单一解码器模型,与 GPT-2 或 Llama 3.2 等未经修改的大语言模型架构非常相似。在这种方法中,图像被转换为与原始文本标记具有相同嵌入大小的标记,使得大语言模型能够在拼接后同时处理文本和图像输入标记。
跨模态注意力架构 则采用交叉注意力机制,直接在注意力层内整合图像和文本嵌入。
在接下来的章节中,我们将从概念层面探讨这些方法的工作原理。然后,我们将查看近期关于多模态大语言模型的研究论文,了解它们在实际中的应用。
让我们从统一嵌入解码器架构开始,如下图所示。

在统一嵌入解码器架构中,图像被转换为嵌入向量,类似于标准纯文本大语言模型中将输入文本转换为嵌入的方式。
对于处理文本的典型纯文本大语言模型,文本输入通常会被分词(例如使用字节对编码),然后通过嵌入层,如下图所示。

与文本的分词和嵌入类似,图像嵌入是使用图像编码器模块(而非分词器)生成的,如下图所示。

上图所示的图像编码器内部发生了什么?为了处理图像,我们首先将其分割成更小的块,类似于分词过程中将单词拆分为子词。然后,这些块由预训练的视觉变换器(ViT)进行编码,如下图所示。
注意,ViT通常用于分类任务,因此我在上图中包含了分类头。但在本例中,我们只需要图像编码器部分。
上图中所示的“线性投影”由一个线性层(即全连接层)组成。该层的目的是将展平为向量的图像块投影到与Transformer编码器兼容的嵌入维度。下图展示了这个线性投影:一个展平为256维向量的图像块被上投影为768维向量。

对于喜欢看代码示例的朋友,在PyTorch中,我们可以这样实现图像块的线性投影:
import torch
class PatchProjectionLayer(torch.nn.Module):
def __init__(self, patch_size, num_channels, embedding_dim):
super().__init__()
self.patch_size = patch_size
self.num_channels = num_channels
self.embedding_dim = embedding_dim
self.projection = torch.nn.Linear(
patch_size * patch_size * num_channels, embedding_dim
)
def forward(self, x):
batch_size, num_patches, channels, height, width = x.size()
x = x.view(batch_size, num_patches, -1) # 展平每个图像块
x = self.projection(x) # 投影每个展平的图像块
return x
# 使用示例:
batch_size = 1
num_patches = 9 # 每张图像的总块数
patch_size = 16 # 每个块16x16像素
num_channels = 3 # RGB图像
embedding_dim = 768 # 嵌入向量的大小
projection_layer = PatchProjectionLayer(patch_size, num_channels, embedding_dim)
patches = torch.rand(
batch_size, num_patches, num_channels, patch_size, patch_size
)
projected_embeddings = projection_layer(patches)
print(projected_embeddings.shape)
# 输出
# torch.Size([1, 9, 768])
如果你碰巧读过我的《Machine Learning Q and AI》一书,你可能知道有一些方法可以用卷积层替换线性层,并且在数学上是等价的。在这里,这尤其方便,因为我们可以将创建图像块和投影合并为两行代码:
layer = torch.nn.Conv2d(3, 768, kernel_size=(16, 16), stride=(16, 16))
image = torch.rand(batch_size, 3, 48, 48)
projected_patches = layer(image)
print(projected_patches.flatten(-2).transpose(-1, -2).shape)
# 输出
# torch.Size([1, 9, 768])
现在我们已经简要讨论了图像编码器(以及作为编码器一部分的线性投影)的用途,让我们回到之前的文本分词类比,并排查看文本和图像的分词与嵌入,如下图所示。

如上图所示,我在图像编码器之后额外添加了一个 投影器 模块。这个投影器通常只是另一个与之前解释过的类似的线性投影层。其目的是将图像编码器的输出投影到与嵌入文本令牌维度相匹配的维度,如下图所示。(稍后我们会看到,投影器有时也被称为适配器或连接器。)

现在图像块嵌入与文本令牌嵌入具有相同的嵌入维度,我们可以简单地将它们拼接起来作为大语言模型的输入,如本节开头的图所示。下面再次展示同一张图,方便参考。

顺便一提,我们在本节讨论的图像编码器通常是一个预训练的视觉变换器。一个流行的选择是 CLIP 或 OpenCLIP。
然而,方法 A 也有直接在图像块上操作的版本,例如 Fuyu,如下图所示。

如上图所示,Fuyu 将输入图像块直接传入线性投影(或嵌入层)来学习自己的图像块嵌入,而不是像其他模型和方法那样依赖额外的预训练图像编码器。这极大地简化了架构和训练设置。
现在我们已经讨论了构建多模态大语言模型的统一嵌入解码器架构方法,并理解了图像编码背后的基本概念,接下来让我们谈谈通过交叉注意力实现多模态大语言模型的另一种方式,如下面的总结图所示。

在上图展示的跨模态注意力架构方法中,我们仍然使用之前讨论过的相同图像编码器设置。然而,我们不再将图像块编码后直接输入给大语言模型(LLM),而是通过交叉注意力机制,将输入图像块连接到多头注意力层中。
这一思路与2017年那篇开创性的论文《Attention Is All You Need》(https://arxiv.org/abs/1706.03762)中提出的原始Transformer架构一脉相承,如下图所示。

请注意,上图中原始的《Attention Is All You Need》Transformer最初是为语言翻译而开发的。因此,它由一个文本编码器(图的左侧部分)和一个文本解码器(图的右侧部分)组成,编码器接收待翻译的句子,解码器则生成翻译结果。在多模态大语言模型的背景下,编码器变成了图像编码器而非文本编码器,但核心理念是相同的。
那么,交叉注意力是如何工作的呢?让我们先看看常规自注意力机制内部运作的概念示意图。

在上图中,x 代表输入,Wq 是用于生成查询(Q)的权重矩阵。类似地,K 代表键,V 代表值。A 代表注意力分数矩阵,而 Z 则是输入(x)经过变换后得到的输出上下文向量。(如果这些概念让你感到困惑,可以参考我写的《从零开始构建大语言模型》一书的第3章(https://www.amazon.com/Build-Large-Language-Model-Scratch/dp/1633437167/),那里有全面的介绍;或者,你也可以阅读我的文章《理解并编码大语言模型中的自注意力、多头注意力、交叉注意力和因果注意力》(https://magazine.sebastianraschka.com/p/understanding-and-coding-self-attention),这也会有所帮助。)
与自注意力不同,在交叉注意力中,我们有两个不同的输入来源,如下图所示。

如前面两图所示,在自注意力中,我们处理的是同一个输入序列。而在交叉注意力中,我们混合或结合了两个不同的输入序列。
在《Attention Is All You Need》论文提出的原始Transformer架构中,两个输入x1和x2分别对应左侧编码器模块返回的序列(x2)和右侧解码器模块正在处理的输入序列(x1)。在多模态大语言模型的语境下,x2是图像编码器的输出。(请注意,查询通常来自解码器,而键和值通常来自编码器。)
需要注意的是,在交叉注意力机制中,两个输入序列x1和x2的元素数量可以不同,但它们的嵌入维度必须匹配。如果设置x1 = x2,这就等同于自注意力机制。
在简要讨论了两大多模态设计选择之后,我们接下来简单谈谈在模型训练过程中如何处理三大核心组件,具体内容总结如下图所示。

与纯文本大语言模型的发展类似,多模态大语言模型的训练也包含两个阶段:预训练和指令微调。不过,与从零开始训练不同,多模态大语言模型的训练通常以经过预训练和指令微调的纯文本大语言模型作为基础模型。
对于图像编码器,通常使用CLIP,并且在大多数情况下,它在整个训练过程中保持不变——尽管也有例外,我们稍后会探讨。在预训练阶段,通常也会冻结大语言模型部分,只专注于训练投影器——一个线性层或小型多层感知机。由于投影器的学习能力有限(通常只有一两层),在多模态指令微调(第二阶段)中,大语言模型通常会被解冻,以便进行更全面的更新。但需要注意的是,在基于交叉注意力的模型(方法B)中,交叉注意力层在整个训练过程中都是解冻的。
在介绍了两种主要方法(方法A:统一嵌入解码器架构;方法B:跨模态注意力架构)之后,你可能会想知道哪种方法更有效。答案取决于具体的权衡。
统一嵌入解码器架构(方法A)通常更容易实现,因为它不需要对大语言模型本身的架构进行任何修改。
跨模态注意力架构(方法B)通常被认为计算效率更高,因为它不会用额外的图像标记过载输入上下文,而是将这些标记稍后引入交叉注意力层。此外,如果在训练过程中保持大语言模型参数冻结,这种方法还能保持原始大语言模型在纯文本任务上的性能。
我们将在后续章节中重新讨论模型性能和响应质量的话题,届时会探讨NVIDIA的NVLM论文。
至此,这篇关于多模态大语言模型的详尽介绍便告一段落。写作过程中,我意识到讨论篇幅已远超最初计划,这或许正是收尾的好时机。
不过,为了提供实践视角,若能审视几篇近期采用这些方法的研究论文,想必会更有价值。因此,在本文剩余部分,我们将探讨这些论文。
在接下来的内容中,我将回顾近期关于多模态大语言模型的文献,重点聚焦于最近几周内发表的作品,以保持合理的范围。
因此,这并非多模态大语言模型的历史概述或全面综述,而是对最新进展的简要梳理。同时,我会尽量保持这些摘要简短精炼,避免冗余——毕竟共有十篇论文需要介绍。
文末的结论部分提供了这些论文所用方法的对比概览。
The Llama 3 Herd of Models 论文(2024年7月31日)由Meta AI于今年夏初发布,按大语言模型的时间尺度来看,这仿佛已是久远之事。然而,考虑到他们直到很晚才描述并发布多模态模型,我认为将Llama 3列入此列表是合理的。(Llama 3.2模型于9月25日正式宣布并开放使用。)
多模态Llama 3.2模型包含110亿参数和900亿参数两个版本,属于图像-文本模型,采用前文所述的基于交叉注意力的方法,如下图所示。

请注意,尽管该图也展示了视频和语音作为可能的模态,但截至本文撰写时发布的模型仅专注于图像和文本。
Llama 3.2采用了基于交叉注意力的方法。然而,它与前文所述略有不同——在多模态大语言模型开发中,我们通常会在预训练期间冻结图像编码器,仅更新大语言模型参数。
而在此处,研究人员几乎采取了相反的做法:他们更新图像编码器,但不更新语言模型的参数。他们表示这是有意为之,旨在保留纯文本能力,从而使110亿和900亿参数的多模态模型能够作为Llama 3.1 80亿和700亿参数纯文本模型在文本任务上的直接替代品。
训练本身会进行多次迭代,首先从 Llama 3.1 文本模型开始。在添加图像编码器和投影(此处称为“适配器”)层后,他们会在图像-文本数据上对模型进行预训练。然后,类似于 Llama 3 模型仅文本训练(我在之前的一篇文章中写过),他们会进行指令和偏好微调。
研究人员没有采用像 CLIP 这样的预训练模型作为图像编码器,而是使用了一个从头开始预训练的视觉变换器。具体来说,他们采用了经典视觉变换器架构中的 ViT-H/14 变体(6.3 亿参数)(Dosovitskiy 等人,2020)。然后,他们在包含 25 亿个图像-文本对的数据集上对 ViT 进行了五个周期的预训练;这是在将图像编码器连接到 LLM 之前完成的。(图像编码器接收 224×224 分辨率的图像,并将其划分为 14×14 的块网格,每个块大小为 16×16 像素。)
由于交叉注意力层增加了大量参数,它们仅被添加到每第四个变换器块中。(对于 8B 模型,这增加了 3B 参数;对于 70B 模型,这增加了 200 亿参数。)
Molmo 和 PixMo:用于最先进多模态模型的开放权重和开放数据 论文(2024 年 9 月 25 日)值得注意,因为它承诺不仅开源模型权重,还开源数据集和源代码,类似于仅文本的 OLMo LLM。(这对 LLM 研究非常有利,因为它允许我们查看确切的训练过程和代码,还能让我们在相同数据集上进行消融研究和重现结果。)
如果你想知道论文标题中为什么有两个名称,Molmo 指的是模型(多模态开放语言模型),而 PixMo(Molmo 的像素)是数据集。

如上图所示,图像编码器采用了现成的视觉变换器,具体来说是 CLIP。这里的“连接器”指的是一个“投影器”,用于将图像特征与语言模型对齐。
Molmo 通过避免多个预训练阶段来简化训练过程,而是选择了一个简单的流水线,以统一的方式更新所有参数——包括基础 LLM、连接器和图像编码器的参数。
Molmo 团队为基础 LLM 提供了几种选择:
- OLMo-7B-1024(一个完全开放的模型主干),
- OLMoE-1B-7B(一种混合专家架构;最高效的模型),
- Qwen2 7B(一个开放权重模型,性能优于 OLMo-7B-1024),
- Qwen2 72B(一个开放权重模型,也是性能最佳的模型)
NVIDIA 的 NVLM:开放前沿级多模态 LLM 论文(2024 年 9 月 17 日)特别有趣,因为它没有专注于单一方法,而是探索了两种方法:
- 方法A:统一嵌入解码器架构(“仅解码器架构”,NVLM-D)
- 方法B:跨模态注意力架构(“基于交叉注意力的架构”,NVLM-X)
此外,他们还开发了一种混合方法(NVLM-H),并对这三种方法进行了公平对比。

如下方图表总结所示,NVLM-D对应方法A,NVLM-X对应方法B。混合模型(NVLM-H)的设计理念是结合两种方法的优势:先输入一张图像缩略图,再通过交叉注意力传递动态数量的图像块,以捕捉更精细的高分辨率细节。
简而言之,研究团队发现:
- NVLM-X在处理高分辨率图像时展现出卓越的计算效率。
- NVLM-D在OCR相关任务中实现了更高的准确率。
- NVLM-H则结合了两种方法的优点。
与Molmo及其他方法类似,他们并非从头开始预训练多模态模型(因为从头训练通常效果更佳),而是从纯文本LLM入手。此外,他们使用的是经过指令微调的LLM,而非基础LLM。具体来说,其骨干LLM是Qwen2-72B-Instruct(据我所知,Molmo使用的是Qwen2-72B基础模型)。
在NVLM-D方法中,他们训练了所有LLM参数;而对于NVLM-X,他们发现冻结原始LLM参数,仅在预训练和指令微调阶段训练交叉注意力层,效果良好。
在图像编码器方面,他们没有使用典型的CLIP模型,而是采用了InternViT-6B,该编码器在所有阶段均保持冻结状态。
投影器是一个多层感知机,而非单一的线性层。
前两篇论文及模型(Molmo和NVLM)均基于Qwen2-72B LLM。而在本文中,Qwen研究团队自身发布了一个多模态LLM——Qwen2-VL: Enhancing Vision-Language Model’s Perception of the World at Any Resolution(2024年10月3日)。
这项工作的核心是他们所谓的“朴素动态分辨率”机制(“naive”一词是刻意使用的,并非“native”的笔误,尽管“native”一词也很贴切)。该机制使模型能够处理不同分辨率的图像,而无需简单地进行下采样,从而允许输入原始分辨率的图像。

原生分辨率输入是通过改进的ViT实现的,具体做法是移除原有的绝对位置嵌入,并引入2D-RoPE。
他们使用了经典的视觉编码器(6.75亿参数)以及不同规模的LLM骨干网络,如下表所示。

训练本身包含三个阶段:(1)仅预训练图像编码器,(2)解冻所有参数(包括大语言模型),以及(3)冻结图像编码器,仅对大语言模型进行指令微调。
Pixtral 12B(2024年9月17日)采用方法A:统一嵌入解码器架构,是 Mistral AI 推出的首个多模态模型。遗憾的是,目前没有可用的技术论文或报告,但 Mistral 团队在他们的博客文章中分享了一些有趣的细节。
有趣的是,他们选择不使用预训练的图像编码器,而是从头训练了一个拥有4亿参数的编码器。对于大语言模型主干,他们使用了拥有120亿参数的 Mistral NeMo 模型。
与 Qwen2-VL 类似,Pixtral 也原生支持可变图像尺寸,如下图所示。

MM1.5: Methods, Analysis & Insights from Multimodal LLM Fine-tuning 论文(2024年9月30日)提供了实用技巧,并介绍了一个混合专家多模态模型,以及一个类似于 Molmo 的密集模型。这些模型的参数规模范围很广,从10亿到300亿不等。
本文描述的模型侧重于方法A,即统一嵌入Transformer架构,该架构有效地为多模态学习构建了输入。
此外,该论文还进行了一系列有趣的消融研究,探讨了数据混合以及使用坐标标记的影响。

Aria: An Open Multimodal Native Mixture-of-Experts Model 论文(2024年10月8日)介绍了另一种混合专家模型方法,类似于 Molmo 和 MM1.5 系列中的某个变体。
Aria 模型拥有249亿个参数,每个文本标记分配35亿个参数。图像编码器(SigLIP)拥有4.38亿个参数。
该模型基于交叉注意力方法,整体训练流程如下:
-
从头开始训练大语言模型主干。
-
同时预训练大语言模型主干和视觉编码器。
Baichuan-Omni Technical Report(2024年10月11日)介绍了 Baichuan-Omni,一个拥有70亿参数的多模态大语言模型,基于方法A:统一嵌入解码器架构,如下图所示。

Baichuan-Omni 的训练过程包含三个阶段:
-
投影器训练:初始阶段仅训练投影器,视觉编码器和语言模型(LLM)均保持冻结状态。
-
视觉编码器训练:随后解冻并训练视觉编码器,LLM 仍保持冻结。
-
全模型训练:最后解冻 LLM,使整个模型能够进行端到端训练。
该模型采用 SigLIP 视觉编码器,并集成了 AnyRes 模块,通过下采样技术处理高分辨率图像。
虽然报告未明确说明 LLM 的主干网络,但根据模型的参数量和命名惯例,它很可能基于百川 7B LLM。
Emu3:下一个 Token 预测即是一切 论文(2024 年 9 月 27 日)为图像生成提供了一种引人注目的扩散模型替代方案,该方案完全基于 Transformer 解码器架构。尽管它并非经典意义上的多模态 LLM(即专注于图像理解而非生成的模型),但 Emu3 非常有趣,因为它证明了使用 Transformer 解码器进行图像生成是可行的,而这一任务通常由扩散方法主导。(不过,请注意此前已有类似方法,例如 自回归模型超越扩散:用于可扩展图像生成的 Llama。)

研究人员从头开始训练 Emu3,然后使用 直接偏好优化(DPO)使模型与人类偏好对齐。
该架构包含一个受 SBER-MoVQGAN 启发的视觉分词器。核心 LLM 架构基于 Llama 2,但完全从头开始训练。
我们之前专注于用于图像理解的多模态 LLM,并在上面看到了一个用于图像生成的 Emu3 示例。现在,Janus:解耦视觉编码以实现统一多模态理解与生成 论文(2024 年 10 月 17 日)介绍了一个框架,该框架在单个 LLM 主干中统一了多模态理解和生成任务。
Janus 的一个关键特性是解耦视觉编码路径,以满足理解和生成任务的不同要求。研究人员认为,图像理解任务需要高维语义表示,而生成任务则需要详细的局部信息和图像的整体一致性。通过分离这些路径,Janus 有效地管理了这些不同的需求。
该模型采用与 Baichuan-Omni 类似的 SigLIP 视觉编码器来处理视觉输入。对于图像生成,它使用 向量量化(VQ) 分词器来处理生成过程。Janus 中的基础 LLM 是 DeepSeek-LLM,具有 13 亿个参数。

该图中模型的训练过程分为三个阶段,如下图所示。

在第一阶段,仅训练投影层和图像输出层,而 LLM、理解编码器和生成编码器保持冻结。在第二阶段,LLM 主干网络和文本输出层被解冻,允许在理解和生成任务上进行统一的预训练。最后,在第三阶段,整个模型(包括 SigLIP 图像编码器)被解冻以进行监督微调,使模型能够完全整合并优化其多模态能力。
你可能已经注意到,我几乎完全跳过了建模和计算性能的比较。首先,由于普遍存在的数据污染问题(即测试数据可能已包含在训练数据中),在公共基准上比较 LLM 和多模态 LLM 的性能颇具挑战性。
此外,架构组件的差异如此之大,以至于很难进行同类比较。因此,非常感谢 NVIDIA 团队开发了不同版本的 NVLM,这至少让我们能够在解码器专用方法和交叉注意力方法之间进行比较。
无论如何,本文的主要结论是,多模态 LLM 可以通过多种不同的方式成功构建。下图总结了本文所涵盖模型的不同组件。

希望你觉得阅读本文有所收获,现在对多模态 LLM 的工作原理有了更好的理解!
本杂志是个人热情项目。对于那些希望支持我的人,请考虑购买一本我的《从头开始构建大型语言模型》书籍。(我相信你将从这本书中获得很多收获,因为它以其他地方找不到的详细程度解释了 LLM 的工作原理。)
如果你读了这本书并且有几分钟空闲,我将非常感谢你留下一个简短评论。这对我们作者帮助很大!
或者,我最近也在 Substack 上启用了付费订阅选项,以直接支持本杂志。
你的支持意义重大!谢谢!