Transformers 中的 SigLIP:图文相似度、零样本图像分类与低显存推理的完整指南
2026/9/8 21:55:56 网站建设 项目流程

Transformers 中的 SigLIP:图文相似度、零样本图像分类与低显存推理的完整指南

【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers

SigLIP 是 Hugging Face Transformers 中一个与 CLIP 同类的多模态图文模型,但其训练时采用成对 sigmoid 损失(pairwise sigmoid loss),摆脱了对 batch 内全局相似度矩阵的依赖,因此在小 batch 下也能保持优异性能。读完本文,你将掌握用pipelineAutoModel两种方式使用 SigLIP 计算图文相似度、复现官方零样本分类效果(含 prompt 模板与padding="max_length"细节)、理解SiglipModel双塔结构及其 sigmoid 损失的源码实现,以及通过 bitsandbytes 4bit 量化降低显存负担的完整方法。

SigLIP 是什么:与 CLIP 的关键区别

SigLIP 使用独立的图像编码器和文本编码器,分别为两种模态生成表示。与 CLIP(参见 CLIP 文档)的核心差异在于训练损失函数:

  • CLIP 风格:对比学习需要看到 batch 内所有图文对的全局相似度矩阵(softmax over batch),batch 越大负样本越多、效果越好,但对显存和 batch size 有较强依赖;
  • SigLIP:训练时对图文对使用成对 sigmoid 损失,不需要 batch 内全局视角。这带来两个直接好处——可以高效扩展到大 batch,同时在小 batch 下也能取得更好的性能(引自官方文档 SigLIP 模型文档)。

所有官方 SigLIP 检查点均可通过google/siglip-*系列模型获取,例如本文示例使用的google/siglip-base-patch16-224(base 规模、16px patch、224 分辨率)。

快速上手:Pipeline 方式做零样本图像分类

最简路径是用pipeline加载zero-shot-image-classification任务:

from transformers import pipeline image = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg" candidate_labels = ["a Pallas cat", "a lion", "a Siberian tiger"] pipeline = pipeline(task="zero-shot-image-classification", model="google/siglip-base-patch16-224", device=0) pipeline(image, candidate_labels=candidate_labels)

pipeline内部会自动完成图像预处理、文本模板化(把每个候选标签包装为自然语言句子)、双向量相似度计算和概率归一化,适合快速验证模型效果。

AutoModel 方式:手动控制图文相似度计算

当需要自定义 prompt 模板、复用特征或接入下游逻辑时,使用AutoModel+AutoProcessor手动调用:

import requests import torch from PIL import Image from transformers import AutoModel, AutoProcessor model = AutoModel.from_pretrained("google/siglip-base-patch16-224", device_map="auto", attn_implementation="sdpa") processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-224") url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg" image = Image.open(requests.get(url, stream=True).raw) candidate_labels = ["a Pallas cat", "a lion", "a Siberian tiger"] texts = [f'This is a photo of {label}.' for label in candidate_labels] inputs = processor(text=texts, images=image, padding="max_length", return_tensors="pt").to(model.device) with torch.no_grad(): outputs = model(**inputs) logits_per_image = outputs.logits_per_image probs = torch.sigmoid(logits_per_image) print(f"{probs[0][0]:.1%} that image 0 is '{candidate_labels[0]}'")

这段代码里有四个关键点,与源码行为一一对应:

  1. padding="max_length"必须显式传入。因为 SigLIP 文本编码器在训练时就采用最长长度 padding,单独使用 [SiglipTokenizer] 或 [SiglipProcessor] 时如果不加该参数,相似度结果会偏离训练分布;
  2. prompt 模板"This is a photo of {label}."。要得到与Pipeline一致的结果,必须给 processor 传入这种带模板的句子,而不是裸标签;
  3. logits_per_image不是 logits 概率,需要再过一层torch.sigmoid。这正对应 sigmoid 损失的设计:每个图文对独立输出一个"匹配/不匹配"的 sigmoid 概率,形状为(image_batch_size, text_batch_size)
  4. attn_implementation="sdpa"可切换到更省显存的注意力实现(详见下文"显存与注意力实现"一节)。

源码级剖析:SiglipModel 双塔结构与 Sigmoid 损失

SigLIP 的模型实现位于 modeling_siglip.py。从源码结构看,整个模型由以下几个部分组成:

双塔编码 + 可学习的尺度/偏置

SiglipModel.__init__中,模型分别实例化文本塔与视觉塔:

self.text_model = SiglipTextModel._from_config(text_config) self.vision_model = SiglipVisionModel._from_config(vision_config) self.logit_scale = nn.Parameter(torch.randn(1)) self.logit_bias = nn.Parameter(torch.randn(1))

logit_scalelogit_bias是两个可学习的标量参数,分别对应温度系数与偏置,用于调节 sigmoid 匹配的决策边界。

前向流程:余弦相似度 × 温度

SiglipModel.forward的推理逻辑是:

