首页
/ Transformers 图像处理器详解:后端化架构、backend 选择与图像预处理全流程

Transformers 图像处理器详解:后端化架构、backend 选择与图像预处理全流程

2026-09-06 17:37:12作者:翟江哲Frasier

本文以 Transformers 官方文档 docs/source/en/main_classes/image_processor.md 为主线,深入讲解图像处理器(Image Processor)的职责、基于后端(backend)的类层次架构、AutoImageProcessorbackend 选择机制、torchvision 后端的 device 加速用法,并结合 image_processing_backends.pyimage_processing_utils.pyimage_processing_auto.py 的源码实现,完整还原从 __call__BatchFeature 输出的预处理调用链,帮助你在实际项目中正确选择后端、配置参数并定制属于自己的图像处理器。

图像处理器是做什么的

图像处理器负责视觉模型输入侧的三件事:

  • 加载图像(可选):接受 PIL Image、NumPy 数组、torch Tensor,甚至 URL/文件路径;
  • 准备模型输入特征:执行 resize、center crop、rescale、normalize、padding 等变换,并把结果转换为 PyTorch 或 NumPy 张量;
  • 模型专属后处理:例如把 logits 转成分割掩码(segmentation masks)等模型特定的输出处理。

与 tokenizer 之于文本、feature extractor 之于音频相对应,图像处理器是视觉与多模态模型推理/训练管线中不可缺少的"数据入口"。

后端化架构:从单一实现到可插拔后端

当前版本中,图像处理器采用基于后端的类继承架构。文档给出的类层次如下:

两种后端暴露完全相同的 API,你可以用 backend 属性查看已加载的处理器实际使用哪个后端:

processor.backend  # "torchvision" 或 "pil"

这一点在源码中体现得很直接:TorchvisionBackendbackend 属性返回 "torchvision"PilBackend 返回 "pil"。此外,文件末尾还保留了兼容别名 BaseImageProcessorFast = TorchvisionBackendsrc/transformers/image_processing_backends.py#L664-L665),方便旧代码中引用的 *Fast 命名平滑迁移。

BaseImageProcessor 的 docstring 中给出了完整的架构图景:

BaseImageProcessor (this class)
├── TorchvisionBackend    (GPU-accelerated, torch.Tensor)
│   └── ModelImageProcessor (e.g. LlavaNextImageProcessor)
└── PilBackend            (portable CPU, np.ndarray)
    └── ModelImageProcessorPil (e.g. CLIPImageProcessorPil)

预处理流程则为:

__call__() → preprocess() → _preprocess_image_like_inputs()
                                 ├── _prepare_image_like_inputs()  (逐图调用 process_image)
                                 └── _preprocess()                  (批量操作: resize/crop/pad/normalize)

两个关键分工(见 BaseImageProcessor 定义):

  • process_image:由后端实现,把单张原始输入(PIL/NumPy/Tensor)转换为后端工作格式,处理 RGB 转换与通道重排;
  • _preprocess:由后端实现,执行真正的批量处理并返回 BatchFeature

无论哪个后端,图像在内部处理时统一采用 channels-first(C, H, W)布局;torchvision 后端得到 torch.Tensor,PIL 后端得到 np.ndarray

用 AutoImageProcessor 选择后端

通过 AutoImageProcessor.from_pretrainedbackend 参数可以显式指定后端:

from transformers import AutoImageProcessor

# 默认:torchvision 可用则选 torchvision,否则用 pil
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50")

# 显式指定 torchvision
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50", backend="torchvision")

# 显式指定 PIL
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50", backend="pil")

默认的解析逻辑

后端选择的具体规则可以在 image_processing_auto.py_resolve_backend 函数中逐条印证:

  1. use_fast 已废弃:仍传入 use_fast=True/False 会收到告警,并被转换为 backend="torchvision"/"pil"源码)。新代码应直接使用 backend
  2. backend=None(默认)时的自动选择
    • 若处理器属于 DEFAULT_TO_PIL_BACKEND_IMAGE_PROCESSORS(即使用 Lanczos 插值的模型:Chameleon、Flava、Idefics3、SmolVLM),强制选择 pil
    • 否则,torchvision 已安装则选 torchvision,否则回退 pil
  3. 显式 backend 字符串:原样采用。

Lanczos 插值的特例与降级行为

使用 Lanczos 插值的少数模型(Chameleon、Flava、Idefics3、SmolVLM)是上述"例外":当 torchvision < 0.27 时默认走 PIL 后端。如果你在旧版 torchvision 上强制 backend="torchvision",会发生插值降级——torchvision 对张量的 Lanczos 支持从 0.27 才提供,且仅在 CPU 上可用。这一点在 TorchvisionBackend.resize 中可以直接看到:当请求 LANCZOS 且(torchvision < 0.27 或张量在 GPU 上)时,会发出一次 warning_once回退到 BICUBIC 近似:

if interpolation == tvF.InterpolationMode.LANCZOS and (
    not is_torchvision_greater_or_equal("0.27") or image.device.type != "cpu"
):
    logger.warning_once(
        "LANCZOS resample requires torchvision >= 0.27 and processing on CPU; ..."
    )
    interpolation = tvF.InterpolationMode.BICUBIC

