視覺語言模型詳解
這篇部落格文章寫於 2024 年 4 月,對視覺語言模型的內部工作原理、現有視覺語言模型套件以及如何微調它們進行了很好的介紹。我們還撰寫了 2025 年 4 月更新版,其中包含更多功能和更多模型。閱讀完這篇後,請務必檢視!
視覺語言模型是一種可以同時從影像和文字中學習的模型,用於處理從視覺問答到影像字幕生成的多種任務。在本文中,我們將深入探討視覺語言模型的主要構建模組:瞭解其概況、掌握其工作原理、找出如何選擇合適的模型、如何使用它們進行推理,以及如何利用今天釋出的新版 trl 輕鬆地對其進行微調!
什麼是視覺語言模型?
視覺語言模型被廣義地定義為可以從影像和文字中學習的多模態模型。它們是一種生成模型,接收影像和文字輸入,並生成文字輸出。大型視覺語言模型具有良好的零樣本能力、泛化性強,並且可以處理多種型別的影像,包括文件、網頁等。其用例包括圍繞影像聊天、透過指令進行影像識別、視覺問答、文件理解、影像字幕生成等。一些視覺語言模型還能捕捉影像中的空間屬性。這些模型可以在被提示檢測或分割特定主體時輸出邊界框或分割掩碼,或者它們可以定位不同的實體或回答關於其相對或絕對位置的問題。現有的大型視覺語言模型在訓練資料、影像編碼方式以及因此具備的能力方面存在很大的多樣性。
開源視覺語言模型概覽
Hugging Face Hub 上有許多開源視覺語言模型。下表展示了一些最著名的模型。
- 有基礎模型,也有為聊天微調的模型,後者可以在對話模式下使用。
- 其中一些模型具有一種稱為“接地”(grounding)的功能,可以減少模型的幻覺。
- 除非另有說明,所有模型均在英語資料上訓練。
模型 | 寬鬆許可證 | 模型大小 | 影像解析度 | 附加功能 |
---|---|---|---|---|
LLaVA 1.6 (Hermes 34B) | ✅ | 34B | 672x672 | |
deepseek-vl-7b-base | ✅ | 7B | 384x384 | |
DeepSeek-VL-Chat | ✅ | 7B | 384x384 | 聊天 |
moondream2 | ✅ | ~2B | 378x378 | |
CogVLM-base | ✅ | 17B | 490x490 | |
CogVLM-Chat | ✅ | 17B | 490x490 | 接地,聊天 |
Fuyu-8B | ❌ | 8B | 300x300 | 影像內文字檢測 |
KOSMOS-2 | ✅ | ~2B | 224x224 | 接地,零樣本物件檢測 |
Qwen-VL | ✅ | 4B | 448x448 | 零樣本物件檢測 |
Qwen-VL-Chat | ✅ | 4B | 448x448 | 聊天 |
Yi-VL-34B | ✅ | 34B | 448x448 | 雙語(英語,中文) |
尋找合適的視覺語言模型
有多種方法可以選擇最適合您用例的模型。
視覺競技場 (Vision Arena) 是一個完全基於對模型輸出的匿名投票而建立的排行榜,並持續更新。在這個競技場中,使用者輸入一張圖片和一個提示,然後匿名抽樣兩個不同模型的輸出,使用者可以選擇他們更喜歡的輸出。透過這種方式,排行榜完全基於人類偏好構建。
開放 VLM 排行榜 (Open VLM Leaderboard) 是另一個排行榜,其中各種視覺語言模型根據這些指標和平均分進行排名。您還可以根據模型大小、專有或開源許可證以及不同指標的排名來篩選模型。
VLMEvalKit 是一個用於在視覺語言模型上執行基準測試的工具包,它為開放 VLM 排行榜提供支援。另一個評估套件是 LMMS-Eval,它提供了一個標準的命令列介面,用於評估您選擇的 Hugging Face 模型在 Hugging Face Hub 上託管的資料集上的表現,如下所示:
accelerate launch --num_processes=8 -m lmms_eval --model llava --model_args pretrained="liuhaotian/llava-v1.5-7b" --tasks mme,mmbench_en --batch_size 1 --log_samples --log_samples_suffix llava_v1.5_mme_mmbenchen --output_path ./logs/
視覺競技場和開放 VLM 排行榜都僅限於提交給它們的模型,並且需要更新才能新增新模型。如果您想查詢其他模型,可以在 Hub 上瀏覽 `image-text-to-text` 任務下的模型。
有不同的基準可以評估視覺語言模型,您可能會在排行榜中遇到。我們將介紹其中幾個。
MMMU
面向專家級 AGI 的海量多學科多模態理解與推理基準 (MMMU) 是評估視覺語言模型最全面的基準。它包含 11,500 個多模態挑戰,這些挑戰需要跨越藝術和工程等不同學科的大學水平知識和推理能力。
MMBench
MMBench 是一個評估基準,包含 3000 個單選題,涵蓋 20 種不同技能,包括 OCR、物體定位等。該論文還引入了一種名為 CircularEval 的評估策略,即問題的答案選項被以不同組合方式打亂,模型需要在每次都給出正確答案。還有其他更專業的跨領域基準,包括 MathVista(視覺數學推理)、AI2D(圖表理解)、ScienceQA(科學問答)和 OCRBench(文件理解)。
技術細節
預訓練視覺語言模型有多種方法。主要技巧是統一影像和文字的表示,並將其輸入文字解碼器進行生成。最常見和最著名的模型通常由一個影像編碼器、一個用於對齊影像和文字表示的嵌入投影器(通常是密集神經網路)和一個文字解碼器按此順序堆疊而成。至於訓練部分,不同的模型採用了不同的方法。
例如,LLaVA 由一個 CLIP 影像編碼器、一個多模態投影器和一個 Vicuna 文字解碼器組成。作者將一個包含影像和字幕的資料集輸入到 GPT-4 中,生成了與字幕和影像相關的問題。作者凍結了影像編碼器和文字解碼器,僅訓練多模態投影器,透過向模型輸入影像和生成的問題,並將模型輸出與真實字幕進行比較,來對齊影像和文字特徵。在投影器預訓練之後,他們保持影像編碼器凍結,解凍文字解碼器,並與解碼器一起訓練投影器。這種預訓練和微調的方式是訓練視覺語言模型最常見的方法。
典型視覺語言模型的結構
投影和文字嵌入被連線在一起
另一個例子是 KOSMOS-2,作者選擇端到端地完全訓練模型,這與 LLaVA 類的預訓練相比計算成本更高。作者後來進行了純語言指令微調來對齊模型。再舉個例子,Fuyu-8B 甚至沒有影像編碼器。相反,影像塊直接被送入一個投影層,然後序列經過一個自迴歸解碼器。大多數時候,你不需要從頭預訓練一個視覺語言模型,因為你可以直接使用現有的模型,或者在自己的用例上對其進行微調。我們將介紹如何使用 transformers 來使用這些模型,以及如何使用 `SFTTrainer` 進行微調。
使用 transformers 執行視覺語言模型
你可以使用 `LlavaNext` 模型透過 Llava 進行推理,如下所示。
我們首先初始化模型和處理器。
from transformers import LlavaNextProcessor, LlavaNextForConditionalGeneration
import torch
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)
我們現在將影像和文字提示傳遞給處理器,然後將處理後的輸入傳遞給 `generate`。請注意,每個模型都使用自己的提示模板,務必使用正確的模板以避免效能下降。
from PIL import Image
import requests
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)
呼叫 decode 來解碼輸出的 token。
print(processor.decode(output[0], skip_special_tokens=True))
使用 TRL 微調視覺語言模型
我們很高興地宣佈,TRL 的 `SFTTrainer` 現在已包含對視覺語言模型的實驗性支援!我們在這裡提供一個示例,展示如何在一個 Llava 1.5 VLM 上使用 llava-instruct 資料集進行監督微調(SFT),該資料集包含 26 萬對影像-對話。資料集包含格式化為訊息序列的使用者-助手互動。例如,每次對話都與一張使用者提問的影像配對。
要使用實驗性的 VLM 訓練支援,您必須安裝最新版本的 TRL,使用 `pip install -U trl`。完整的示例指令碼可以在這裡找到。
from trl.commands.cli_utils import SftScriptArguments, TrlParser
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 %}"""
我們現在將初始化我們的模型和分詞器。
from transformers import AutoTokenizer, AutoProcessor, TrainingArguments, LlavaForConditionalGeneration
import torch
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)
我們來建立一個數據整理器 (data collator) 以組合文字和影像對。
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)
載入我們的資料集。
from datasets import load_dataset
raw_datasets = load_dataset("HuggingFaceH4/llava-instruct-mix-vsft")
train_dataset = raw_datasets["train"]
eval_dataset = raw_datasets["test"]
初始化 SFTTrainer,傳入模型、資料集拆分、PEFT 配置和資料整理器,然後呼叫 `train()`。要將我們最終的檢查點推送到 Hub,請呼叫 `push_to_hub()`。
from trl import 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()
儲存模型並推送到 Hugging Face Hub。
trainer.save_model(training_args.output_dir)
trainer.push_to_hub()
你可以在這裡找到訓練好的模型。
你可以在下面的 VLM 遊樂場中直接嘗試我們剛剛訓練的模型 ⬇️
致謝
我們要感謝 Pedro Cuenca、Lewis Tunstall、Kashif Rasul 和 Omar Sanseviero 對這篇博文的審閱和建議。