关于 blip-2-vision-language
BLIP-2 是一项视觉语言模型技能,用于图像描述、视觉问答和图文理解,面向构建多模态应用的开发者。它通过 Q-Former 将冻结的图像编码器与语言模型连接起来。
主要功能
- 01生成自然语言图像描述
- 02回答有关图像的问题
- 03执行零样本图文理解
- 04提取图像和文本特征用于匹配
- 05采用 OPT 或 FlanT5 语言模型后端
- 06通过 HuggingFace Transformers 或 LAVIS 运行
适用场景
- 01为图像集合生成描述
- 02构建视觉问答系统
- 03依据文本或图像特征检索图像
- 04为多模态应用加入视觉理解
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kalarislabs/ research-agent-skills --skill blip-2-vision-language安装后在 Claude Code 中输入/blip-2-vision-language确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/advanced-usage-2.mdadvanced-usage.mdtroubleshooting.md详细介绍
BLIP-2:视觉-语言预训练
全面介绍如何使用 Salesforce 的 BLIP-2,通过冻结的图像编码器和大模型完成视觉-语言任务。
何时使用 BLIP-2
在以下情况下使用 BLIP-2:
- 需要生成自然描述的高质量图像字幕
- 构建视觉问答(VQA)系统
- 需要无需针对特定任务进行训练的零样本图文理解
- 希望利用 LLM 的推理能力完成视觉任务
- 构建多模态对话式 AI
- 需要进行图文检索或匹配
主要特性:
- Q-Former 架构:轻量级查询 Transformer 连接视觉与语言
- 冻结骨干网络,效率更高:无需微调大型视觉或语言模型
- 多种 LLM 后端:OPT(2.7B、6.7B)和 FlanT5(XL、XXL)
- 零样本能力:无需针对特定任务进行训练,也能取得出色表现
- 高效训练:仅训练 Q-Former(约 188M 个参数)
- 先进的结果:在 VQA 基准测试中胜过更大的模型
以下情况请改用其他方案:
- LLaVA:用于遵循指令的多模态聊天
- InstructBLIP:用于改进指令遵循能力(BLIP-2 的后继模型)
- GPT-4V/Claude 3:用于生产环境中的多模态聊天(专有)
- CLIP:用于不需要生成内容的简单图文相似度计算
- Flamingo:用于少样本视觉学习
快速入门
安装
# HuggingFace Transformers (recommended)
pip install transformers accelerate torch Pillow
# Or LAVIS library (Salesforce official)
pip install salesforce-lavis
基本图像字幕生成
import torch
from PIL import Image
from transformers import Blip2Processor, Blip2ForConditionalGeneration
# Load model and processor
processor = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b")
model = Blip2ForConditionalGeneration.from_pretrained(
"Salesforce/blip2-opt-2.7b",
torch_dtype=torch.float16,
device_map="auto"
)
# Load image
image = Image.open("photo.jpg").convert("RGB")
# Generate caption
inputs = processor(images=image, return_tensors="pt").to("cuda", torch.float16)
generated_ids = model.generate(**inputs, max_new_tokens=50)
caption = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(caption)
视觉问答
# Ask a question about the image
question = "What color is the car in this image?"
inputs = processor(images=image, text=question, return_tensors="pt").to("cuda", torch.float16)
generated_ids = model.generate(**inputs, max_new_tokens=50)
answer = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(answer)
使用 LAVIS 库
import torch
from lavis.models import load_model_and_preprocess
from PIL import Image
# Load model
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model, vis_processors, txt_processors = load_model_and_preprocess(
name="blip2_opt",
model_type="pretrain_opt2.7b",
is_eval=True,
device=device
)
# Process image
image = Image.open("photo.jpg").convert("RGB")
image = vis_processors["eval"](image).unsqueeze(0).to(device)
# Caption
caption = model.generate({"image": image})
print(caption)
# VQA
question = txt_processors["eval"]("What is in this image?")
answer = model.generate({"image": image, "prompt": question})
print(answer)
核心概念
架构概览
BLIP-2 Architecture:
┌─────────────────────────────────────────────────────────────┐
│ Q-Former │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Learned Queries (32 queries × 768 dim) │ │
│ └────────────────────────┬────────────────────────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────┐ │
│ │ Cross-Attention with Image Features │ │
│ └────────────────────────┬────────────────────────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────┐ │
│ │ Self-Attention Layers (Transformer) │ │
│ └────────────────────────┬────────────────────────────┘ │
└───────────────────────────┼─────────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────────┐
│ Frozen Vision Encoder │ Frozen LLM │
│ (ViT-G/14 from EVA-CLIP) │ (OPT or FlanT5) │
└─────────────────────────────────────────────────────────────┘
模型变体
| 模型 | LLM 后端 | 大小 | 使用场景 |
|---|---|---|---|
blip2-opt-2.7b | OPT-2.7B | 约 4GB | 通用字幕生成、VQA |
blip2-opt-6.7b | OPT-6.7B | 约 8GB | 更强的推理能力 |
blip2-flan-t5-xl | FlanT5-XL | 约 5GB | 指令遵循 |
blip2-flan-t5-xxl | FlanT5-XXL | 约 13GB | 最高质量 |
Q-Former 组件
| 组件 | 描述 | 参数 |
|---|---|---|
| 可学习查询 | 一组固定的可学习嵌入 | 32 × 768 |
| 图像 Transformer | 对视觉特征进行交叉注意力 | 约 108M |
| 文本 Transformer | 用于文本的自注意力 | 约 108M |
| 线性投影 | 映射到 LLM 维度 | 视情况而定 |
高级用法
详细信息、代码示例和参数表:references/advanced-usage-2.md。适用时请阅读。
常见工作流
工作流 1:图像字幕生成管线
import torch
from PIL import Image
from transformers import Blip2Processor, Blip2ForConditionalGeneration
from pathlib import Path
class ImageCaptioner:
def __init__(self, model_name="Salesforce/blip2-opt-2.7b"):
self.processor = Blip2Processor.from_pretrained(model_name)
self.model = Blip2ForConditionalGeneration.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto"
)
def caption(self, image_path: str, prompt: str = None) -> str:
image = Image.open(image_path).convert("RGB")
if prompt:
inputs = self.processor(images=image, text=prompt, return_tensors="pt")
else:
inputs = self.processor(images=image, return_tensors="pt")
inputs = inputs.to("cuda", torch.float16)
generated_ids = self.model.generate(
**inputs,
max_new_tokens=50,
num_beams=5
)
return self.processor.decode(generated_ids[0], skip_special_tokens=True)
def caption_batch(self, image_paths: list, prompt: str = None) -> list:
images = [Image.open(p).convert("RGB") for p in image_paths]
if prompt:
inputs = self.processor(
images=images,
text=[prompt] * len(images),
return_tensors="pt",
padding=True
)
else:
inputs = self.processor(images=images, return_tensors="pt", padding=True)
inputs = inputs.to("cuda", torch.float16)
generated_ids = self.model.generate(**inputs, max_new_tokens=50)
return self.processor.batch_decode(generated_ids, skip_special_tokens=True)
# Usage
captioner = ImageCaptioner()
# Single image
caption = captioner.caption("photo.jpg")
print(f"Caption: {caption}")
# With prompt for style
caption = captioner.caption("photo.jpg", "a detailed description of")
print(f"Detailed: {caption}")
# Batch processing
captions = captioner.caption_batch(["img1.jpg", "img2.jpg", "img3.jpg"])
for i, cap in enumerate(captions):
print(f"Image {i+1}: {cap}")
工作流 2:视觉问答系统
class VisualQA:
def __init__(self, model_name="Salesforce/blip2-flan-t5-xl"):
self.processor = Blip2Processor.from_pretrained(model_name)
self.model = Blip2ForConditionalGeneration.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto"
)
self.current_image = None
self.current_inputs = None
def set_image(self, image_path: str):
"""Load image for multiple questions."""
self.current_image = Image.open(image_path).convert("RGB")
def ask(self, question: str) -> str:
"""Ask a question about the current image."""
if self.current_image is None:
raise ValueError("No image set. Call set_image() first.")
# Format question for FlanT5
prompt = f"Question: {question} Answer:"
inputs = self.processor(
images=self.current_image,
text=prompt,
return_tensors="pt"
).to("cuda", torch.float16)
generated_ids = self.model.generate(
**inputs,
max_new_tokens=50,
num_beams=5
)
return self.processor.decode(generated_ids[0], skip_special_tokens=True)
def ask_multiple(self, questions: list) -> dict:
"""Ask multiple questions about current image."""
return {q: self.ask(q) for q in questions}
# Usage
vqa = VisualQA()
vqa.set_image("scene.jpg")
# Ask questions
print(vqa.ask("What objects are in this image?"))
print(vqa.ask("What is the weather like?"))
print(vqa.ask("How many people are there?"))
# Batch questions
results = vqa.ask_multiple([
"What is the main subject?",
"What colors are dominant?",
"Is this indoors or outdoors?"
])
工作流 3:图像搜索/检索
import torch
import numpy as np
from PIL import Image
from lavis.models import load_model_and_preprocess
class ImageSearchEngine:
def __init__(self):
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.model, self.vis_processors, self.txt_processors = load_model_and_preprocess(
name="blip2_feature_extractor",
model_type="pretrain",
is_eval=True,
device=self.device
)
self.image_features = []
self.image_paths = []
def index_images(self, image_paths: list):
"""Build index from images."""
self.image_paths = image_paths
for path in image_paths:
image = Image.open(path).convert("RGB")
image = self.vis_processors["eval"](image).unsqueeze(0).to(self.device)
with torch.no_grad():
features = self.model.extract_features({"image": image}, mode="image")
# Use projected features for matching
self.image_features.append(
features.image_embeds_proj.mean(dim=1).cpu().numpy()
)
self.image_features = np.vstack(self.image_features)
def search(self, query: str, top_k: int = 5) -> list:
"""Search images by text query."""
# Get text features
text = self.txt_processors["eval"](query)
text_input = {"text_input": [text]}
with torch.no_grad():
text_features = self.model.extract_features(text_input, mode="text")
text_embeds = text_features.text_embeds_proj[:, 0].cpu().numpy()
# Compute similarities
similarities = np.dot(self.image_features, text_embeds.T).squeeze()
top_indices = np.argsort(similarities)[::-1][:top_k]
return [(self.image_paths[i], similarities[i]) for i in top_indices]
# Usage
engine = ImageSearchEngine()
engine.index_images(["img1.jpg", "img2.jpg", "img3.jpg", ...])
# Search
results = engine.search("a sunset over the ocean", top_k=5)
for path, score in results:
print(f"{path}: {score:.3f}")
输出格式
生成输出
# Direct generation returns token IDs
generated_ids = model.generate(**inputs, max_new_tokens=50)
# Shape: [batch_size, sequence_length]
# Decode to text
text = processor.batch_decode(generated_ids, skip_special_tokens=True)
# Returns: list of strings
特征提取输出
# Q-Former outputs
features = model.extract_features({"image": image}, mode="image")
features.image_embeds # [B, 32, 768] - Q-Former outputs
features.image_embeds_proj # [B, 32, 256] - Projected for matching
features.text_embeds # [B, seq_len, 768] - Text features
features.text_embeds_proj # [B, 256] - Projected text (CLS)
性能优化
GPU 显存需求
| 模型 | FP16 显存 | INT8 显存 | INT4 显存 |
|---|---|---|---|
| blip2-opt-2.7b | 约 8GB | 约 5GB | 约 3GB |
| blip2-opt-6.7b | 约 16GB | 约 9GB | 约 5GB |
| blip2-flan-t5-xl | 约 10GB | 约 6GB | 约 4GB |
| blip2-flan-t5-xxl | 约 26GB | 约 14GB | 约 8GB |
速度优化
# Use Flash Attention if available
model = Blip2ForConditionalGeneration.from_pretrained(
"Salesforce/blip2-opt-2.7b",
torch_dtype=torch.float16,
attn_implementation="flash_attention_2", # Requires flash-attn
device_map="auto"
)
# Compile model (PyTorch 2.0+)
model = torch.compile(model)
# Use smaller images (if quality allows)
processor = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b")
# Default is 224x224, which is optimal
常见问题
| 问题 | 解决方案 |
|---|---|
| CUDA 显存不足 | 使用 INT8/INT4 量化或更小的模型 |
| 生成速度慢 | 使用贪心解码,减少 max_new_tokens |
| 字幕质量差 | 尝试 FlanT5 变体,使用提示词 |
| 幻觉 | 降低温度,使用束搜索 |
| 答案错误 | 改写问题,提供上下文 |
参考资料
资源
- 论文:https://arxiv.org/abs/2301.12597
- GitHub(LAVIS):https://github.com/salesforce/LAVIS
- HuggingFace:https://huggingface.co/Salesforce/blip2-opt-2.7b
- 演示:https://huggingface.co/spaces/Salesforce/BLIP2
- InstructBLIP:https://arxiv.org/abs/2305.06500(后继模型)
Agent 操作流程
- 检查环境。 确认 GPU 内存、模型检查点及许可证、框架版本和输入格式。
- 明确输入。 根据数据或用户确认格式、标识符和参数。任何会影响结果的值都应询问,不要猜测。
- 先运行小规模版本。 首先以低分辨率或较短长度对单个样本运行推理。
- 按照上述说明和参考资料执行完整任务。
- 验证结果。 通过定性检查和任务指标检查输出;确认生成内容符合许可证限制。
- 汇报。 说明运行了什么(版本、命令、参数)、检查了什么,以及哪些事项仍不确定。
| 如果发生这种情况 | 请这样做 |
|---|---|
| 大型输入导致内存不足 | 降低分辨率或序列长度、使用半精度,或对输入进行分块。 |
| 这些说明中提到的函数、标志或端点在已安装版本中不存在 | 查看已安装版本自己的文档(help()、--help、官方文档),调整做法,并告知用户。绝不编造 API。 |
| 必需的输入、标识符或参数不明确 | 询问用户,或在运行前明确说明所采用的假设。 |
诚信规则
- 绝不捏造结果、参数、标识符、引文或统计数据。如果无法运行或验证某项内容,请直言说明。
- 用于商业用途或发布前,检查模型和数据集的许可证。
- 请将此处与特定版本相关的细节视为可能已过时:根据已安装版本的官方文档进行确认。
- 对于需要付费、占用共享 GPU 或云配额、涉及个人或患者数据,或无法撤销的操作,先征求同意。
相关技能
clip:连接视觉与语言的 OpenAI 模型。llava:大语言与视觉助手。quantizing-models-bitsandbytes:将 LLM 量化为 8 位或 4 位,在准确率损失极小的情况下减少 50-75% 的内存占用。
评论
支持 Markdown