如果你需要与原始模型完全一致的数值,升级 torchvision 并把张量放到 CPU 上 resize,或干脆改用 PIL 后端。

后端缺失时的回退

AutoImageProcessor 内部通过 _load_class_with_fallback 加载类:先尝试请求的后端,若该类不可用(依赖缺失时表现为 DummyObject),则依次尝试另一个标准后端并给出一次性告警 Requested {backend} backend is not available. Falling back to {b} backend.。若所有候选都无法导入,错误信息会列出各后端对应的类名与缺失的可选依赖(torchvision / Pillow),提示你安装依赖或换一个可用后端(源码)。

torchvision 后端:用 device 参数在 GPU 上处理

使用 torchvision 后端时,可以在调用时传 device 参数指定处理所在设备。默认规则是:输入是张量时在与输入相同的设备上处理,否则在 CPU 上处理。文档给出的示例:

import torch
from torchvision.io import read_image
from transformers import DetrImageProcessor

device = torch.accelerator.current_accelerator().type if torch.accelerator.is_available() else "cpu"

images = read_image("image.jpg")
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
images_processed = processor(images, return_tensors="pt", device=device)

其作用点在 TorchvisionBackend.process_image:单图转换完成后,若 device is not Noneimage.to(device),让后续的 resize、pad 等批量操作直接在目标设备上执行,避免"CPU 预处理再搬运"的往返开销。

官方文档还引用了 DETR 与 RT-DETR 在 AWS EC2 g5.2xlarge 实例(NVIDIA A10G GPU)上对 torchvision 与 PIL 两后端的基准测试,展示预处理提速如何传导到整体推理时间。从 TorchvisionBackend._preprocess 的实现也能看出提速来源:

  • 按形状分组批量处理group_images_by_shape 把相同尺寸的图像堆叠成批次,resize、crop、normalize 均按 batch 张量执行,而不是逐张循环;
  • rescale 与 normalize 融合rescale_and_normalize 借助带 lru_cache_fuse_mean_std_and_rescale_factor,把 image * (1/255)(x - mean)/std 两步合并为一次归一化(mean/std 预先乘上 1/rescale_factor),减少一次全张量遍历;
  • 批量 padpad 同样按形状分组后用 tvF.pad 对整个 batch 张量填充,并可通过 return_mask 生成像素掩码(pixel_mask),供检测模型区分真实像素与填充区域;
  • torch.compile 兼容:针对 AMD ROCm 平台 uint8 张量在 dynamo 编译下的问题,_compile_friendly_resize 会临时转 float 做 resize 再量化回 uint8。

对比之下,PilBackend._preprocess 是朴素的逐图 NumPy 循环(resize → center crop → rescale → normalize → pad),胜在零额外依赖、可移植,适合需要与最初实现逐位对齐的场合。

关键参数速查

图像处理器接受的核心 kwargs(由各模型的 valid_kwargs,默认继承自 ImagesKwargs 校验)及典型默认值如下,可对照 BaseImageProcessor 的类级默认值与后端实现确认:

