1. 概述
近年来深度学习在计算机视觉(CV)和自然语言处理(NLP)等单模态领域都取得了十分优异的性能。随着技术的发展,多模态学习的重要性和必要性已经慢慢展现。视觉语言学习作为多模态学习的重要部分,得到国内外研究人员的广泛关注。得益于Transformer框架的发展,越来越多的预训练模型被运用到视觉语言多模态学习上,相关任务在性能上得到了质的飞跃。
2. 基本概念
传统的基于卷积神经网络的 CV 模型是在有限类别的数据集上针对特定任务而进行训练的,无法超越其开发和训练的任务或类别集。如果用例发生根本变化或需要向模型添加新类别,开发人员则须收集和标记大量图像并重新训练模型。这是一个昂贵且耗时的过程。此外,CV 模型没有任何自然语言理解。例如:识别图像中是否包含猫或狗的分类模型;读取图像中的文本,但不对文档的格式或任何视觉数据进行解读的光学字符检测和识别 CV 模型。
然而,随着通用语言模型(如GPTs)的发展,它们不仅变得更加通用,而且更加强大。然而,即使在语言模型取得了巨大进展的情况下,它们仍然与计算机视觉领域保持独立。而视觉语言模型(Vision-Language Models, VLMs)是通过结合计算机视觉(CV)和自然语言处理(NLP)的技术,将大语言模型 (LLM) 与视觉编码器相结合构建的多模态 AI 系统,使 LLM 具有“看”的能力,能够处理和理解视觉(图像)和语言(文本)两种模态的信息,实现对图像和文本的联合理解与生成。可以理解和处理多种数据类型,包括文本、图像、视频和音频。
VLMs 拥有广泛的应用,包括基于图像的聊天、根据指令的图像识别、图像描述、根据文本生成图片、视觉问答(Visual QuestionAnswering,VQA)、图像字幕生成(lmage Captioning)和文本到图像搜索(Text-to-lmage Search)等,在各种视觉任务上具有强大的零样本能力。它们也非常灵活,不仅可以用于一组固定类别集,而且可以通过简单地更改文本提示用于几乎任何用例。其一些视觉语言模型还可以捕获图像中的空间信息,当提示要求其检测或分割特定目标时,这些模型可以输出边界框或分割掩模,有些模型还可以定位不同的目标或回答其相对或绝对位置相关的问题。
3. 模型架构
从多模态融合的角度对比单流结构与双流结构。
单流结构:单流结构指一种将文本和视觉特征连接到一起,然后输入进单个Transformer模块中。单流结构利用注意力来融合多模态输入,因为对不同的模态都使用了相同形式的参数,其在参数方面更具效率。双流结构:在双流结构中文本和视觉特征没有连接在一起,而是单独输入到两个不同的Transformer模块中。这两个Transformer没有共享参数,为了达到更高的性能,双流结构使用交叉注意力的方式来实现不同模态之间的交互。为了达到更高的效率,处理不同模态信息的Transformer模块之间也可以不存在交叉注意。
现如今大多数 VLMs 的架构由三部分构成:
- 视觉编码器
- 投影器 (Projector)
- 大语言模型(LLM)
视觉编码器,也称为特征提取器,负责将图像转换为高维特征向量。常用的图像编码器包括卷积神经网络(CNN)或视觉Transformer(ViT)等结构,用于提取图像中的关键特征。投影器作为中介,将图像信息融入到语言模型中,从而实现多模态的理解和处理。它由一组网络层构成,通常处理视觉编码器的最后一个特征层,并生成供 LLM 使用的一维类似token的特征,一般解读为图像标记 (tokens)。投影器可以是如 LLLaVA 与 VILA 中的简单线性层,或者是如 Llama 3.2 Vision 中使用的交叉注意力层更复杂的结构。任何现有的 LLM 都可以用来构建 VLM。有数百种结合了各种 LLM 与视觉编码器的 VLM 变体。
4. 数据集
视觉语言模型通常根据预训练目标在结构各异的大型图像和文本数据集上进行训练。在对它们进行预训练后,再使用特定于任务的数据集进一步针对各种下游任务进行微调。下面列举一些用于训练和评估视觉语言模型的流行的数据集。
(1)视觉问答类数据集
- VQA:包含超过20万张图像,每张图像有5个问题、10个真实答案,每个问题有3个错误答案,用于视觉问答任务的训练和微调。
- VQAv2:VQA的升级版本,提供了更高质量的问答对,用于进一步提升视觉问答模型的性能。
- GQA:由斯坦福大学创建,包含超过22万个图像和150万个问答对,问题更加复杂多样,用于训练模型更好地理解和推理图像内容。
- DVQA:包含30万张图像对应的约348万个问题答案对,用于问答框架中条形图理解的微调。
- NLVR2:多语言视觉问答数据集,包含超过100,000个图像对和200,000个自然语言问题。问题以英文和多种其他语言呈现。
- TextVQA:关注图像中的文本信息,要求模型可以读取识别图片中的文本信息,并回答与之相关的问题。来自OpenImage的28k张图片,45k个问题及453k个答案,能够更加准确并高效地回答问题。
- TDIUC:包括来自MS COCO和视觉基因组数据集的160万个问题及17万张图像,可用于评估模型稳健性及推理能力的微调。
- VizWiz:这是第一个源自真实视觉问答场景的数据集,包含超过31,000个视觉问答对,由视障用户拍摄图片并提出语音问题。
(2)图像描述类数据集
- COCO Captions:该数据集是图像描述领域的经典数据集之一,包含大量的图像和对应的描述文本。每张图像通常有5个描述,描述内容丰富且多样。
- Flickr30k:包含3万张图像,每张图像有5个描述性文本,用于图像描述生成任务的训练和评估。
- Conceptual Captions (CC):由Google创建,包含超过300万张图像和描述性文本对,覆盖广泛的主题和场景,用于训练模型生成更具创造性和多样性的图像描述。
(3)多模态对话类数据集
- Visual Dialog:包含超过12万张图像和120万条对话,用于训练模型在视觉上下文中进行多轮对话。
- VisDial:包含超过10万张图像和100万条对话,用于评估模型在视觉对话任务中的表现。
- MMDialog:包含108万个完整对话session,超过4,000个对话主题,以及153万张非重复图像,每个对话session有平均2.59张图像。
(4)多视角图像处理类数据集
MVCap-4M:包含超过460万个多视角图像-文本对,涉及超过10万个对象,专为视觉-语言模型的视角不变性研究设计。
(5)文本引导目标检测数据集
- MSCOCO:这是一个广泛使用的计算机视觉数据集,包含大量的图像和对应的文本描述。每张图像都有详细的标注信息,包括目标的类别和坐标,适合用于多模态目标检测任务。
- Visual Genome:该数据集包含大量的图像及其对应的文本描述和目标框标注。它不仅用于目标检测,还支持视觉问答、场景图构建等多模态任务。
5. 训练过程
主要有两种训练范式:预训练-微调(pretrain fine-tuning)和预训练-提示(pretrain prompt)。
预训练-微调已经成了经典的训练范式。其做法是:首先以监督或无监督的方式在大型数据集上预训练模型,然后通过微调将预训练的模型在较小的数据集上适应特定的下游任务。这种模式可以避免为不同的任务或数据集从头开始训练新模型。越来越多的实验证明,在较大的数据集上进行预训练有助于学习通用表征,从而提高下游任务的性能。
提示学习起源于NLP领域,随着预训练语言模型体量的不断增大,对其进行微调的硬件要求、数据需求和实际代价也在不断上涨。除此之外,丰富多样的下游任务也使得预训练-微调阶段的设计变得繁琐复杂,提示学习就此诞生。在预训练-提示范式中通常使用一个模板来给预训练模型提供一些线索和提示,从而能够更好地利用预训练语言模型中已有的知识,以此完成下游任务。
5.1 预训练
对视觉语言模型进行预训练的方法有很多。主要技巧是统一图像和文本表征以将其输入给文本解码器用于文本生成。最常见且表现最好的模型通常由图像编码器、用于对齐图像和文本表征的嵌入投影子模型 (通常是一个稠密神经网络) 以及文本解码器按序堆叠而成。至于训练部分,不同的模型采用的方法也各不相同。
5.1.1 学习策略
学习策略(预训练策略)指的是用于优化模型性能和实现目标的训练方法和技术,旨在更好地学习图像和文本之间的相关性,以及提升模型在各种下游任务上的表现。接下来,笔者将总结几个 VLM 的训练方法,并分析每种训练方法的性能和应用场景。
(1)对比学习
对比学习 ,这是一种常用的策略,旨在通过比较样本之间的相似性和差异性来学习有效的特征表示。它是视觉语言模型中一种常用的学习策略,特别适合用于多模态任务(如图像-文本对齐),能够帮助模型在共享的嵌入空间中学习图像和文本的关联。
正样本对(Positive Pair):表示具有相似语义的样本对(如一张图像和其对应的描述文本)。
负样本对(Negative Pair):表示语义不相似的样本对(如一张图像与随机选择的无关文本)。
通过训练,模型的目标是:
- 最小化正样本对的距离(使它们更接近)。
- 最大化负样本对的距离(使它们更远离)。
如 CLIP、ALIGN 和 DeCLIP 在 {图像,标题} 对组成的大型数据集上,通过使用对比损失函数联合训练文本编码器和图像编码器,从而桥接视觉和语言两个模态。CLIP 仅采用文本和图像嵌入之间的余弦距离作为距离度量。而 ALIGN 和 DeCLIP 等模型则设计了自己的距离度量,这些距离在设计时考虑了数据集是有噪声的。
(2)掩码学习
掩码是一种在深度学习中常用的技术,特别是在自然语言处理(NLP)、计算机视觉(CV)和多模态任务中。掩码的核心思想是通过隐藏部分输入信息,迫使模型学习如何根据上下文或已知信息预测被隐藏的信息,从而提升模型对数据的理解能力和生成能力。
文本掩码: 在 NLP 中,掩码用于隐藏输入序列中的某些词语或标记。它是自监督学习的基础,广泛应用于模型预训练(如 BERT)。
掩码语言建模(Masked Language Modeling, MLM)是一种在自然语言处理(NLP)中广泛使用的预训练技术,尤其在基于Transformer架构的模型中,如BERT。其核心思想是通过随机遮蔽输入文本中的部分词汇,并要求模型根据剩余的上下文信息来预测这些被遮蔽的词汇。例如,对于句子"The quick brown fox jumps over the lazy dog.“,在训练时可能会被修改为"The quick brown [MASK] jumps over the lazy [MASK].”,模型需要预测出被遮蔽的单词。这种训练方式使模型在预训练阶段就学习到丰富的语义信息和上下文关系,这使得模型在后续的微调阶段能够更好地适应各种下游任务。
图像掩码: 在 CV 中,掩码用于隐藏图像中的部分区域,模型需要根据可见区域预测被隐藏的内容。
掩码图像建模(Masked Image Modeling, MIM): 随机遮挡图像的某些部分(如块状区域),要求模型恢复这些区域的像素或高层次特征。使模型能够学习图像的全局和局部特征,提高模型的重建能力和泛化能力。常见模型:MAE(Masked Autoencoders)、BEiT。例如,输入:带有遮挡块的图片。输出:完整图片或特征。
在视觉语言模中,遮掩部分文本,模型根据图像和上下文预测。类似的,遮掩部分图像,模型根据文本和可见图像区域恢复。常见模型:FLAVA、UniLMv2。例如,输入:图像和 A [MASK] is on the table。输出:cat
(3)其他学习
- 图文匹配
在视觉语言模型中,有一些模型,如 VisualBERT、FLAVA、ViLBERT、LXMERT 和 BridgeTower,把掩码语言建模 (MLM) 和图文匹配 (ITM) 目标组合起来使用,将图像的特定部分与文本对齐,并完成各种下游任务,例如视觉问答、视觉常识推理、文搜图以及文本引导的目标检测。然而,MLM 目标需要使用带有边界框的标注丰富的多模态数据集,或者使用目标检测模型为部分输入文本生成候选目标区域。
例如,VisualBERT 提出了一种类似 BERT 的架构,它使用预训练的目标检测模型 Faster-RCNN 来检测目标。VisualBERT 在预训练期间结合了 MLM 和 ITM 目标,通过自注意力机制隐式对齐输入文本的元素和相应输入图像中的区域。
- 前缀策略
PrefixLM,即前缀语言模型,是一种特殊的语言模型结构,主要用于生成文本。它结合了Encoder-Decoder模型的特点,但与标准的Encoder-Decoder模型不同,PrefixLM的Encoder和Decoder共享同一个Transformer结构。具体来说,PrefixLM在Encoder部分采用自编码(Auto Encoding, AE)模式,即前缀序列中的任意两个token都相互可见;而在Decoder部分采用自回归(Auto Regressive, AR)模式,即待生成的token可以看到Encoder侧所有token(包括上下文)和Decoder侧已经生成的token,但不能看到未来尚未产生的token。
在具有前缀目标的语言模型中,通过在给定输入文本作为前缀的情况下预测下一个词。例如,给定序列 “她在看电视剧”,我们可以使用” 她在看” 作为前缀并训练模型以预测下一个词: 可以是 “电视剧” 或另一个合理的补全词。在视觉模型中,Visual transformers (ViT) 通过将每个图像划分为多个块,并将这些块按顺序输入给模型,从而将相同的前缀概念应用于图像。利用这个想法,SimVLM 实现了这样一种架构,将图像块序列和前缀文本序列串接起来作为最终的前缀,输入给编码器,然后由解码器来预测该文本序列的接续文本。然而,仅使用 PrefixLM 策略的模型在应用领域上可能会受到限制,因为它们主要为图像标题生成或视觉问答这两个下游任务而设计。
- 交叉注意力
使用交叉注意机制将视觉信息直接融合到语言模型解码器的层中,而不是使用图像作为语言模型的附加前缀。VisualGPT、VC-GPT 和 Flamingo 使用此预训练策略并在图像标题任务和视觉问答任务上进行训练。VisualGPT 等模型使用视觉编码器来生成图像嵌入,并将视觉嵌入提供给预训练语言解码器模块的交叉注意层,以生成合理的标题。最近的一项工作 FIBER 将具有门控机制的交叉注意力层插入到视觉和语言的主干模型中,以实现更高效的多模态融合,并使能各种其他下游任务,如图文互搜、开放域 (open-vocabulary) 目标检测等。
5.1.2 开源模型
Hugging Face Hub这个网站有很多开源的预训练模型和数据集。
5.2 微调
大多数时候,我们不需要预训练视觉语言模型,仅需使用现有的模型进行推理,抑或是根据自己的场景对其进行微调。
5.2.1 模型选择
怎么找到最适合自己特定需求的VLMs???
我们可以使用评估工具和资源来帮助我们选择合适的预训练模型。
-
Vision Arena:这是一个动态排行榜,基于模型输出的匿名投票。用户上传一张图片和一个提示,然后系统会从两个不同的模型中随机抽取输出,让用户选择他们更喜欢哪个。这个排行榜完全是基于人的喜好来构建的,给模型提供了一个公平的排名。
-
Open VLM Leaderboard:这个排行榜会根据不同的指标和平均分数给各种VLMs打分,还提供了筛选器,可以按照模型的大小、许可证和不同指标的性能来排序。
-
VLMEvalKit:这是一个工具包,专门设计用来在VLMs上运行基准测试,也是Open VLM Leaderboard的技术支持。还有一个评估套件叫LMMS-Eval,它提供了一个命令行界面,让用户可以使用Hugging Face Hub上托管的数据集来评估模型。
5.2.2 冻结与微调策略
在模型预训练后的监督微调(SFT)阶段,数据的质量和多样性至关重要。
在 SFT 阶段,不同模型的训练策略各异:
- 一些模型(例如 Llama3.2)会冻结 LLM,以避免对以文本为中心或仅文本任务的性能回退。
- 其他模型(例如 MM1.5、MiniCPM-V、LLaVa-OneVision)声称微调 LLM 能提高对视觉特征的理解能力以及任务指令的执行能力。
建议:除非使用高质量的以文本为中心的数据,否则LLM通常在预训练阶段保持冻结状态。
类似地,是否冻结(部分)视觉编码器也各有利弊。根据不同的模型配置、数据量和数据分布,可能不存在统一的最佳后期训练策略,因此需要视具体情况决策(或者从另一个角度看,扩展模型的其他部分可能对性能提升更为关键)。
这是一个典型的多模态大语言模型(MLLM)设计,这种预训练加微调的方法是训练视觉语言模型最常见的做法。在默认设置下,预训练阶段仅训练投影器,图像编码器和文本解码器使用预训练模型。在后续训练阶段(微调),有时会解冻大语言模型(LLM)或视觉编码器,以提升模型在指令跟随任务中的表现。例如,在 Llama3.2 中,为了保持纯文本性能,LLM 在后续训练阶段也保持冻结状态。而在 MM1.5 中,LLM 和视觉编码器都被解冻。
大多数时候,我们不需要预训练视觉语言模型,仅需使用现有的模型进行推理,抑或是根据自己的场景对其进行微调。下面,我们介绍如何在 Huggingface transformers中使用这些模型,以及如何使用 SFTTrainer 对它们进行微调。
(1)在 transformers 中使用视觉语言模型
import torch
from PIL import Image
import requests
from transformers import LlavaNextProcessor, LlavaNextForConditionalGeneration
# 初始化模型和数据处理器
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
processor = LlavaNextProcessor.from_pretrained("llava-hf/llava-v1.6-mistral-7b-hf")
model = LlavaNextForConditionalGeneration.from_pretrained(
"llava-hf/llava-v1.6-mistral-7b-hf",
torch_dtype=torch.float16,
low_cpu_mem_usage=True
)
model.to(device)
url = "https://github.com/haotian-liu/LLaVA/blob/1a91fc274d7c35a9b50b3cb29c4247ae5837ce39/images/llava_v1_5_radar.jpg?raw=true"
image = Image.open(requests.get(url, stream=True).raw)
prompt = "[INST] <image>\nWhat is shown in this image? [/INST]"
# 每个模型都有自己的提示模板,请务必根据模型选用正确的模板,以避免性能下降
inputs = processor(prompt, image, return_tensors="pt").to(device)
output = model.generate(**inputs, max_new_tokens=100)
# 对输出词元进行解码
print(processor.decode(output[0], skip_special_tokens=True))
(2)使用 TRL 微调视觉语言模型
TRL 的 SFTTrainer 如今已支持视觉语言模型的微调。在这里,笔者对llava在llava-instruct 数据集上进行微调,该数据集包含 260k 个图像对话对。
首先安装最新版本的 TRL。
pip install -U trl
import torch
from datasets import load_dataset
from trl import SFTTrainer
from trl.commands.cli_utils import SftScriptArguments, TrlParser
from transformers import AutoTokenizer, AutoProcessor, TrainingArguments, LlavaForConditionalGeneration
# 新建数据整理器来组合文本和图像对
class LLavaDataCollator:
def __init__(self, processor):
self.processor = processor
def __call__(self, examples):
texts = []
images = []
for example in examples:
messages = example["messages"]
text = self.processor.tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=False
)
texts.append(text)
images.append(example["images"][0])
batch = self.processor(texts, images, return_tensors="pt", padding=True)
labels = batch["input_ids"].clone()
if self.processor.tokenizer.pad_token_id is not None:
labels[labels == self.processor.tokenizer.pad_token_id] = -100
batch["labels"] = labels
return batch
data_collator = LLavaDataCollator(processor)
parser = TrlParser((SftScriptArguments, TrainingArguments))
args, training_args = parser.parse_args_and_config()
# 初始化聊天模板以进行指令微调
LLAVA_CHAT_TEMPLATE = """A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions. {% for message in messages %}{% if message['role'] == 'user' %}USER: {% else %}ASSISTANT: {% endif %}{% for item in message['content'] %}{% if item['type'] == 'text' %}{{ item['text'] }}{% elif item['type'] == 'image' %}<image>{% endif %}{% endfor %}{% if message['role'] == 'user' %} {% else %}{{eos_token}}{% endif %}{% endfor %}"""
# 初始化模型和分词器
model_id = "llava-hf/llava-1.5-7b-hf"
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.chat_template = LLAVA_CHAT_TEMPLATE
processor = AutoProcessor.from_pretrained(model_id)
processor.tokenizer = tokenizer
model = LlavaForConditionalGeneration.from_pretrained(model_id, torch_dtype=torch.float16)
# 加载数据集
raw_datasets = load_dataset("HuggingFaceH4/llava-instruct-mix-vsft")
train_dataset = raw_datasets["train"]
eval_dataset = raw_datasets["test"]
# 初始化 SFTTrainer
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
dataset_text_field="text", # need a dummy field
tokenizer=tokenizer,
data_collator=data_collator,
dataset_kwargs={"skip_prepare_dataset": True},
)
trainer.train()
# 保存模型
trainer.save_model(training_args.output_dir)
6. 评估方法
目前存在的常见基准测试,如 MMMU、Video-MME、MathVista、ChartQA 和 DocVQA, 用于确定视觉语言模型在各种任务上的表现。大多数基准测试由一组图像和几个相关问题组成,通常以多选题的形式呈现。多选题是一致性基准测试和比较 VLM 的最简单方法。这些问题测试 VLM 的感知、知识和推理能力。在运行这些基准测试时,VLM 会收到图像、问题以及它必须做出选择的多选题答案。