import open_clip
import torch

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# CLIP
device = torch.device(device)
clip_model_name = "ViT-L-14"
pretrained = "laion2b_s32b_b82k"

clip_model, _, clip_img_preprocessor = open_clip.create_model_and_transforms(
        model_name=clip_model_name, pretrained=pretrained, device=device
    )

print(clip_img_preprocessor)

输出:

Compose(
    Resize(size=224, interpolation=bicubic, max_size=None, antialias=None)
    CenterCrop(size=(224, 224))
    <function _convert_to_rgb at 0x7a4b01d96050>
    ToTensor()
    Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
)

clip_img_preprocessor 是一个用于图像预处理的变换(transform),它是通过 open_clip.create_model_and_transforms 函数生成的。它的作用是将输入的图像转换为适合 CLIP 模型输入的格式。


CLIP 图像预处理器的作用

CLIP 模型(Contrastive Language–Image Pretraining)是一个多模态模型,能够同时处理图像和文本。为了将图像输入到 CLIP 模型中,图像需要经过以下预处理步骤:

  1. 调整大小(Resize):将图像调整为模型所需的输入尺寸。
  2. 中心裁剪(Center Crop):从图像中心裁剪出固定大小的区域。
  3. 归一化(Normalization):将像素值归一化到模型训练时使用的均值和标准差。
  4. 转换为 Tensor:将图像从 PIL 格式或 NumPy 数组转换为 PyTorch 的 Tensor 格式。

clip_img_preprocessor 就是将这些步骤封装成一个可调用的变换(transform),可以直接应用于图像数据。


clip_img_preprocessor 的具体内容

通过 open_clip.create_model_and_transforms 生成的 clip_img_preprocessor 是一个 torchvision.transforms.Compose 对象,包含以下步骤:

  1. 调整大小:将图像调整为指定大小(例如 224x224)。
  2. 中心裁剪:从图像中心裁剪出指定大小的区域。
  3. 转换为 Tensor:将图像从 PIL 格式转换为 PyTorch 的 Tensor 格式。
  4. 归一化:使用 CLIP 模型训练时使用的均值和标准差对图像进行归一化。

你可以通过打印 clip_img_preprocessor 来查看其具体内容(见上)。


如何使用 clip_img_preprocessor

clip_img_preprocessor 可以直接应用于 PIL 图像或图像文件路径。以下是一个示例:

from PIL import Image

# 加载一张图片
image_path = "path_to_your_image.jpg"
image = Image.open(image_path).convert("RGB")

# 使用 clip_img_preprocessor 对图像进行预处理
preprocessed_image = clip_img_preprocessor(image)

# preprocessed_image 是一个 PyTorch Tensor,可以直接输入到 CLIP 模型中
print(preprocessed_image.shape)  # 输出: torch.Size([3, 224, 224])

clip_img_preprocessor 的参数

clip_img_preprocessor 的具体参数(如图像大小、归一化均值和标准差)是由 CLIP 模型的配置决定的。例如:

  • 图像大小:通常为 224x224(对于 ViT 模型)。
  • 归一化均值[0.48145466, 0.4578275, 0.40821073]
  • 归一化标准差[0.26862954, 0.26130258, 0.27577711]

这些参数是在 CLIP 模型训练时确定的,因此在使用预训练模型时必须保持一致。


与 CLIP 模型的配合使用

clip_img_preprocessor 的输出可以直接输入到 CLIP 模型的图像编码器中,以提取图像特征。以下是一个完整示例:

import torch
import open_clip
from PIL import Image

# 加载 CLIP 模型和预处理器
clip_model_name = "ViT-L-14"
pretrained = "laion2b_s32b_b82k"
device = "cuda" if torch.cuda.is_available() else "cpu"
clip_model, _, clip_img_preprocessor = open_clip.create_model_and_transforms(
    model_name=clip_model_name, pretrained=pretrained, device=device
)

# 加载一张图片
image_path = "path_to_your_image.jpg"
image = Image.open(image_path).convert("RGB")

# 对图像进行预处理
preprocessed_image = clip_img_preprocessor(image).unsqueeze(0).to(device)  # 增加 batch 维度并移动到设备

# 提取图像特征
with torch.no_grad():
    image_features = clip_model.encode_image(preprocessed_image)

print("图像特征形状:", image_features.shape)  # 输出: torch.Size([1, 768])

总结

  • clip_img_preprocessor 是一个图像预处理工具,用于将图像转换为适合 CLIP 模型输入的格式。
  • 它包含调整大小、中心裁剪、转换为 Tensor 和归一化等步骤。
  • 它的输出可以直接输入到 CLIP 模型的图像编码器中,以提取图像特征。

clip_img_preprocessor 里,已经执行了 Resize(size=224),为什么还需要 CenterCrop(size=(224, 224)) 这个问题的关键在于 Resize() 的行为

1. Resize(size=224, interpolation=bicubic)

  • 行为:当 size=224 时,Resize() 并不会直接把图片变成 224×224,而是等比例缩放,保证较短边变成 224,而较长边按比例缩放。
  • 结果:如果原始图片是 300×400,那么 Resize(224) 会将它缩放成 224×(224 × 4/3) = 224×298

2. CenterCrop(size=(224, 224))

  • 行为:在 Resize() 之后,图片的短边已经是 224,但长边可能仍然超过 224。因此,CenterCrop(224, 224)从中心裁剪出 224×224 的区域,去掉两边多余的部分。
  • 结果
    • 继续上面的例子,Resize(224) 得到 224×298CenterCrop(224, 224)从中心裁掉左右 37 像素,最终得到 224×224
    • 这保证了最终输入 CLIP 的图像是一个正方形(224×224),符合 CLIP 预训练时的输入格式。

为什么不直接 Resize(224, 224)

可以直接 Resize((224,224)) 吗?不行!因为:

  1. 直接 Resize((224,224))破坏图片的原始比例,可能导致形变(例如人脸可能会被压扁)。
  2. Resize(224) + CenterCrop(224, 224) 方案可以:
    • 保留原始比例(仅缩放短边到 224)
    • 保证最终尺寸为 224×224
    • 只裁剪掉长边的多余部分,不会改变主要内容的比例。

示意图

假设原始图像:

┌──────────────────────────────┐
│                              │
│          原始图片            │
│                              │
└──────────────────────────────┘

Resize(224) 可能会变成:

┌──────────────────────────────┐
│                              │
│       224 × 298(缩放)      │
│                              │
└──────────────────────────────┘

然后 CenterCrop(224, 224)

┌──────────────────┐
│                  │
│    224 × 224     │
│                  │
└──────────────────┘

最终,得到 CLIP 需要的 224×224 尺寸的输入。

总结

  1. Resize(224) 先把短边缩放到 224,保持原比例。
  2. CenterCrop(224, 224) 从中心裁剪,保证最终尺寸是 224×224。
  3. 这样既能保持原始长宽比例,又能满足 CLIP 的输入要求。

这种 “缩放+居中裁剪” 的做法,在很多预训练模型(如 ResNet、ViT)里也很常见!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