参数 作用 默认/说明
do_resize / size 是否缩放;size 支持 {height, width}{shortest_edge, longest_edge}{max_height, max_width} 三种键组合 size 会被 _standardize_kwargs 统一为标准 SizeDict源码
resample 插值方式,PILImageResamplingtvF.InterpolationMode 均可,两后端会自动互转 torchvision 后端缺省为 BILINEAR(源码
do_center_crop / crop_size 中心裁剪;裁剪目标大于原图时先 0 填充再裁剪(见 TorchvisionBackend.center_crop
do_rescale / rescale_factor 像素缩放,通常是 1/255 把 0–255 映射到 0–1 rescale_factor = 1/255类默认值
do_normalize / image_mean / image_std 归一化 (x - mean)/std 模型自行声明,如 DETR 用 IMAGENET 均值方差
do_pad / pad_size 填充到统一尺寸;不指定时填充到 batch 内最大高宽 检测模型通常开启
return_tensors 输出张量类型("pt"/"np" 等),由 BatchFeature 完成转换
device 仅 torchvision 后端:指定处理设备 默认输入同设备或 CPU

注意 size 的三种语义差异:{height, width}精确尺寸(不保比例){shortest_edge, longest_edge}{max_height, max_width}保持宽高比。这套规则在 TorchvisionBackend.resizePilBackend.resize 中是对称实现的。

实例剖析:DetrImageProcessor

以检测模型的 DetrImageProcessor 为例,可以看到一个典型的 torchvision 后端处理器是如何声明的:

class DetrImageProcessor(TorchvisionBackend):
    valid_kwargs = DetrImageProcessorKwargs
    resample = PILImageResampling.BILINEAR
    image_mean = IMAGENET_DEFAULT_MEAN
    image_std = IMAGENET_DEFAULT_STD
    format = AnnotationFormat.COCO_DETECTION
    do_resize = True
    do_rescale = True
    do_normalize = True
    do_pad = True
    size = {"shortest_edge": 800, "longest_edge": 1333}
    default_to_square = False
    model_input_names = ["pixel_values", "pixel_mask"]

几个值得注意的设计:

  • 类属性即默认参数:preprocess 会用实例属性补齐用户未显式传入的 kwargs(preprocess 实现),因此 __init__ 与调用时的参数都能覆盖这些默认值;
  • DETR 用 {shortest_edge: 800, longest_edge: 1333} 保比例缩放,并覆写 resize 先算出目标 (height, width) 再委托后端执行;do_pad=True 则会把 batch 内图像填充到统一尺寸并返回 pixel_mask(对应 model_input_names 中的第二项);
  • 它还提供 prepare_annotation / resize_annotation 等模型专属方法,把 COCO 格式标注转换为模型可用的 dict 并随图像同步缩放——这就是文档所说"模型专属后处理"的一部分。

ImageProcessingMixin:加载与保存

所有图像处理器共享 ImageProcessingMixin 提供的 Hub 交互能力,文档对此专门做了 autodoc:

from_pretrained 的关键参数(docstring):

  • pretrained_model_name_or_path:Hub 模型 id、保存目录、或 preprocessor_config.json 文件路径;
  • cache_dir / force_download / local_files_only:缓存与下载控制,离线模式下自动强制 local_files_only=True
  • token:私有仓库需传 token(token=True 时使用 hf auth login 存储的凭据);
  • revision:分支/tag/commit id,测试 PR 时可传 revision="refs/pr/<pr_number>"
  • 其余 kwargs:键名是处理器属性的会覆盖加载值return_unused_kwargs=True 时返回未使用 kwargs 元组。

save_pretrained实现)把处理器的 to_dict() 结果写入 preprocessor_config.jsonIMAGE_PROCESSOR_NAME),支持 push_to_hub=True 直接推送到 Hub。序列化时 BaseImageProcessor.to_dict 会过滤与类默认值重复的 None 值,保持配置文件精简。

PilBackend 在保存时还有一个细节:to_dict 会剥掉类名中的 Pil 后缀,使配置文件与后端无关、可被两种后端共用。

BatchFeature:统一的输出容器

处理器 __call__/preprocess 的返回值是 BatchFeature——一个字典子类,data 中存放 pixel_valuespixel_mask 等键值,并可在构造时按 tensor_type(即 return_tensors)把列表统一转换为 PyTorch/NumPy 张量。两后端的 _preprocess 最终都返回 BatchFeature(data={"pixel_values": ...}, tensor_type=return_tensors)torchvisionPIL),下游模型/Trainer/Pipeline 因此可以无差别消费。

自定义处理器:在哪个层面扩展

BaseImageProcessor 的 docstring(src/transformers/image_processing_utils.py#L60-L187)给出了四个层次的扩展路径,均沿用官方示例风格:

  1. 标准操作直接复用后端:只需继承后端并声明类属性(resamplesizedo_resizedo_rescaledo_normalize 等),后端内置的 _preprocess 自动完成流水线;
  2. 自定义批量逻辑:覆写 _preprocess。它收到的图像已是后端格式且 channels-first,推荐按形状分组做批量操作(docstring 示例用 group_images_by_shape + 逐组 resize/normalize + reorder_images 还原顺序);
  3. 多类图像输入(如图像 + 分割掩码):覆写 _preprocess_image_like_inputs,分别 _prepare_image_like_inputs 后写入 BatchFeature 的不同键;
  4. 自定义参数:定义 ImagesKwargs 子类作为 valid_kwargs,即可让新参数参与类型校验与默认值合并(validate_typed_dict,见 preprocess)。

另外,_standardize_kwargs 允许子类在参数校验前做格式归一(它负责把 size/crop_size/pad_size 统一为 SizeDict,把 image_mean/image_std 列表转元组,源码),需要兼容旧配置的模型可以在这里扩展。

小结

当前 Transformers 的图像处理器体系可以概括为三句话:

  • 架构上BaseImageProcessor 定义"参数校验 → 单图格式转换 → 批量处理"的骨架,TorchvisionBackend(GPU、批量、融合优化)与 PilBackend(CPU、可移植、数值对齐)提供同 API 的两种实现,模型类(如 DetrImageProcessor)声明默认参数并可覆写任意环节;
  • 使用上AutoImageProcessor.from_pretrained(..., backend=...) 是入口:默认自动选择、pil 用于精确对齐旧实现、torchvision 下可用 device 参数把处理搬上 GPU;Lanczos 模型在 torchvision < 0.27 时自动走 PIL 或降级 BICUBIC,行为可预期;
  • 扩展上,类属性声明默认参数、覆写 _preprocess/_preprocess_image_like_inputs 实现自定义流水线、valid_kwargs 扩展参数面——三层机制覆盖了绝大多数定制需求。

相关源码入口:image_processing_utils.py(骨架与参数体系)、image_processing_backends.py(双后端实现)、image_processing_auto.py(后端解析与回退)、image_processing_base.py(加载/保存与 BatchFeature)。

登录后查看全文
热门项目推荐
相关项目推荐