使用Transformers库中的模型提取图像特征遇到的问题

最近做一个图像相关的项目,需要提取图像特征,在使用Transformers库中的深度神经网络模型提取图像特征的过程中,遇到一些问题,记录一下。

下面是图像特征提取的简化代码及相应的中间输出,使用的是OpenAI的CLIP模型:

import os
import torch
import numpy as np

from PIL import Image
from transformers import AutoProcessor, CLIPModel

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

processor = AutoProcessor.from_pretrained('openai/clip-vit-base-patch32')
model = CLIPModel.from_pretrained('openai/clip-vit-base-patch32').to(device)

img_dir = '/dir/to/img'

img_paths = [os.path.join(img_dir, filename)  for filename in os.listdir(img_dir)]
# ['/dir/to/img/a.tif', '/dir/to/img/b.jpg', '/dir/to/img/c.jpg', '/dir/to/img/d.tif']

pilimgs = [Image.open(img) for img in img_paths]
# [<PIL.TiffImagePlugin.TiffImageFile image mode=CMYK size=3008x2000>,  <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=3702x2592>, <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=3024x1084>, <PIL.TiffImagePlugin.TiffImageFile image mode=CMYK size=3872x2592>]

nparrs = [np.array(img) for img in pilimgs]
# [arr.shape for arr in nparrs]
# [(2000, 3008, 4), (2592, 3702, 3), (1084, 3024, 3), (2592, 3872, 4)]

with torch.no_grad():
    inputs = processor(images=nparrs, return_tensors='pt')
    image_feature = model.get_image_features(**inputs)

通过中间输出可以看到,使用PIL.Image读取图片得到的对象的mode属性是不一样的,tif图片对应的mode为CMYK,jpg图片对应的mode为RGB,将这些对象转化为ndarray后,能够看到tif图片的通道数为4,而jpg图片的通道数为3,图片数据的这些差异会导致使用模型批量提取图片特征时出现问题,而且输入的数据类型和输入图片的顺序不同,出现的问题也不一样。

不同的模型输入及对应的结果

  • 直接输入PIL.Image.Image对象列表(如下所示),不会报错
with torch.no_grad():
    inputs = processor(images=pilimgs, return_tensors='pt')
    image_feature = model.get_image_features(**inputs)

直接传入PIL.Image.Image对象列表,无论列表中是相同mode的图片对象还是不同mode的图片对象,模型都能正确处理,不会报错。但是实际情况下,一般不会直接传入PIL.Image.Image列表,因为通常需要处理大量图片,在这种情况下,大量使用Image.open而没有进行正确的后续处理很容易造成内存泄漏。可以配合with语句将图片转化为ndarray

with open(img_path, 'rb') as f:
    img = Image.open(f)
    arr = np.array(img)
  • 输入np.ndarray列表,列表中含有通道数为4的图片且第一个元素的通道数为4或列表中图片的通道数都为4
    出现错误ValueError: Unable to infer channel dimension format
  • 输入np.ndarray列表,列表中图片的通道数不同且第一个元素的通道数为3
    出现错误ValueError: mean must have 4 elements if it is an iterable, got 3
  • 输入np.ndarray列表,列表中图片的通道数都为3,成功执行

可以看到,当传入给模型的数据类型为np.ndarray(或torch.Tensor)时,存在通道数为4(mode为CMYK或其他)的图片都会导致模型处理出现异常,因此需要将这些图片转化为RGB模式,也就是通道数为3:

with open(img_path, 'rb') as f:
    img = Image.open(f)
    if img.mode != 'RGB':
        img = img.convert('RGB')
    arr = np.array(img)
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用 transformers 库进行图像分割的例子: 1. 安装必要的库和模块: ``` !pip install transformers !pip install torch torchvision ``` 2. 导入必要的库和模块: ``` import torch import torchvision import matplotlib.pyplot as plt from transformers import ViTFeatureExtractor, ViTForImageSegmentation ``` 3. 加载数据集: ``` transform = torchvision.transforms.Compose([ torchvision.transforms.Resize((224, 224)), torchvision.transforms.ToTensor(), ]) train_dataset = torchvision.datasets.CocoDetection( root='./data/train2017', annFile='./data/annotations/instances_train2017.json', transform=transform ) test_dataset = torchvision.datasets.CocoDetection( root='./data/val2017', annFile='./data/annotations/instances_val2017.json', transform=transform ) ``` 4. 加载模型特征提取器: ``` feature_extractor = ViTFeatureExtractor.from_pretrained('google/vit-base-patch16-224') model = ViTForImageSegmentation.from_pretrained('google/vit-base-patch16-224') ``` 5. 定义训练函数: ``` def train(model, train_dataloader, optimizer, criterion, device): model.train() train_loss = 0 for i, (inputs, targets) in enumerate(train_dataloader): inputs = inputs.to(device) targets = targets.to(device) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, targets) loss.backward() optimizer.step() train_loss += loss.item() return train_loss / len(train_dataloader) ``` 6. 定义测试函数: ``` def test(model, test_dataloader, criterion, device): model.eval() test_loss = 0 with torch.no_grad(): for i, (inputs, targets) in enumerate(test_dataloader): inputs = inputs.to(device) targets = targets.to(device) outputs = model(inputs) loss = criterion(outputs, targets) test_loss += loss.item() return test_loss / len(test_dataloader) ``` 7. 训练模型: ``` device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model.to(device) optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) criterion = torch.nn.CrossEntropyLoss() train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=16, shuffle=True) test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=16, shuffle=False) num_epochs = 10 train_losses = [] test_losses = [] for epoch in range(num_epochs): train_loss = train(model, train_dataloader, optimizer, criterion, device) test_loss = test(model, test_dataloader, criterion, device) train_losses.append(train_loss) test_losses.append(test_loss) print(f'Epoch {epoch+1}/{num_epochs}, Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}') plt.plot(train_losses, label='Train Loss') plt.plot(test_losses, label='Test Loss') plt.legend() plt.show() ``` 8. 对单个图像进行预测: ``` image = torchvision.io.read_image('image.jpg') inputs = transform(image).unsqueeze(0).to(device) outputs = model(inputs) segmentation_map = torch.argmax(outputs, dim=1).squeeze().cpu().numpy() plt.imshow(segmentation_map) plt.show() ``` 以上是使用 transformers 库进行图像分割的例子,其中使用了 ViT 模型和 COCO 数据集。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elwin Wong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值