image_embeds = vision_outputs.pooler_output text_embeds = text_outputs.pooler_output # normalized features image_embeds = image_embeds / image_embeds.norm(p=2, dim=-1, keepdim=True) text_embeds = text_embeds / text_embeds.norm(p=2, dim=-1, keepdim=True) # cosine similarity as logits logits_per_text = torch.matmul(text_embeds, image_embeds.t().to(text_embeds.device)) logit_scale, logit_bias = self.logit_scale.to(text_embeds.device), self.logit_bias.to(text_embeds.device) logits_per_text = logits_per_text * logit_scale.exp() + logit_bias logits_per_image = logits_per_text.t()

即:两塔池化输出先做 L2 归一化,再点积得到余弦相似度矩阵,乘以exp(logit_scale)(温度取反方向)并加上logit_bias,最后转置得到logits_per_image。返回的SiglipOutput同时包含losslogits_per_imagelogits_per_texttext_embedsimage_embeds以及两个子塔的完整输出,方便直接取特征做检索。

Sigmoid 损失只在训练时使用

forward中通过return_loss参数触发训练损失(代码注释标明该实现改编自 Google big_vision 中的 SigLIP 官方实现):

if return_loss: # Adapted from .../big_vision/.../siglip.py#L287 eye = torch.eye(logits_per_text.size(0), device=logits_per_text.device) m1_diag1 = -torch.ones_like(logits_per_text) + 2 * eye loglik = torch.nn.functional.logsigmoid(m1_diag1 * logits_per_text) nll = -torch.sum(loglik, dim=-1) loss = nll.mean()

这个公式把每个 batch 内样本拆成独立的二分类问题:对角线位置(正确图文对)标签为 1,其余位置标签为 0,对每行分别取logsigmoid再求和取负。它不依赖 batch 内其他样本的相似度值作为"竞争项"——这正是"成对 sigmoid 损失"消除全局视角依赖的数学体现。

文本塔:双向注意力 + 末位 token 池化

SiglipTextModel.forward有两个区别于因果语言模型的特征:

  • 注释明确写道 "SigLIP's text model does not use a causal mask",实际调用的是create_bidirectional_mask,即文本编码器是双向Transformer;
  • 池化策略是pooled_output = last_hidden_state[:, -1, :]——取最后一个 token的隐藏状态(训练时因padding="max_length"恒为 EOS 位置),再经过线性投影头self.head映射到projection_size

这也是为什么推理时必须padding="max_length":它保证"最后一个 token"始终是同一个语义位置(EOS),而非不同长度文本各自不同的最后一个实义 token。

视觉塔:Patch 卷积嵌入 + 多头注意力池化头

  • 输入经SiglipVisionEmbeddingsConv2d(kernel_size=patch_size, stride=patch_size)切成 patch 序列,加上可学习的 2D 位置嵌入;还支持interpolate_pos_encoding(双三次插值位置编码),用于推理时输入更高分辨率图像;
  • 编码器结束后经过一次post_layernorm,再由SiglipMultiheadAttentionPoolingHead完成池化:一个可学习的probe查询向量对 patch token 序列做 MultiheadAttention,输出即整图表示。这与 CLIP 的 mean pooling 不同,是 SigLIP 视觉侧的标志性设计。

配置体系:三个 Config 类与默认值

配置定义在 configuration_siglip.py。SiglipConfig由两个子配置组成,缺失时自动用默认值初始化:

配置类关键默认值
SiglipTextConfigvocab_size=32000hidden_size=768intermediate_size=3072num_hidden_layers=12num_attention_heads=12max_position_embeddings=64pad_token_id=1bos_token_id=49406eos_token_id=49407
SiglipVisionConfighidden_size=768num_hidden_layers=12num_attention_heads=12image_size=224patch_size=16num_channels=3
SiglipConfigtext_config/vision_config双子配置 +initializer_factor=1.0

两个值得注意的实现细节:

  • 文本侧的pad_token_id默认是1(对应 SentencePiece 词表中的<unk>),注释中说明这与CLIPTokenizer的默认值不同——因为 SigLIP 的 EOS 同时也是 padding token(</s>),见下文 tokenizer 部分;
  • SiglipTextConfig.projection_size若未显式设置会自动回退为hidden_size

也可以显式组合两个子配置来构造:

from transformers import SiglipConfig, SiglipTextConfig, SiglipVisionConfig config_text = SiglipTextConfig() config_vision = SiglipVisionConfig() config = SiglipConfig(text_config=config_text, vision_config=config_vision)

分词器与处理器:为什么 EOS 就是 PAD

SiglipTokenizer基于 SentencePiece,model_max_length默认为64,与文本塔max_position_embeddings=64对齐。其特殊 token 约定是:

eos_token="</s>", unk_token="<unk>", pad_token="</s>", # PAD 与 EOS 使用同一个 token

build_inputs_with_special_tokens可以看到输入序列只会在末尾追加</s>_add_eos_if_not_present防止重复添加),batching 时短序列再用同一个</s>补齐到max_length——训练与推理位置分布因此保持一致。

另外,tokenizer 内置了canonicalize_text方法(改编自 Google big_vision 的 prompt 工程工具):小写化、去标点、压缩空白,用于评估时对文本做规范化,提升检索/分类一致性。

