概述
Siglip2 测试套件的位置和规模:
| 项目 | 说明 |
|---|---|
| 路径 | G:\Project\blog\content\posts\VLM\Siglip2\ |
| 文件数 | 4 个 .py 文件 |
| 总行数 | ~700 行 |
| 依赖 | transformers 核心库、torch、PIL、numpy、pytest |
| 定位 | 对 Siglip2 多模态模型的完整测试覆盖:tokenizer、image processor、vision model、text model、combined model |
| 上游模型 | google/siglip2-base-patch16-naflex (灵活分辨率), google/siglip2-base-patch16-224 (固定分辨率) |
四个文件的职责定位速览
| 文件 | 行数 | 抽象层次 | 核心角色 |
|---|---|---|---|
__init__.py | 0 | 出口层 (Barrel) | 空文件,标记目录为 Python 包 |
test_image_processing_siglip2.py | ~110 | 预处理层 (Preprocessing) | 测试图像处理器:resize、rescale、normalize、patchify 全流程 |
test_modeling_siglip2.py | ~540 | 模型层 (Model) | 测试 Vision/Text/Combined/Classification 四种模型的 forward、SDPA、Flash Attention |
test_tokenization_siglip2.py | ~55 | 分词层 (Tokenization) | 测试 tokenizer 的 lowercasing、padding、truncation、save/load 行为 |
分析框架说明
对每个文件,按以下五层解构:
+-------------------------------------------------------------+
| 1. 代码 (Code) |
| 具体的函数签名、类结构、关键代码段 |
+-------------------------------------------------------------+
| 2. 功能 (Function) |
| 这段代码在测试运行时做什么 |
+-------------------------------------------------------------+
| 3. 抽象 (Abstraction) |
| 代码在测试架构中的抽象层级/角色 |
+-------------------------------------------------------------+
| 4. 实例 (Instance) |
| 在哪里被引用/谁调用它 |
+-------------------------------------------------------------+
| 5. 设计目的 (Design Purpose) |
| 为什么这么设计,验证了什么核心逻辑 |
+-------------------------------------------------------------+
文件一:__init__.py – 出口层 (Barrel Layer)
| 项目 | 值 |
|---|---|
| 行数 | 0 |
| 导出量 | 0 |
| 依赖 | 无 |
解构分析
代码:
| |
功能:标记 Siglip2/ 目录为 Python 包,使测试发现工具(如 pytest、unittest)能够扫描该目录。
抽象:Python 包标记 – 在 Python 的隐式命名空间包(PEP 420)环境下,该文件确保目录被显式视为 package,使相对 import(如 from ...test_image_processing_common import ...)可正确解析。
被引用处:
test_modeling_siglip2.py中from ...test_modeling_common import ModelTesterMixintest_image_processing_siglip2.py中from ...test_image_processing_common import ImageProcessingTestMixin
设计目的:保持 HuggingFace Transformers 测试套件的标准目录结构。每个模型的测试文件统一放在 tests/models/{model_name}/ 下,__init__.py 是必需的包标记。
文件二:test_image_processing_siglip2.py – 预处理层 (Preprocessing Layer)
整体信息
| 项目 | 值 |
|---|---|
| 行数 | ~110 |
| 类数 | 2 (Tester + TestCase) |
| 关键配置 | patch_size=16, max_num_patches=256, rescale_factor=1/255, mean=[0.5,0.5,0.5], std=[0.5,0.5,0.5] |
| 继承链 | ImageProcessingTestMixin, unittest.TestCase |
解构分析
1. Siglip2ImageProcessingTester – 测试数据工厂
代码:
| |
功能:为图像处理测试提供标准化的配置参数和测试数据。核心方法:
prepare_image_processor_dict()– 返回图像处理器的完整参数字典expected_output_image_shape(images)– 返回预期的输出 shape:(max_num_patches, patch_size * patch_size * num_channels)=(256, 768)prepare_image_inputs(...)– 生成不同分辨率的批量图像输入
抽象:测试夹具工厂 (Test Fixture Factory) – 将图像处理器的参数化配置与测试逻辑分离。测试用例不硬编码参数,而是从 Tester 获取。
被引用处:
Siglip2ImageProcessingTest.setUp()中创建self.image_processor_tester = Siglip2ImageProcessingTester(self)image_processor_dict属性委托给self.image_processor_tester.prepare_image_processor_dict()
设计目的:
- 参数集中管理,修改测试配置只需改 Tester 的默认值
expected_output_image_shape编码了 Siglip2 的核心图像处理公式:图像被切分为最多 256 个 patch,每个 patch 是16*16*3=768维向量rescale_factor=1/255将像素值从 [0,255] 归一化到 [0,1]image_mean=image_std=[0.5,0.5,0.5]将 [0,1] 映射到 [-1,1]
2. Siglip2ImageProcessingTest – 图像处理器测试用例
代码:
| |
功能:三个测试方法:
test_image_processor_properties– 验证图像处理器拥有所有必需的 8 个属性test_image_processor_from_dict_with_kwargs– 验证from_dict()支持 kwargs 覆盖test_call_numpy_4_channels– 被跳过(不支持 4 通道输入)
抽象:接口合规测试 (Contract Test) – 不测试具体输出值,而是验证:
- 图像处理器实现了特定接口(拥有特定属性)
- 序列化/反序列化 (
from_dict) 保持参数一致性 - kwargs 覆盖机制正常工作(patch_size 从 16 覆盖到 32)
被引用处:
- pytest/unittest 自动发现并执行
- 代码标注
# Copied from tests.models.clip.test_image_processing_clip...,说明 Siglip2 的图像处理沿用了 CLIP 的测试框架
设计目的:
# Copied from注释表明 Siglip2 与 CLIP 共享图像处理测试代码,实际处理逻辑可能完全一致- 属性检查覆盖了完整的图像处理 pipeline:
do_resize -> do_rescale -> do_normalize -> patchify max_num_patches=256和patch_size=16是 Siglip2 的核心配置,定义了模型对图像的分割策略- 4 通道测试被跳过,因为 Siglip2 只处理 RGB 三通道图像
文件三:test_modeling_siglip2.py – 模型层 (Model Layer)
整体信息
| 项目 | 值 |
|---|---|
| 行数 | ~540 |
| 类数 | 10 (3 个 Mixin/Tester 基类 + 4 个 TestCase + 2 个 Tester + 1 个 IntegrationTest) |
| 被测模型 | Siglip2VisionModel, Siglip2TextModel, Siglip2Model, Siglip2ForImageClassification |
| 关键输入 | pixel_values, pixel_attention_mask, spatial_shapes |
| 关键输出 | logits_per_image, logits_per_text, pooler_output |
模型架构概览
+----------------------------+
| Siglip2Model |
| (Dual Encoder - Contrastive)|
+----------------------------+
| |
v v
+--------------+ +--------------+
| VisionModel | | TextModel |
| (ViT-based) | | (Transformer)|
+--------------+ +--------------+
| |
v v
pooler_output pooler_output
| |
+----+ +-----+
| |
logits_per_image
logits_per_text
|
+--------+--------+
| |
Siglip2ForImageClassification
(Vision-only head)
解构分析
1. Siglip2ModelTesterMixin – SDPA/Flash Attention 测试混入
SDPA 是缩放点积注意力机制,Eager 是 PyTorch 默认的注意力实现,Flash Attention 是一种高效的注意力计算方法。Siglip2 支持三种注意力后端。
test_sdpa_can_dispatch_composite_models 创建、配置所有待测试的模型实例,保存到临时目录,同一个模型分别用 sdpa/eager 两种注意力实现进行前向传播。
功能:两个关键测试:
- SDPA dispatch – 验证复合模型(vision + text 子模型)能正确分派 SDPA 注意力实现,每个子模型的
_attn_implementation独立配置 - Flash Attention 等价性 – 验证 flash_attention_2 与 eager 模式产生等价输出,容差
atol=4e-2, rtol=4e-2
test_flash_attn_2_inference_equivalence 测试 Flash Attention 与 Eager 在推理阶段的输出一致性。因为 Flash Attention 主要支持半精度计算,测试中使用 float16,并检验了有无 pixel_attention_mask 的两种情况。
抽象:注意力实现兼容性测试 (Attention Backend Compatibility) – 确保模型在 eager、sdpa、flash_attention_2 三种注意力后端下行为一致。
被引用处:
Siglip2VisionModelTest(Siglip2ModelTesterMixin, ...)– Vision-only 测试Siglip2TextModelTest(Siglip2ModelTesterMixin, ...)– Text-only 测试Siglip2ModelTest(Siglip2ModelTesterMixin, ...)– 组合模型测试Siglip2ForImageClassificationModelTest(Siglip2ModelTesterMixin, ...)– 分类测试
设计目的:
- 复合模型分派:Siglip2 是双塔结构,每个塔独立控制注意力实现。MixIn 级测试确保配置保存/加载后分派正确
- Flash Attention 等价性:
pixel_attention_mask会导致 flash attention 与 eager 的 padding 区域不同,测试中通过 mask 相乘进行校正 atol=4e-2是宽松容差,因为不同注意力实现的浮点运算顺序不同,但语义等价
2. Siglip2VisionModelTester – Vision 模型测试数据工厂
功能:生成 Vision 模型的测试输入。核心机制:
- pixel_values 构造:shape 为
(batch_size, seq_length, patch_dim),已经是 patchified 形式。patch_dim = num_channels * patch_size * patch_size = 12 - spatial_shapes 生成:枚举所有可能的
(height, width)组合,使得height * width <= seq_length。有效 shape 示例:(1,1)=(1),(1,2)=(2),(2,1)=(2), …,(4,6)=(24)等 - pixel_attention_mask 构造:根据
spatial_shapes中每个样本的实际 patch 数量设置 mask
抽象:空间感知测试数据生成器 (Spatial-Aware Data Generator) – 模拟真实图像的不同尺寸/宽高比场景。
被引用处:
Siglip2VisionModelTest.setUp()创建self.model_tester = Siglip2VisionModelTester(self)Siglip2ModelTester内部持有一个self.vision_model_tester = Siglip2VisionModelTester(parent, **vision_kwargs)
设计目的:
spatial_shapes是 Siglip2 区别于 CLIP 的核心创新:传统 CLIP 固定输入尺寸(224x224 -> 14x14=196 patches),而 Siglip2 (naflex) 支持灵活分辨率。spatial_shapes记录每个样本的 patch 网格 (height, width),使模型知道如何 reshape 1D patch 序列回 2D 结构用于位置编码pixel_attention_mask用于处理可变 patch 数量的 batch:同一 batch 中不同图像可能产生不同数量的 patch,padding 位置通过 mask 排除- 小尺寸测试配置(patch_size=2, hidden_size=64, num_hidden_layers=2)保证 CI 快速运行
3. Siglip2VisionModelTest – Vision 模型测试用例
代码:
| |
功能:
- 验证 Vision 模型的
forward()签名(首参数为pixel_values) - 验证模型前向传播的输出 shape:
last_hidden_state (batch, seq_len, hidden_size)和pooler_output (batch, hidden_size) - 验证从 HuggingFace Hub 加载预训练模型
抽象:模型接口合规测试 – 确保 Vision 模型:
- 接受
pixel_values,pixel_attention_mask,spatial_shapes三个输入 - 输出标准格式(last_hidden_state + pooler_output)
- 预训练检查点可正确加载
被引用处:由 unittest/pytest 自动发现执行
设计目的:
additional_model_inputs声明了 Siglip2 特有的两个输入,基类ModelTesterMixin会据此调整通用测试逻辑- 关闭设备卸载测试(
test_cpu_offload=False等):因为MultiheadAttentionPoolingHead在卸载时存在问题,临时跳过 - 关闭 embeddings resize 测试:Vision Transformer 不需要文本 tokenizer 的 embeddings resize 机制
test_model_from_pretrained使用 naflex 变体(灵活分辨率),而非固定尺寸版本
4. Siglip2TextModelTester – Text 模型测试数据工厂
代码:
| |
功能:生成 Text 模型的测试输入:
input_ids:随机 token id 序列input_mask:变长序列的 attention mask(每个样本随机截断长度)Siglip2TextConfig:小尺寸测试配置
抽象:变长序列测试数据生成器 – 模拟真实文本的变长特性。
被引用处:
Siglip2TextModelTest.setUp()创建self.model_tester = Siglip2TextModelTester(self)Siglip2ModelTester内部持有self.text_model_tester = Siglip2TextModelTester(parent, **text_kwargs)
设计目的:
- 变量长度序列(通过随机截断
input_mask实现)模拟真实场景中同一 batch 内文本长度不同的情况 max_position_embeddings=512定义了文本模型的最大序列长度- Text Model 比 Vision Model 更简单:只需要
input_ids和attention_mask,不需要类似spatial_shapes的空间信息
5. Siglip2TextModelTest – Text 模型测试用例
代码:
| |
功能:
- 验证 Text 模型前向传播输出 shape
- 跳过独立训练测试(Text 模型需要与 Vision 模型联合训练才有意义)
抽象:文本塔接口测试 – 文本塔仅作为 Siglip2 联合模型的一部分,不支持独立训练。
设计目的:
test_training等 4 个训练相关测试全部跳过,因为 Siglip2 的 loss 是在Siglip2Model层面计算的(对比学习 loss),Siglip2TextModel本身只是一个编码器- 与 Vision Model 类似的
pooler_output输出,确保两个塔的输出对齐
6. Siglip2ModelTester – 组合模型测试数据工厂
代码:
| |
功能:
- 聚合 Text + Vision 两个子模型的测试数据
- 关键验证:
logits_per_image和logits_per_text的 shape 为(vision_batch, text_batch)和(text_batch, vision_batch),是标准的对比学习 logits 矩阵
抽象:双塔模型测试编排器 (Dual-Encoder Test Orchestrator) – 协调两个子模型的测试数据生成,验证联合 forward 的输出格式。
被引用处:
Siglip2ModelTest.setUp()创建self.model_tester = Siglip2ModelTester(self)Siglip2ForImageClassificationModelTester(Siglip2ModelTester)继承并覆盖
设计目的:
- 组合配置:
Siglip2Config由Siglip2TextConfig和Siglip2VisionConfig组合而成,而非单一配置类 - logits 矩阵:是 Siglip2 对比学习损耗的核心输出。传统 CLIP 使用 softmax cross-entropy loss,Siglip2 使用 sigmoid loss(在 logits 矩阵上逐元素计算)。测试验证
(batch, batch)的方形 logits 矩阵 shape text_kwargs/vision_kwargs参数允许覆盖子模型的测试配置
7. Siglip2ModelTest – 组合模型测试用例
代码:
| |
功能:
- 验证组合模型 forward 输出
- 验证
Siglip2Config可分解为独立的Siglip2VisionConfig和Siglip2TextConfig - 跳过
output_attentions、output_hidden_states、input_embeds等不支持的测试
抽象:组合模型完整性测试 – 验证双塔模型的两个子模块正确组合。
被引用处:由 unittest/pytest 自动发现执行
设计目的:
_is_composite = True声明这是复合模型,触发基类中针对复合模型的特殊测试逻辑- config 分解测试是 Siglip2 特有的:确保组合配置的序列化/反序列化后,子配置能独立加载
- 大量跳过:
output_attentions– Siglip2 当前不支持输出注意力权重output_hidden_states– Siglip2 当前不支持输出隐藏状态(get_image_features/get_text_features有局限)- 这些跳过表明 Siglip2 是一个功能尚不完整的模型实现,attention/hidden_state 输出功能需要在未来重构
8. Siglip2ForImageClassificationModelTester & Test – 图像分类测试
代码:
| |
功能:
- 测试
Siglip2ForImageClassification(Vision-only 分类头) - 输入只含
pixel_values, pixel_attention_mask, spatial_shapes,无文本输入 - 梯度检查点测试标记为
xfail(已知失败)
抽象:视觉下游任务头测试 (Vision Downstream Head Test) – 验证 Vision 编码器 + 分类头的组合。
设计目的:
- 复用
Siglip2ModelTester但移除文本输入 - 梯度检查点 xfail 表明:当 Vision 编码器使用 gradient checkpointing 时,某些层的梯度无法正确计算,这是已知的待修复问题
9. Siglip2ModelIntegrationTest – 端到端集成测试
代码:
| |
功能:用真实预训练模型和真实图像执行完整推理:
- 加载
google/siglip2-base-patch16-naflex模型和 processor - 准备 3 张不同尺寸/比例的红底蓝圈图
- 准备 7 条不同语义贴近度的文本
- 验证 logits 值与预期精确匹配
抽象:端到端回归测试 (End-to-End Regression Test) – 确保模型权重更新后推理结果无漂移。
设计目的:
- 多分辨率测试:3 张图片尺寸分别为 224, 1024, 224x1024,验证 naflex 的灵活分辨率特性
- 语义梯度验证:logits 值形成清晰的语义梯度:
- “blue circle with green border on red background” (9.4-10.2) > “blue circle on red background” (4.2-5.0) > “circle” (1.0)
- 负样本 “a dog” (-12.3 到 -13.7) 和 “blue dog” (1.2 到 -2.0) logits 显著低于正样本
- 多平台期望值:不同 CUDA/ROCm/XPU 平台的期望 logits 略有差异,但容差
rtol=1e-3, atol=1e-3保证高度一致 prepare_images()生成的测试图片是确定性图像(红底 + 蓝圆 + 绿边),确保可复现
文件四:test_tokenization_siglip2.py – 分词层 (Tokenization Layer)
整体信息
| 项目 | 值 |
|---|---|
| 行数 | ~55 |
| 类数 | 1 (TestCase) |
| 被测模型 | google/siglip2-base-patch16-224 |
| 关键行为 | 默认 lowercasing、padding/truncation、save/load roundtrip |
解构分析
1. Siglip2TokenizerTest – Tokenizer 测试用例
代码:
| |
功能:三个核心测试:
- Lowercasing 行为:大写和小写输入产生完全相同的 token IDs(单条和批量均验证)
- Padding/Truncation:
max_length=64时所有序列被填充或截断到完全相同长度 - Save/Load 一致性:保存/重载后的 tokenizer 对相同输入产生完全一致的 token IDs
抽象:Tokenizer 行为契约测试 (Tokenizer Contract Test) – 验证 tokenizer 在不同使用模式下的确定性行为。
被引用处:由 unittest 自动发现执行
设计目的:
- Lowercasing 是 Siglip2 tokenizer 的默认行为,这源于 Siglip2 的文本处理策略:与 CLIP 类似,Siglip2 在文本侧使用小写 tokenization 来减少词汇量、提高泛化能力
- 测试覆盖三种模式:单条编码 vs 批量编码 vs padding/truncation,确保批量处理与单条处理一致
- Save/Load roundtrip 确保序列化不丢失信息(vocab、special tokens、lowercasing 配置等)
- 注意:tokenizer 测试使用
google/siglip2-base-patch16-224(固定 224x224 尺寸),而模型测试使用google/siglip2-base-patch16-naflex(灵活分辨率)。两者 tokenizer 行为一致,差异仅在 vision encoder 的分辨率处理
跨文件架构总结
Siglip2 核心设计决策
| 决策 | 体现位置 | 理由 |
|---|---|---|
| 灵活分辨率 (Naflex) | test_modeling_siglip2.py — spatial_shapes 参数 | 传统 CLIP 固定 224x224 输入限制了对非方形/高分辨率图像的利用。Siglip2 通过 spatial_shapes + pixel_attention_mask 支持自适应 patch 数量 |
| Dual Encoder 架构 | test_modeling_siglip2.py — Siglip2Model = Vision + Text | 复用 CLIP 的双塔设计,但改用 Sigmoid Loss 替代 Softmax CE |
| Lowercasing Tokenizer | test_tokenization_siglip2.py | 减少词汇量,提高文本编码的泛化性 |
| Patch + Pooling 输出 | test_modeling_siglip2.py — pooler_output shape | Vision 和 Text 编码器都输出 pooler_output(而非仅用 last_hidden_state pooling),通过 MultiheadAttentionPoolingHead 聚合 |
| 注意力实现可替换 | Siglip2ModelTesterMixin — SDPA/Flash Attn 测试 | 模型设计为注意力实现无关,eager/sdpa/flash_attention_2 均可运行 |
| 残缺点但可用 | 大量 @unittest.skip | output_attentions、output_hidden_states 等功能尚未实现,gradient checkpointing 在分类头有已知 bug |
测试覆盖矩阵
| 被测组件 | 测试文件 | 关键验证 |
|---|---|---|
| Tokenizer | test_tokenization_siglip2.py | Lowercasing, padding, save/load |
| Image Processor | test_image_processing_siglip2.py | Properties, from_dict, patchify config |
| Vision Model | test_modeling_siglip2.py | Forward shape, SDPA/Flash Attn, pretrained loading |
| Text Model | test_modeling_siglip2.py | Forward shape, SDPA/Flash Attn, pretrained loading |
| Combined Model | test_modeling_siglip2.py | Logits shape, config decomposition, SDPA/Flash Attn |
| Classification Head | test_modeling_siglip2.py | Vision-only forward, xfail gradient checkpointing |
| End-to-End | test_modeling_siglip2.py | Real model + real images, exact logit matching |
测试参数配置速查
| 参数 | Vision (小测试) | Text (小测试) | 真实模型 (base) |
|---|---|---|---|
hidden_size | 64 | 64 | 768 |
num_hidden_layers | 2 | 2 | 12 |
num_attention_heads | 4 | 4 | 12 |
patch_size | 2 | N/A | 16 |
max_num_patches | N/A (seq_length=24) | N/A | 256 |
max_position_embeddings | N/A | 512 | 64 |
vocab_size | N/A | 99 (mock) | ~32000 |
数据流全貌
[Image] [Text]
| |
v v
ImageProcessor Tokenizer
| (resize, rescale, | (lowercase,
| normalize, patchify) | tokenize,
| | pad/truncate)
v v
pixel_values input_ids
pixel_attention_mask attention_mask
spatial_shapes
| |
v v
VisionModel TextModel
| (ViT Encoder + | (Transformer +
| Attention Pooling) | Pooling)
v v
image_embeds text_embeds
| (batch, hidden_size) | (batch, hidden_size)
| |
+------------+ +-------------------+
| |
v v
logits = image @ text.T * temperature
|
v
logits_per_image (I, T)
logits_per_text (T, I)
|
v
Sigmoid Loss (per-element)
与 CLIP 的关键差异
| 维度 | CLIP | Siglip2 |
|---|---|---|
| 固定分辨率 | 是 (224x224 或 336x336) | 否 (naflex: 灵活分辨率) |
| 空间信息 | 隐式 (固定 patch grid) | 显式 (spatial_shapes tensor) |
| Patch mask | 无 | pixel_attention_mask |
| Loss | Softmax Cross-Entropy | Sigmoid Loss |
| Attention Pooling Head | 标准线性投影 | MultiheadAttentionPoolingHead |
| Lowercasing | 是 | 是 |
| 模型名 | openai/clip-vit-base-patch32 | google/siglip2-base-patch16-naflex |
关键算法实现细节
1. 图像 Patch 化与输出 Shape
Siglip2 图像处理的核心公式:
给定图像 I ∈ R^{H x W x 3}
patch_size = 16
num_patches = floor(H / 16) * floor(W / 16) (最多 256)
每个 patch flatten 为 16 * 16 * 3 = 768 维向量
输出 shape: (num_patches, 768)
若 num_patches < max_num_patches,padding 到 (256, 768)
测试中验证:expected_output_image_shape = (max_num_patches, patch_size * patch_size * num_channels) = (256, 768)
2. spatial_shapes 与 pixel_attention_mask 的配合
| |
3. Sigmoid Loss (对比 Softmax CE)
Siglip2 的核心算法创新在于 Loss 函数。虽然测试文件不直接测试 loss 计算,但从 logits_per_image (I, T) 和 logits_per_text (T, I) 的输出 shape 可以推断:
# CLIP: Softmax CE Loss
# loss_img = CE(softmax(logits_per_image, dim=1), targets)
# loss_txt = CE(softmax(logits_per_text, dim=1), targets)
# Siglip2: Sigmoid Loss
# 对 logits 矩阵的每个 (i,j) 元素:
# target = 1 if i == j else -1
# loss = -log(sigmoid(target * logits[i,j]))
# 优点:不再受 batch size 约束,可利用大量负样本,训练更稳定
logits_per_image 和 logits_per_text 互为转置,两者同时输出是为了对称性。
4. MultiheadAttentionPoolingHead 的卸载问题
在 Siglip2VisionModelTest 中:
| |
这个 Head 使用多头注意力来聚合 patch 序列为单个向量表示(替代 CLIP 的简单 mean/CLS pooling)。由于内部使用了 nn.MultiheadAttention,在 device_map="auto" / cpu_offload 场景下可能出现模块卸载不正确的问题。解决方案是在 dispatch_model 时预加载该模块。
5. Gradient Checkpointing 兼容性
| |
在 Siglip2ForImageClassification 中启用 gradient checkpointing 时,某层(可能是 Vision Transformer 的注意力或 MLP)的梯度未正确回传。这可能是由于:
- 自定义 attention 实现与 checkpoint 的
use_reentrant=False不兼容 MultiheadAttentionPoolingHead在中间激活值丢弃后无法正确重建
标记为 xfail 表示这是已知问题但暂不修复。
测试信息的业务价值
对模型用户
| 问题 | 答案(从测试推断) |
|---|---|
| 支持哪些分辨率? | naflex 变体支持任意分辨率(max 256 patches);224 变体固定 224x224 |
| Tokenizer 如何处理大小写? | 默认 lowercase,大小写输入等价 |
| 支持 Flash Attention 吗? | 支持,且与 eager 模式输出一致(atol=4e-2) |
| 能用 gradient checkpointing 吗? | Vision encoder 训练可以,分类头有 bug |
| 能输出 attention 权重吗? | 当前不支持 |
| 图像预处理流程? | resize(BILINEAR) → rescale(1/255) → normalize(mean=0.5, std=0.5) → patchify |
对贡献者
- 修改 vision/text model 时:必须通过
Siglip2ModelTesterMixin中的 SDPA/Flash Attn 测试 - 修改 image processor 时:
max_num_patches=256和patch_size=16是硬约束 - 修改 tokenizer 时:lowercasing 行为不能变更
- 修改 config 序列化时:
test_load_vision_text_config必须通过
附录:SDPA 与 Flash Attention 算法详解
概述
SDPA 和 Flash Attention 都是 Transformer 中 Multi-Head Attention 的高效实现算法。它们计算相同的数学结果,但在内存使用和计算速度上有巨大差异。Siglip2 测试文件中的 Siglip2ModelTesterMixin 专门验证模型在 eager、sdpa、flash_attention_2 三种后端下行为一致。
SDPA (Scaled Dot-Product Attention)
本质:PyTorch 2.0 内置的融合注意力算子 torch.nn.functional.scaled_dot_product_attention。
它不是新算法,而是工程优化——将原本分散的多个操作(QK^T、softmax、乘以 V)融合成一个 CUDA kernel,避免中间矩阵反复在 GPU 显存和计算单元之间搬运。
传统实现(多个 kernel 调用):
scores = Q @ K.T # kernel 1: 写回 HBM
scores = scores / sqrt(d) # kernel 2: 读 -> 算 -> 写
attn = softmax(scores) # kernel 3: 读 -> 算 -> 写
output = attn @ V # kernel 4: 读 -> 算 -> 写
SDPA(融合 kernel):
output = sdpa(Q, K, V) # 一次 kernel 调用,中间结果不离开寄存器/SRAM
关键特性:PyTorch 的 SDPA 会根据输入自动选择最优后端:
| 优先级 | 后端 | 条件 |
|---|---|---|
| 1 | Flash Attention 2 | CUDA 可用,fp16/bf16,无自定义 mask,无 attn_mask dtype 不兼容 |
| 2 | Memory Efficient Attention | xformers 的 cutlass 实现,比 Flash Attn 慢但比朴素实现快 |
| 3 | 朴素实现 | 兜底,标准 math 实现 |
Flash Attention
本质:Stanford Tri Dao 提出的 I/O 感知精确注意力算法 (2022, FA1; 2023, FA2)。
核心洞察:Attention 的瓶颈不是计算量 (FLOPs),而是显存带宽。一个 (N, N) 的 attention 矩阵,在长序列时需要反复在 HBM (High Bandwidth Memory, 即 GPU 显存) 和计算单元之间搬运,严重拖慢速度。
HBM (显存): 大容量 (~80GB), 慢带宽 (~1.5 TB/s)
SRAM (片上): 小容量 (~20MB), 快带宽 (~19 TB/s)
传统做法:中间结果都在 HBM 上来回搬运 → 带宽是瓶颈
Flash Attention:中间结果全在 SRAM 上处理 → 省掉了大部分 HBM 读写
核心技巧一:平铺 (Tiling)
将 Q, K, V 分成小块 (tile),逐块加载到片上 SRAM 计算:
+-----+-----+-----+
| Q_1 | K_1 | V_1 | Block 1: 只计算这一块
+-----+-----+-----+ 在 SRAM 内完成 QK^T -> softmax -> xV
| Q_2 | K_2 | V_2 | Block 2: 结果累加到输出
+-----+-----+-----+
每一步:
1. 从 HBM 加载 Q_block, K_block, V_block 到 SRAM
2. 在 SRAM 内计算该块的 attention(不写回 HBM)
3. 只把最终结果写回 HBM
关键效果:完整的 NxN attention 矩阵永远不会出现在 HBM 中
数值案例:假设 N=128K,N x N = 16B 元素,fp16 下约 32GB。传统实现需要这 32GB 矩阵完整存在于 HBM 中。Flash Attention 将其分割成小块后逐块处理,HBM 上只有最终输出 (N, d)。
核心技巧二:Online Softmax(在线 Softmax)
分块计算 softmax 时,需要知道全局最大值来做数值稳定。传统做法是先扫一遍找最大值,再算 softmax(两次遍历)。Flash Attention 的在线 softmax 通过 running statistics 只需一次遍历:
传统 Stable Softmax:
m = max(x_i) # 第一次遍历:找最大值
s = sum(exp(x_i - m)) # 第二次遍历:算分母
softmax(x_i) = exp(x_i - m) / s
Online Softmax (Flash Attention 用):
对于每个新块:
m_new = max(m_old, max(当前块))
旧结果 *= exp(m_old - m_new) # rescale:修正之前块的结果
新贡献 = 当前块 * exp(当前块值 - m_new)
结果 += 新贡献
只需一次遍历,且空间复杂度 O(1)
Flash Attention 2 改进 (2023)
| 改进 | 说明 |
|---|---|
| 减少非矩阵乘法操作 | FA1 中 non-matmul FLOPs 占比高,FA2 通过重排计算顺序降低 |
| 并行化策略调整 | 分 sequence length 维度而非 batch/head 维度,提高 GPU 占用率 |
| 前向推理速度 | 比 FA1 快约 2x |
三种实现的对比
| 维度 | 朴素 Attention | SDPA (auto) | Flash Attention 2 |
|---|---|---|---|
| 显存复杂度 | O(N^2) | O(N) | O(N) |
| 中间矩阵存放 | HBM (显存) | 寄存器 / 共享内存 | 片上 SRAM |
| SRAM 利用率 | 极低 | 中等 | 极高 (~19 TB/s) |
| N=128K 时的中间矩阵 | ~32GB (可能 OOM) | N/A (融合掉) | N/A (从不落地) |
| PyTorch 调用 | 手动实现 | F.scaled_dot_product_attention() | SDPA 自动选或指定 attn_implementation="flash_attention_2" |
| 精度 | fp32 全精度 | 与后端一致 | fp16/bf16 |
| 自定义 mask 支持 | 完全支持 | 受限(取决于后端) | 有限 |
在 Siglip2 测试中的体现
test_sdpa_can_dispatch_composite_models
验证 Siglip2 的双塔结构(Vision + Text)能各自独立选择 SDPA 后端,save/load 后 _attn_implementation 属性正确恢复。关键校验逻辑:
| |
这确保了 Siglip2 的双塔各自可以灵活切换注意力后端而互不影响。
test_flash_attn_2_inference_equivalence
验证 Flash Attention 2 和 eager(朴素实现)产生数值等价的输出。核心代码:
| |
容差为什么是 atol=4e-2?
不同注意力实现的浮点累加顺序不同:
- softmax 涉及
exp求和,结果对累加顺序敏感 - Flash Attention 中 tiling 改变了累加顺序
- 这些微观差异在 fp16 下累积,但宏观语义等价
padding 区域的特殊处理:
| |
Flash Attention 对 mask 的处理与 eager 不同:padding 位置的 softmax 计算可能有微小差异。测试通过乘以 pixel_attention_mask 排除这些位置,确保只在有效 patch 上比较。
训练模式验证
| |
这确保 Flash Attention 的 dropout 模式(random mask pattern)与 eager 的语义一致,不会在训练时产生 NaN 或异常。
一句话总结
SDPA 是 PyTorch 的"自动选最优"融合接口——它不是一个算法,而是一个智能调度器。Flash Attention 是具体的"把显存带宽省到极致"的算法——通过 tiling + online softmax,让完整的 NxN attention 矩阵永远不出现在显存中。Siglip2 测试确保两种(以及 eager 朴素实现)都能正常工作且语义等价。
附录二:四文件变量全量词典
按文件 -> 类 -> 变量的层级,逐一解释每个变量的含义、默认值选择原因、对应模型组件的角色。
文件一:test_image_processing_siglip2.py 变量
Siglip2ImageProcessingTester.__init__
| 变量 | 默认值 | 类型 | 含义与用途 |
|---|---|---|---|
parent | (必传) | unittest.TestCase | 指向调用此 Tester 的测试用例实例,用于 self.parent.assertEqual(...) 等断言 |
batch_size | 7 | int | 每次测试生成的图像 batch 大小。值 7 是质数,避免对称 batch size 带来的虚假通过 |
num_channels | 3 | int | 图像通道数,RGB = 3。Siglip2 只接受 RGB 输入,4 通道测试被显式跳过 |
image_size | 18 | int | 测试用图像的基础尺寸(像素)。18 不是 16 的整数倍,用于验证 processor 对非对齐尺寸的处理 |
min_resolution | 30 | int | 随机生成测试图像的最小边长。30 < 2 * 16 = 32,用于验证极小图的处理 |
max_resolution | 400 | int | 随机生成测试图像的最大边长。400 > 16 * 16 = 256 (max patches 对应 4096x4096),覆盖边界场景 |
do_resize | True | bool | 是否启用 resize 步骤。控制 pipeline 中的第一步开关 |
size | {"height": 18, "width": 18} | dict | resize 的目标尺寸。当 do_resize=True 时生效,将图像缩放至此尺寸 |
do_rescale | True | bool | 是否启用像素值重缩放。控制 pipeline 中的第二步开关 |
rescale_factor | 1 / 255 | float | 重缩放因子。将像素值从 [0, 255] 除以 255 映射到 [0, 1]。来自 CLIP 的标准预处理 |
do_normalize | True | bool | 是否启用归一化。控制 pipeline 中的第三步开关 |
image_mean | [0.5, 0.5, 0.5] | list[float] | 各通道的均值,用于 (x - mean) / std。将 [0, 1] 中心化到 [-1, 1] |
image_std | [0.5, 0.5, 0.5] | list[float] | 各通道的标准差。与 mean=[0.5, 0.5, 0.5] 配合,将 [0,1] -> [-1,1] |
resample | Image.Resampling.BILINEAR | PIL enum | resize 时的插值算法。BILINEAR 是 CV 领域标准选择,平衡速度与质量 |
patch_size | 16 | int | ViT 的 patch 边长。将图像划分为 16x16 的小块。值为 16 是 ViT 论文的经典选择(1/14, 1/16 是两种主流) |
max_num_patches | 256 | int | 每张图像最多保留的 patch 数量。这是 Siglip2 Naflex 的核心参数:一张图最多切 256 个 patch。256 个 16x16 的 patch 最多覆盖 4096 个像素维度(如 256x256 需 16x16=256 patch) |
Siglip2ImageProcessingTester 方法参数
| 变量 | 默认值 | 含义与用途 |
|---|---|---|
equal_resolution (in prepare_image_inputs) | False | 是否强制所有测试图像使用相同分辨率。False 模拟真实场景中不同尺寸/宽高比的图像 |
numpify (in prepare_image_inputs) | False | 是否将输出转为 NumPy 数组。控制数据格式切换 |
torchify (in prepare_image_inputs) | False | 是否将输出转为 PyTorch Tensor。与 numpify 互斥 |
Siglip2ImageProcessingTest 类级别变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
self.image_processor_tester | Siglip2ImageProcessingTester(self) | 测试数据工厂实例,在 setUp() 中创建,每个测试方法前重新初始化 |
self.image_processor_dict | (property) | 委托给 image_processor_tester.prepare_image_processor_dict() 的属性,返回完整的 image processor 配置字典 |
文件二:test_modeling_siglip2.py 变量
Siglip2ModelTesterMixin 内部变量
| 变量 | 默认值 | 出现位置 | 含义与用途 |
|---|---|---|---|
dtype | torch.float16 | test_flash_attn_2_inference_equivalence | Flash Attention 限制必须使用 fp16/bf16,不可用 fp32 |
key | 动态选择 | test_flash_attn_2_inference_equivalence | 选择比较哪个输出 key。优先级:logits > logits_per_image > last_hidden_state。根据模型类型自动适配 |
atol | 4e-2 | test_flash_attn_2_inference_equivalence | 绝对容差。值 0.04 较宽松,因为 flash attn 与 eager 的浮点累加顺序不同,在 fp16 下误差累积 |
rtol | 4e-2 | test_flash_attn_2_inference_equivalence | 相对容差。与 atol 配合使用,确保语义等价而非逐位精确 |
tmpdirname | tempfile.TemporaryDirectory() | 多处 | 临时目录,用于 save/load 测试后自动清理 |
Siglip2VisionModelTester.__init__
| 变量 | 默认值 | 类型 | 含义与用途 |
|---|---|---|---|
parent | (必传) | unittest.TestCase | 指向调用此 Tester 的测试用例实例 |
batch_size | 12 | int | Vision 模型测试的 batch 大小。12 是 3 和 4 的最小公倍数,方便验证 attention head 的整除性 |
num_patches | 16 | int | config 中声明的 patch 数量占位。注意:实际序列长度由 image_num_patches 决定,此值用于 config 初始化而非输入生成 |
image_num_patches | 24 | int | 实际的序列长度(= seq_length)。Vision 模型接收的 patch 数量。24 方便构造多种 (height, width) 组合:1x24, 2x12, 3x8, 4x6 等 |
patch_size | 2 | int | 测试用 patch 边长。仅 2(而非真实模型的 16),因为 patch_dim = 3 * 2 * 2 = 12,极小的向量便于快速测试 |
num_channels | 3 | int | 图像通道数,固定为 RGB=3 |
is_training | True | bool | 模型是否处于训练模式。影响 dropout 和 batch norm 行为 |
hidden_size | 64 | int | Transformer 隐藏层维度。仅为真实模型 768 的 1/12,大幅降低测试的计算开销 |
num_hidden_layers | 2 | int | Transformer 层数。仅为真实模型的 2/12,最小可验证深度堆叠行为的层数 |
num_attention_heads | 4 | int | 注意力头数。4 个头确保 hidden_size // num_heads = 64 // 4 = 16 可整除 |
intermediate_size | 37 | int | FFN 中间层维度。37 是质数,确保不因特殊数值巧合通过测试 |
dropout | 0.1 | float | 全连接层 dropout 比率。标准 Transformer 配置 |
attention_dropout | 0.1 | float | 注意力权重 dropout 比率。标准 Transformer 配置 |
initializer_range | 0.02 | float | 权重初始化的标准差。BERT/ViT 的经典值,源自 Xavier 初始化 |
scope | None | str or None | 变量作用域前缀(旧版 TF 遗留)。PyTorch 下无用,保持 API 兼容 |
seq_length | =image_num_patches | int | 模型接收的序列长度。等于 image_num_patches,是它的语义化别名 |
Siglip2VisionModelTester.prepare_config_and_inputs 局部变量
| 变量 | shape / 含义 | 用途 |
|---|---|---|
pixel_values | (batch_size, seq_length, patch_dim) | 已 patchify 的图像输入。每行是一个 flatten 的 patch 向量 |
pixel_attention_mask | (batch_size, seq_length) | 标记哪些 patch 有效 (1) 哪些是 padding (0)。由 spatial_shapes 决定 |
spatial_shapes | (batch_size, 2) | 每张图的 patch 网格高度和宽度。例如 (4, 6) 表示 4 行 6 列共 24 个 patch |
spatial_shapes的生成逻辑:枚举所有(h, w)组合满足h * w <= seq_length(24),每个 batch 样本随机分配一个组合。这确保测试覆盖不同宽高比(1x24, 2x12, 3x8, 4x6, 6x4, 8x3, 12x2, 24x1)。
Siglip2VisionModelTest 类级别变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
all_model_classes | (Siglip2VisionModel,) | 基类 Mixin 据此知道要测试哪些模型类。这里仅测试 Vision 塔 |
additional_model_inputs | ["pixel_attention_mask", "spatial_shapes"] | 告诉基类:你的 forward 除了 pixel_values 还接受这两个额外参数。基类的通用测试会根据此列表构造 inputs_dict |
test_resize_embeddings | False | 禁用 embeddings resize 测试。Vision Transformer 无 token embeddings,不需要 resize 功能 |
test_cpu_offload | False | 禁用 CPU 卸载测试。原因:MultiheadAttentionPoolingHead 在 device_map="auto" 时卸载异常,已知 bug 待修复 |
test_disk_offload_safetensors | False | 禁用磁盘卸载测试(safetensors 格式)。同上原因 |
test_disk_offload_bin | False | 禁用磁盘卸载测试(bin 格式)。同上原因 |
Siglip2TextModelTester.__init__
| 变量 | 默认值 | 类型 | 含义与用途 |
|---|---|---|---|
parent | (必传) | unittest.TestCase | 指向调用此 Tester 的测试用例实例 |
batch_size | 12 | int | Text 模型测试的 batch 大小。与 Vision 保持一致 |
seq_length | 7 | int | 文本序列长度。7 是质数且足够短,快速测试 padding/truncation 行为 |
is_training | True | bool | 模型是否处于训练模式 |
use_input_mask | True | bool | 是否生成 attention_mask。控制 random_attention_mask 的创建 |
use_labels | True | bool | 是否生成标签(用于 loss 计算)。Text 模型本身无 loss,此值在联合模型中生效 |
vocab_size | 99 | int | 词汇表大小(测试用)。远小于真实 ~32000,降低 embedding 矩阵尺寸 |
hidden_size | 64 | int | Transformer 隐藏层维度。与 Vision 保持一致 |
num_hidden_layers | 2 | int | Transformer 层数。与 Vision 保持一致 |
num_attention_heads | 4 | int | 注意力头数。64 / 4 = 16 可整除 |
intermediate_size | 37 | int | FFN 中间层维度。37 是质数,与 Vision 一致 |
dropout | 0.1 | float | 全连接层 dropout 比率 |
attention_dropout | 0.1 | float | 注意力权重 dropout 比率 |
max_position_embeddings | 512 | int | 最大位置编码数。定义文本塔的最长序列长度。512 是 CLIP 文本塔的标准值 |
initializer_range | 0.02 | float | 权重初始化标准差 |
scope | None | str or None | 变量作用域前缀(旧版 TF 遗留) |
Siglip2TextModelTester.prepare_config_and_inputs 局部变量
| 变量 | shape / 含义 | 用途 |
|---|---|---|
input_ids | (batch_size, seq_length) | 随机 token ID 序列。值域 [0, vocab_size) |
input_mask | (batch_size, seq_length) | Attention mask。每个样本随机截断到不同长度。rnd_start_indices 决定每个样本的有效 token 数:input_mask[b, :start] = 1, input_mask[b, start:] = 0 |
rnd_start_indices在[1, seq_length-1]区间均匀随机,使得 batch 内序列长度各不相同,模拟真实 batching 场景的 padding 需求。
Siglip2TextModelTest 类级别变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
all_model_classes | (Siglip2TextModel,) | 仅测试 Text 塔 |
test_resize_embeddings | False | 禁用 embeddings resize 测试。虽然文本模型有 embeddings,但 Siglip2 的联合训练模式下 resize 不适用 |
model_split_percents | [0.5, 0.8, 0.9] | 模型分割点比例。用于 device_map 测试:将模型按 50%、80%、90% 的比例分配到不同设备。覆盖浅层/深层分割场景 |
Siglip2ModelTester.__init__
| 变量 | 默认值 | 类型 | 含义与用途 |
|---|---|---|---|
parent | (必传) | unittest.TestCase | 指向调用此 Tester 的测试用例实例 |
text_kwargs | None (→ {}) | dict or None | 传递给 Siglip2TextModelTester 的参数覆盖。None 时使用全部默认值 |
vision_kwargs | None (→ {}) | dict or None | 传递给 Siglip2VisionModelTester 的参数覆盖。None 时使用全部默认值 |
is_training | True | bool | 联合模型的训练模式标志 |
Siglip2ModelTest 类级别变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
all_model_classes | (Siglip2Model,) | 测试联合模型(Vision + Text) |
pipeline_model_mapping | {"feature-extraction": Siglip2Model} | 告诉 Pipeline 测试框架:Siglip2Model 可被当作 feature-extraction pipeline 使用。图像/文本特征提取 |
additional_model_inputs | ["pixel_values", "pixel_attention_mask", "spatial_shapes"] | 联合模型的额外输入列表。注意不含 input_ids 和 attention_mask(那些是文本塔标准输入,基类自动处理) |
test_resize_embeddings | False | 联合模型不需要 resize |
test_attention_outputs | False | 关键:Siglip2 当前不支持 output_attentions=True。设为 False 跳过相关测试 |
test_cpu_offload | False | 与 Vision 塔相同原因:MultiheadAttentionPoolingHead 卸载 bug |
test_disk_offload_safetensors | False | 同上 |
test_disk_offload_bin | False | 同上 |
_is_composite | True | 关键:声明这是复合模型(包含子模型)。触发基类 ModelTesterMixin 中的复合模型特殊测试逻辑。如:test_sdpa_can_dispatch_composite_models 会检查 vision 和 text 子模型的注意力实现 |
Siglip2ForImageClassificationModelTest 类级别变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
all_model_classes | (Siglip2ForImageClassification,) | 测试图像分类头 |
pipeline_model_mapping | {"image-classification": Siglip2ForImageClassification} | 可作为 image-classification pipeline 使用 |
additional_model_inputs | ["pixel_values", "pixel_attention_mask", "spatial_shapes"] | 仅含视觉输入(无文本) |
test_resize_embeddings | False | 不需要 resize |
test_attention_outputs | False | 不支持 attention 输出 |
test_cpu_offload | False | 同 Vision 塔原因 |
test_disk_offload_safetensors | False | 同上 |
test_disk_offload_bin | False | 同上 |
_is_composite | True | 分类头包含 Vision 子模型,属于复合模型 |
prepare_images() 函数局部变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
shapes | [(224, 224), (1024, 1024), (224, 1024)] | 三张测试图像的尺寸。覆盖正方形(1:1)、大正方形、长方形(高瘦型)。224=16x14 是 CLIP 标准尺寸,1024=16x64 是 Naflex 支持的大尺寸 |
height / width | 遍历 shapes | 当前图像的尺寸 |
image | Image.new("RGB", (width, height), color="red") | 创建纯红色背景的 PIL 图像 |
draw | ImageDraw.Draw(image) | PIL 绘图上下文 |
center_x / center_y | width // 2 / height // 2 | 圆心坐标 = 图像中心 |
radius | min(center_x, center_y) // 8 * 7 | 圆半径 = 短边的 7/8。确保圆完全在图像内,不同尺寸下比例一致 |
fill / outline / width | "blue" / "green" / image.width // 20 | 椭圆填充色(蓝)、边框色(绿)、边框粗细。生成 红底 + 蓝圆 + 绿边 的标准测试图 |
Siglip2ModelIntegrationTest.test_inference 局部变量
| 变量 | 值/类型 | 含义与用途 |
|---|---|---|
model_name | "google/siglip2-base-patch16-naflex" | 预训练模型的 HuggingFace Hub ID。使用 naflex 变体而非固定尺寸版本 |
model | Siglip2Model 实例 | 加载的预训练模型,移至 torch_device |
processor | Siglip2Processor 实例 | 同时处理图像和文本的联合 processor |
images | list[Image] (3 张) | prepare_images() 生成的测试图 |
text | list[str] (7 条) | 测试文本。语义梯度设计:精准描述 > 部分描述 > 模糊描述 > 错误描述 |
inputs | dict[str, Tensor] | processor 输出的编码后输入。return_tensors="pt" 指定 PyTorch 格式 |
outputs | Siglip2ModelOutput | 模型前向传播输出。含 logits_per_image 和 logits_per_text |
logits_per_image | (3, 7) tensor | 每张图像与 7 条文本的相似度得分。每行是一个图像对所有文本的 logits |
logits_per_text | (7, 3) tensor | 每条文本与 3 张图像的相似度得分。每行是一个文本对所有图像的 logits |
expected_logits_per_texts | Expectations 对象 | 平台相关的期望 logits 值。键 ("cuda", None) 匹配所有 CUDA 设备,("rocm", (9, 5)) 匹配 ROCm 特定版本,("xpu", 3) 匹配 Intel GPU |
EXPECTED_LOGITS_PER_TEXT | Tensor (7, 3) | 从 Expectations 提取的当前平台期望值 |
rtol / atol | 1e-3 / 1e-3 | 集成测试的容差。比 flash attn 测试(4e-2)严格 40 倍,因为 eager 模式的结果应高度可复现 |
期望 logits 矩阵的语义解读
EXPECTED_LOGITS_PER_TEXT shape 为 (7, 3),7 条文本对 3 张图像:
| 文本 (行) \ 图像 (列) | img0 (224x224 方) | img1 (1024x1024 大) | img2 (224x1024 高) | 解读 |
|---|---|---|---|---|
"circle" | 1.02 | -0.03 | -1.45 | 方形图匹配最高(简单描述偏好方形图) |
"ellipsoid" | -4.54 | -6.23 | -1.57 | 全部低分,因为画的是正圆而非椭圆 |
"blue circle on red background" | 4.18 | 5.04 | 3.52 | 精确描述,全部高分。大图略高(更多细节) |
"blue circle with green border..." | 9.43 | 10.19 | 6.34 | 最精确描述,最高分。绿边是区分性特征 |
"green circle on red background" | 2.44 | 3.11 | 4.55 | 颜色错误(绿而非蓝),分数下降 |
"a dog" | -12.32 | -13.74 | -13.46 | 完全无关,极低分 |
"a blue dog with a green border..." | 1.15 | 1.17 | -1.96 | 颜色对但物体错,低分 |
文件三:test_tokenization_siglip2.py 变量
Siglip2TokenizerTest 类级别变量
| 变量 | 值 | 含义与用途 |
|---|---|---|
from_pretrained_id | "google/siglip2-base-patch16-224" | 加载此预训练模型的 tokenizer。注意:tokenizer 测试用 patch16-224(固定 224 尺寸),模型测试用 patch16-naflex(灵活尺寸)。两者 tokenizer 完全一致 |
Siglip2TokenizerTest.test_tokenizer 局部变量
| 变量 | 值/类型 | 含义与用途 |
|---|---|---|
tokenizer | Siglip2Tokenizer 实例 | 从 HuggingFace Hub 加载的预训练 tokenizer |
texts_uc | list[str] (5 条) | 大写 / 混合大小写测试文本。覆盖:全大写、多余空格、特殊字符(带变音符号的 u)、地名、混合大小写 + 数字 |
texts_lc | list[str] (5 条) | texts_uc 的 .lower() 版本。与 texts_uc 一一对应 |
enc_uc / enc_lc | BatchEncoding | 单条编码结果。验证 enc_uc["input_ids"] == enc_lc["input_ids"],即大小写无关 |
batch_uc / batch_lc | BatchEncoding | 批量编码结果。验证批量路径与单条路径行为一致 |
max_len | 64 | padding 的目标长度。64 远大于 5 条测试文本的自然 token 数,确保所有序列都经历 padding 而非 truncation |
padded | BatchEncoding | padding="max_length" + truncation=True + max_length=64 的编码结果。验证每条序列长度恰好为 64 |
tmpdir | tempfile.TemporaryDirectory() | 保存 tokenizer 的临时目录 |
tokenizer_reloaded | Siglip2Tokenizer 实例 | 从 tmpdir 重新加载的 tokenizer。验证 roundtrip 不变性 |
batch_uc_2 / batch_lc_2 | BatchEncoding | 重载后 tokenizer 的编码结果。与原始结果逐元素比较 |
padded_2 | BatchEncoding | 重载后 tokenizer 的 padded 编码结果。验证 padding 行为不变 |
文件四:__init__.py 变量
无变量。空文件仅作为 Python 包标记。
变量间的依赖关系
Image Processor 变量:
patch_size=16 ────> expected_output_image_shape = (max_num_patches, 16*16*3)
max_num_patches=256 ──┘ = (256, 768)
rescale_factor=1/255 ──> pixel_values in [0, 1]
image_mean=[0.5,0.5,0.5] + image_std=[0.5,0.5,0.5] ──> pixel_values in [-1, 1]
Vision Model 变量:
patch_size=2 (test) ──> patch_dim = 3 * 2 * 2 = 12
image_num_patches=24 ──> seq_length = 24, spatial_shapes 可构造 8 种 (h,w) 组合
hidden_size=64 ──> pooler_output.shape = (batch, 64)
num_attention_heads=4 ──> head_dim = 64 / 4 = 16
intermediate_size=37 ──> FFN 维度 = 37 (质数, 无巧合通过)
Text Model 变量:
vocab_size=99 ──> embedding 表尺寸 (99, 64)
seq_length=7 ──> 短序列, 快速测试
max_position_embeddings=512 ──> 最大文本长度上限
hidden_size=64 ──> 与 Vision 塔对齐 (pooler_output 维度一致)
model_split_percents=[0.5, 0.8, 0.9] ──> device_map 测试的三种分割策略
Combined Model 变量:
_is_composite=True ──> 触发复合模型特殊测试
test_attention_outputs=False ──> 跳过 attention 输出测试 (功能未实现)
test_cpu_offload=False ──> 跳过卸载测试 (MultiheadAttentionPoolingHead bug)
Tokenizer 变量:
from_pretrained_id="...patch16-224" ──> 使用固定尺寸模型的 tokenizer
max_len=64 ──> 远超测试文本长度, 纯 padding 场景
Integration Test 变量:
shapes = [(224,224), (1024,1024), (224,1024)] ──> 覆盖 1:1 和不同宽高比
model_name="...naflex" ──> 使用灵活分辨率模型
atol=1e-3 (严格) vs model test atol=4e-2 (宽松) ──> 集成测试是 eager 模式, 误差应更小