Hugging Face Transformers 中的 BLIP 模型:Bootstrapped 视觉-语言预训练架构、配置与 VQA 实战指南
BLIP(Bootstrapped Language-Image Pretraining)是由 Salesforce 提出的视觉-语言预训练(VLP)框架,其核心目标是让同一套参数同时擅长理解类(如图文检索)与生成类(如图像描述、视觉问答)任务。本文以 Transformers 仓库中 BLIP 的官方文档为主体,结合 configuration_blip.py、modeling_blip.py 与 processing_blip.py 等源码,完整讲解三类任务模型、三个配置类的全部默认参数、预处理管线与底层实现原理。读完本文,你将能够独立完成 BLIP 的视觉问答、图像描述、图文检索的推理与训练,并能看懂、调整其双塔与融合层配置。
BLIP 的核心思想:用“标题生成器 + 噪声过滤器”驯服海量网页数据
大多数早期的预训练模型只能在“理解”或“生成”二者中擅长其一:CLIP 一类模型擅长图文对齐与检索,但不能生成自然语言;仅靠生成目标训练的模型又缺乏语义理解的对齐监督。BLIP 的设计动机正是打破这一瓶颈——它的全称即点明方法:Bootstrapping(自举式数据重标定)。
BLIP 使用一个 captioner(标题生成器)为网络图片生成合成标题,再用一个 filter(过滤器)剔除其中含噪、不相关的标题。通过这种方式,模型得以在训练过程中持续自我提升训练数据质量,从而更充分地利用参差不齐(messy)的网页图文数据。docs/source/en/model_doc/blip.md 将其概括为一种“同时面向理解与生成任务”的 VLP 框架。
据该文档记载,BLIP 论文于 2022-01-28 发布,该模型类型于 2022-12-21 由 ybelkada 贡献并入 Hugging Face Transformers。官方发布的 BLIP 检查点统一以 Salesforce/blip-* 命名,源码中各配置类与 Auto API 的 checkpoint 示例默认值均为 Salesforce/blip-vqa-base(见 configuration_blip.py),这是全库中最具代表性的 BLIP 权重标识。
快速上手:基于 Pipeline 的视觉问答(Visual Question Answering)
BLIP 最典型的落地场景是 VQA:输入一张图片 + 一个自然语言问题,输出答案。文档给出的第一种方式是 Pipeline 高层 API——无需手动管理预处理与模型实例:
from transformers import pipeline
# device=0 表示使用第一块 GPU;不传该参数则回退到 CPU
vqa_pipeline = pipeline(
task="visual-question-answering",
model="Salesforce/blip-vqa-base",
device=0,
)
# 换成本地测试图即可复现;原文档示例使用远端 COCO 图片
answer = vqa_pipeline(
question="What is in this image?",
image="tests/fixtures/tests_samples/COCO/000000039769.png", # 仓库自带测试样本
)
print(answer)
visual-question-answering 任务会在内部自动装配 BlipForQuestionAnswering 与其配套的 BlipProcessor(可在 src/transformers/models/auto 的 pipeline 注册表中确认映射)。仓库自带一张 COCO 样例图位于 tests/fixtures/tests_samples/COCO/000000039769.png,可用于离线快速验证推理流程。
进阶用法:AutoModel + AutoProcessor 手动串联
Pipeline 封装了全部细节,但当你需要精确控制预处理、batch、半精度推理时,更推荐文档展示的第二条路径——用 AutoModelForVisualQuestionAnswering 与 AutoProcessor 手工串联。Auto 注册表确认了 blip 架构到 BlipForQuestionAnswering 的映射(见 modeling_auto.py 中 MODEL_FOR_VISUAL_QUESTION_ANSWERING_MAPPING_NAMES 等常量)。
import torch
from PIL import Image
from transformers import AutoModelForVisualQuestionAnswering, AutoProcessor
processor = AutoProcessor.from_pretrained("Salesforce/blip-vqa-base")
model = AutoModelForVisualQuestionAnswering.from_pretrained(
"Salesforce/blip-vqa-base",
device_map="auto", # 自动分配 GPU / CPU
torch_dtype=torch.float16, # 半精度加速(需 GPU 支持)
)
# 读取仓库内置 COCO 样例图片
image = Image.open("tests/fixtures/tests_samples/COCO/000000039769.png")
question = "What is in this image?"
# 注意:图片与文本必须由同一个 processor 处理,processor 会自动完成 resize/rescale/normalize 与 tokenize
inputs = processor(images=image, text=question, return_tensors="pt").to(model.device, torch.float16)
# BLIP 为 encoder-decoder 结构,最终答案通过自回归生成得到
output = model.generate(**inputs)
print(processor.batch_decode(output, skip_special_tokens=True)[0])
要点拆解:
processor(...)一次性把图片变成pixel_values、把问题变成input_ids/attention_mask,并统一移动到模型所在设备、转为 fp16;- 由于输出是文本而非 logits 取 argmax,VQA 必须走
generate(); processor.batch_decode(output, skip_special_tokens=True)负责去掉 BOS/SEP/PAD 等特殊 token 后还原答案字符串。
三个下游模型类:按任务选择正确的入口
文档特别强调:BlipModel 属于早期综合入口,后续版本将弃用,应按任务在三个专用模型中选择(官方提示见 docs/source/en/model_doc/blip.md 及 modeling_blip.py):
| 模型类 | 适用任务 | 结构组成 |
|---|---|---|
BlipForConditionalGeneration |
图像描述(captioning)、以文本为前缀的条件生成 | 视觉编码器 BlipVisionModel + 文本解码器 BlipTextLMHeadModel |
BlipForQuestionAnswering |
视觉问答(VQA) | 视觉编码器 + 文本编码器(带交叉注意力融合图像)+ 文本解码器 |
BlipForImageTextRetrieval |
图文检索 / ITM 匹配打分 | 视觉编码器 + 文本编码器 + 投影层 + ITM 分类头 |
BlipModel(已弃用) |
通用对比学习入口(近似 CLIP) | 双塔编码器 + 投影 + logit scale |
BlipForConditionalGeneration:图像描述与条件文本生成
该类在 modeling_blip.py 中实现,main_input_name = "pixel_values",结构为 BlipVisionModel + BlipTextLMHeadModel。其 forward 先将图片编码为 image_embeds,再以 encoder_hidden_states=image_embeds 送入文本解码器做交叉注意力(源码 L830-L846)。
该类的 generate 覆盖了父类实现(源码 L857-L932),行为要点如下:
- 不传
input_ids时,解码器从[BOS](bos_token_id=30522)开始生成纯图像描述; - 传
input_ids时,它会作为文本 prompt,让解码器“续写”——这正是文档所述“以文本前缀引导生成”的能力; - 生成阶段
eos_token_id被设为sep_token_id(102),pad_token_id为 0。
from PIL import Image
from transformers import AutoProcessor, BlipForConditionalGeneration
processor = AutoProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base")
image = Image.open("tests/fixtures/tests_samples/COCO/000000039769.png")
# 不传 text:纯图像描述
inputs = processor(images=image, return_tensors="pt")
print(processor.decode(model.generate(**inputs)[0], skip_special_tokens=True))
# 传 text 作为前缀:条件生成(prompt-guided captioning)
inputs = processor(images=image, text="A picture of", return_tensors="pt")
print(processor.decode(model.generate(**inputs)[0], skip_special_tokens=True))
BlipForQuestionAnswering:视觉问答
该类结构为“视觉编码器 + 文本编码器 + 文本解码器”(源码 L942-L955),与 captioning 的关键差异在于引入了一个文本编码器:它先让问题 token 与图像特征做交叉注意力(question_embeds),融合后的表示再作为解码器的 encoder_hidden_states 输出答案(源码 L1033-L1055)。
forward 有一个必须遵守的约束(源码 L1017-L1022):必须传入 decoder_input_ids 或 labels 之一。训练时传 labels(源码注释说明 labels 已被右移,符合 #23153 的约定),推理时调用 generate()。VQA 训练片段(从模型 docstring 提取):
# 训练:question 作为编码器输入,answer 作为解码器监督
inputs = processor(images=image, text="How many cats are in the picture?", return_tensors="pt")
labels = processor(text="2", return_tensors="pt").input_ids
inputs["labels"] = labels
outputs = model(**inputs)
loss = outputs.loss
loss.backward()
# 推理
inputs = processor(images=image, text="How many cats are in the picture?", return_tensors="pt")
print(processor.decode(model.generate(**inputs)[0], skip_special_tokens=True))
BlipForImageTextRetrieval:图文检索与 ITM 打分
该类对应理解型任务(源码 L1165-L1182),在视觉编码器与文本编码器之上增加:
vision_proj/text_proj:将两侧特征投影到image_text_hidden_size=256的共享空间;itm_head:Linear(text_hidden_size, 2)的图像-文本匹配分类头。
forward 通过 use_itm_head 开关支持两种打分模式(源码 L1248-L1270):
use_itm_head=True(默认):对“图文是否匹配”做二分类,取[CLS]位置的 logits;use_itm_head=False:对vision_proj/text_proj投影后的[CLS]特征做 L2 归一化后点积,得到余弦相似度作为检索分数。
from PIL import Image
from transformers import AutoProcessor, BlipForImageTextRetrieval
processor = AutoProcessor.from_pretrained("Salesforce/blip-itm-base-coco")
model = BlipForImageTextRetrieval.from_pretrained("Salesforce/blip-itm-base-coco")
image = Image.open("tests/fixtures/tests_samples/COCO/000000039769.png")
inputs = processor(images=image, text="an image of a cat", return_tensors="pt")
# ITM 二分类 logits:判断该文本是否与该图匹配
outputs = model(**inputs)
print(outputs.itm_score)
已弃用的 BlipModel 与特征提取接口
BlipModel(源码 L509)是类 CLIP 的双塔对比学习封装:文本塔 BlipTextModel 与视觉塔 BlipVisionModel 分别输出特征,经 text_projection/visual_projection 投影到 projection_dim=512 并 L2 归一化,相似度乘以可学习的 logit_scale(初始值 2.6592,见配置)得到 logits_per_image/logits_per_text(源码 L730-L758)。训练目标是对称的 image_text_contrastive_loss(该函数与 contrastive_loss 均直接拷贝自 CLIP 实现,源码 L44-L53)。
即使该类即将弃用,其三个特征接口仍值得理解,因为它们的逻辑被下游模型复用:
get_text_features:纯文本编码,pooler_output经过text_projection;get_image_features:纯图像编码,pooler_output经过visual_projection;get_multimodal_features:先视觉编码得到image_embeds,再将其作为encoder_hidden_states喂给文本编码器做交叉注意力,返回融合了图文信息的“多模态特征”。
配置类深度解析:BlipConfig / BlipTextConfig / BlipVisionConfig
BLIP 是一个复合架构,因此配置被拆成三个类,位于 configuration_blip.py。BlipConfig 通过 sub_configs = {"text_config": BlipTextConfig, "vision_config": BlipVisionConfig}(源码 L145)把两个子配置聚合为一个整体——这正是 AutoModel/AutoProcessor 加载时能看到统一 config.json 的原因。
BlipVisionConfig(视觉塔,model_type="blip_vision_model")
| 参数 | 默认值 | 说明 |
|---|---|---|
hidden_size |
768 | Transformer 隐藏维度 |
intermediate_size |
3072 | FFN 中间层维度 |
projection_dim |
512 | 对比学习投影输出维度 |
num_hidden_layers |
12 | 编码器层数 |
num_attention_heads |
12 | 注意力头数 |
image_size |
384 | 输入图像边长(预训练分辨率) |
patch_size |
16 | Patch 尺寸,patch 数 = (384/16)² = 576 |
hidden_act |
"gelu" |
FFN 激活函数 |
layer_norm_eps |
1e-5 | LayerNorm epsilon |
attention_dropout |
0.0 | 注意力 dropout |
initializer_range |
1e-10 | 权重初始化范围 |
以上默认值对应 configuration_blip.py L97-L107。
BlipTextConfig(文本塔/解码器,model_type="blip_text_model")
| 参数 | 默认值 | 说明 |
|---|---|---|
vocab_size |
30524 | 词表大小 |
hidden_size |
768 | 隐藏维度 |
encoder_hidden_size |
768 | 交叉注意力的 key/value 维度(被强制同步为视觉塔 hidden_size) |
intermediate_size |
3072 | FFN 中间层维度 |
projection_dim |
768 | 文本侧投影维度 |
num_hidden_layers |
12 | Transformer 层数 |
num_attention_heads |
8 | 注意力头数 |
max_position_embeddings |
512 | 文本最大序列长度 |
hidden_dropout_prob |
0.0 | 隐藏层 dropout |
attention_probs_dropout_prob |
0.0 | 注意力 dropout |
bos_token_id |
30522 | 生成起始符 |
eos_token_id |
2 | 结束符 |
pad_token_id |
0 | 填充符 |
sep_token_id |
102 | 分隔符(生成阶段的 eos 实际使用它) |
is_decoder |
True | 是否以解码器模式运行 |
use_cache |
True | 生成时使用 KV cache |
tie_word_embeddings |
True | 输入输出词嵌入权重共享 |
label_smoothing |
0.0 | 训练损失标签平滑系数,取值范围 [0,1] |
对应 configuration_blip.py L52-L72。值得注意 tie_word_embeddings=True 与解码器头部实现是配套的:BlipForConditionalGeneration/BlipForQuestionAnswering 通过 _tied_weights_keys 显式声明了 text_decoder.cls.predictions.decoder.weight 与 word embedding 之间的权重共享关系(见 modeling_blip.py L772-L775)。
BlipConfig(聚合配置,model_type="blip")
| 参数 | 默认值 | 说明 |
|---|---|---|
projection_dim |
512 | 图文投影统一维度 |
logit_scale_init_value |
2.6592 | 对比学习温度参数初值 |
image_text_hidden_size |
256 | 图文融合层(retrieval 的 proj 层)隐藏维度 |
label_smoothing |
0.0 | 解码器 LM loss 标签平滑系数 |
initializer_factor |
1.0 | 初始化缩放因子 |
initializer_range |
0.02 | 初始化范围 |
BlipConfig 的 __post_init__(源码 L157-L172)负责收尾:两个子配置若传 dict 会被实例化为对应类;若为空则使用默认值;同时强制 text_config.encoder_hidden_size = vision_config.hidden_size,从配置层保证交叉注意力的维度一致性。使用时可像源码 docstring 演示的那样分别构造再合并:
from transformers import BlipConfig, BlipTextConfig, BlipVisionConfig
config = BlipConfig(text_config=BlipTextConfig(), vision_config=BlipVisionConfig())
# 等价于 BlipConfig(),二者都会被自动实例化并完成维度同步
预处理与 Processor:图片与文本的标准化入口
BLIP 的多模态输入需要在同一入口统一处理,仓库提供了三个类(image_processing_blip.py、image_processing_pil_blip.py、processing_blip.py):
BlipImageProcessor:基于TorchvisionBackend的图像处理器,类属性即默认预处理策略——BICUBIC重采样、size={"height": 384, "width": 384}、default_to_square=True、do_convert_rgb=True,均值/方差采用 OpenAI CLIP 的OPENAI_CLIP_MEAN/OPENAI_CLIP_STD(image_processing_blip.py L21-L31),完整流程为 Resize → Rescale → Normalize → Convert RGB;BlipImageProcessorPil:同配置的纯 PIL 后端版本,为不依赖 torchvision 的环境提供等价功能(其preprocess同样被 docs/source/en/model_doc/blip.md 的 autodoc 覆盖);BlipProcessor:ProcessorMixin的组合处理器,构造时接收image_processor与tokenizer,并强制tokenizer.return_token_type_ids = False(BLIP 不使用 token type ids,见 processing_blip.py L42-L48)。
AutoProcessor 就是根据 checkpoint 的 preprocessor_config.json 自动选择这三个类中合适组合的便捷入口,因此上文所有示例都推荐用 AutoProcessor.from_pretrained。
源码级架构剖析:从 Patch 到融合表示
视觉塔:ViT 式 Patch Embedding + 可插值位置编码
BlipVisionEmbeddings(modeling_blip.py L172-L243)用卷积核/步长均为 patch_size 的 nn.Conv2d(3, 768, 16, 16) 切 patch,前置一个可学习的 class token,并采用可学习位置编码。它实现了一个对实战很有价值的机制——interpolate_pos_encoding:当输入图片分辨率不是训练时的 384×384 时,位置编码会沿空间维度做 bicubic 插值(对齐 DINO/DINOv2 的做法),从而支持任意分辨率输入。这在文档介绍的高分辨率推理场景中尤为重要。
BlipVisionModel.forward(源码 L473-L498)返回 BaseModelOutputWithPooling:last_hidden_state 经过 post_layernorm,pooler_output 取 [CLS] 位置再做一次 LayerNorm。
文本塔:可复用的 decoder 结构
BlipTextModel/BlipTextLMHeadModel 被拆分在独立的 modeling_blip_text.py 中,其中注意力层同时支持自注意力与针对图像特征的交叉注意力(encoder_hidden_states 参数)。BlipTextLMHeadModel 在文本塔之上叠加 LM Head,作为 captioning 与 VQA 的共享解码器组件被两个上游模型类复用——这是理解 BLIP 各模型参数重叠关系的钥匙。
权重转换、回归测试与生态集成
- 权重转换脚本:convert_blip_original_pytorch_to_hf.py(192 行)内含
rename_key函数,负责把 Salesforce 官方 PyTorch checkpoint 的 key 名映射为 HF 命名规范,供从官方仓库移植自定义检查点使用。 - 回归测试:tests/models/blip 目录下四个测试文件覆盖模型前向(
test_modeling_blip.py、test_modeling_blip_text.py)、图像预处理(test_image_processing_blip.py)与 Processor 文本-图像联合处理(test_processing_blip.py)。阅读这些测试可以快速确认处理器默认参数的边界行为与各模型类的输入输出张量形状。 - Auto 体系接入:BLIP 家族注册在多张 Auto 映射表中——
MODEL_MAPPING(blip→BlipModel)、MODEL_FOR_CAUSAL_LM_MAPPING(blip→BlipForConditionalGeneration)以及 VQA、Retrieval 映射(见 modeling_auto.py)。这也解释了为何同一个blip架构能通过AutoModelForVisualQuestionAnswering等多种 Auto 类按需加载,同时也为后续扩展(如 BLIP-2)共用架构名埋下伏笔。
模型取舍与常见问题小结
- 该选哪个类? 描述/条件生成用
BlipForConditionalGeneration,VQA 用BlipForQuestionAnswering,打分/检索用BlipForImageTextRetrieval;不要在新代码中使用将被弃用的BlipModel。 - 分辨率限制与扩展:默认
image_size=384、patch_size=16。对更高分辨率图片,可在配置中调大image_size或利用位置编码插值机制直接传入大图。 - 文本超长怎么办:文本侧
max_position_embeddings=512,超出会在BlipTextEmbeddings中直接抛错(modeling_blip.py L267-L271),预处理时应按需截断。 - 继续深入:上文涉及的官方模型文档原文位于 docs/source/en/model_doc/blip.md;本文所引配置、模型与处理器实现分别在
src/transformers/models/blip/下的configuration_blip.py、modeling_blip.py、modeling_blip_text.py、processing_blip.py与两个image_processing*文件中,可作为进一步阅读与二次开发的起点。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00