图像侧由SiglipImageProcessor负责,默认参数为:

参数默认值说明
size{"height": 224, "width": 224}默认输入分辨率(与视觉配置一致)
resamplePILImageResampling.BICUBIC双三次重采样
image_mean/image_stdIMAGENET_STANDARD_MEAN/IMAGENET_STANDARD_STDImageNet 标准归一化
do_resize/do_rescale/do_normalize/do_convert_rgb均为True完整预处理链

SiglipProcessor是这两个组件的组合入口,即上文示例中AutoProcessor.from_pretrained实际加载的类。仓库内还存在纯 PIL 后端版本SiglipImageProcessorPil(见 image_processing_pil_siglip.py),供不依赖 torchvision 的场景使用。

显存优化:SDPA、FlashAttention-2 与 bitsandbytes 4bit

切换注意力实现

官方文档提示,可将attn_implementation切换为"sdpa""flash_attention_2"以使用更省显存的注意力。从SiglipPreTrainedModel的类属性看,实现同时声明了:

_supports_flash_attn = True _supports_sdpa = True _supports_flex_attn = True _supports_attention_backend = True

即 eager / sdpa / flash_attention_2 / flex_attention 均受支持。使用 FlashAttention-2 时需先安装对应版本:

# pip install -U flash-attn --no-build-isolation from transformers import SiglipModel model = SiglipModel.from_pretrained( "google/siglip-so400m-patch14-384", attn_implementation="flash_attention_2", device_map="auto", )

注意 attention 实现会向下分发到text_modelvision_model两个子配置上(测试用例 test_sdpa_can_dispatch_composite_models 专门验证了这一行为)。

4bit 量化:只量化权重

量化通过以更低精度表示权重来降低显存开销,可用后端总览见 Quantization 概览。下面示例用 bitsandbytes 只把权重量化到 int4:

import requests import torch from PIL import Image from transformers import AutoModel, AutoProcessor, BitsAndBytesConfig bnb_config = BitsAndBytesConfig(load_in_4bit=True) model = AutoModel.from_pretrained("google/siglip-base-patch16-224", quantization_config=bnb_config, device_map="auto", attn_implementation="sdpa") processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-224") url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg" image = Image.open(requests.get(url, stream=True).raw) candidate_labels = ["a Pallas cat", "a lion", "a Siberian tiger"] texts = [f'This is a photo of {label}.' for label in candidate_labels] inputs = processor(text=texts, images=image, padding="max_length", return_tensors="pt").to(model.device) with torch.no_grad(): outputs = model(**inputs) logits_per_image = outputs.logits_per_image probs = torch.sigmoid(logits_per_image) print(f"{probs[0][0]:.1%} that image 0 is '{candidate_labels[0]}'")

除了模型加载行的quantization_config=bnb_config,其余流程与非量化版本完全相同——量化是"透明"的后端替换。

训练支持与注意事项

官方文档的 Notes 部分给出了几条重要使用约束,这里逐条结合实现说明:

  1. 训练支持 DDP 与 FSDP(单节点多 GPU),但不使用torch.distributed工具链,batch size 的可扩展性可能受限;
  2. 单独使用SiglipTokenizer/SiglipProcessor时必须传padding="max_length",因为模型就是这样训练的(源码中取最后一个 token 池化的设计依赖这一点);
  3. 要与Pipeline结果对齐,需传入 prompt 模板"This is a photo of {label}."
  4. attn_implementation可在"sdpa""flash_attention_2"之间切换以降低注意力显存占用。

此外,SigLIP 还支持仅用视觉塔做图像分类的封装SiglipForImageClassification:它在SiglipVisionModel之上直接挂一个线性分类头(hidden_size -> num_labels),num_labels=0时退化为nn.Identity,适合 ImageNet 风格的单标签分类任务。

测试与进一步阅读

SigLIP 的完整测试套件位于 tests/models/siglip/:

  • test_modeling_siglip.py:模型通用测试(含 SDPA 分发、前向torch.sigmoid(logits_per_image)概率计算路径等);
  • test_tokenization_siglip.py:分词行为验证;
  • test_image_processing_siglip.py:图像预处理验证。

相关源码入口汇总:

组件文件
模型实现(SiglipModel/ 文本塔 / 视觉塔 / sigmoid 损失)modeling_siglip.py
配置(SiglipConfig三件套)configuration_siglip.py
分词器(SentencePiece,EOS 即 PAD)tokenization_siglip.py
图像处理器(torchvision 后端 / PIL 后端)image_processing_siglip.py / image_processing_pil_siglip.py
处理器入口processing_siglip.py
权重转换脚本convert_siglip_to_hf.py

总结:在 Transformers 中使用 SigLIP,核心是记住"sigmoid 概率而非 softmax 相似度"、"padding 必须拉满到 max_length"、"零样本分类要用完整 prompt 模板"这三条约定,其余的量化、注意力后端、子塔单独使用都建立在标准的AutoModel/AutoProcessor接口之上。

【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询