PyTorch加载可变尺寸图像转Tensor报错:无法转换numpy.object_类型
解决PyTorch加载可变尺寸图像时的Tensor转换错误
你遇到的这个问题其实是处理可变尺寸图像时的典型误区——PyTorch的Tensor要求所有元素的形状完全一致,但你把不同尺寸的图像打包成了numpy object数组,这种数组里的每个元素形状都不一样,自然无法直接转换成Tensor。下面是具体的解决步骤:
第一步:调整图像加载逻辑,保留原始图像列表
首先修改你的get_imgs函数,不需要把图像转成numpy object数组,直接用Python列表存储每张图像即可:
def get_imgs(path_to_imgs): imgs = [] for path in path_to_imgs: # 注意cv2.imread返回的是BGR格式,如果需要RGB可以用img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.imread(path) imgs.append(img) return imgs # 直接返回列表,跳过numpy数组转换
第二步:重构Dataset类,在单样本获取时转换Tensor
不要在__init__里批量转换所有图像,而是在__getitem__中单独处理单张图像——这样每张图像的形状不同也没关系,因为我们是逐个转换:
import torch import cv2 from torch.utils.data import Dataset, DataLoader class VariableSizeImageDataset(Dataset): def __init__(self, path_to_imgs, path_to_label): self.path_to_imgs = path_to_imgs self.path_to_label = path_to_label self.imgs = get_imgs(path_to_imgs) self.labels = get_pts(path_to_label) # 假设你的get_pts返回形状统一的标签数据 def __len__(self): return len(self.imgs) def __getitem__(self, index): # 处理单张图像:从numpy转Tensor,同时转换通道顺序(cv2是HWC,PyTorch用CHW) img = self.imgs[index] # 转成float32并归一化(可选,根据你的模型需求调整) img_tensor = torch.from_numpy(img).permute(2, 0, 1).float() / 255.0 # 处理标签:如果标签形状统一,直接转成Tensor label = self.labels[index] label_tensor = torch.tensor(label, dtype=torch.float32) # 标签类型按需调整 return img_tensor, label_tensor
第三步:处理DataLoader的批量问题
默认的DataLoader会尝试把batch里的Tensor堆叠成一个大Tensor,但可变尺寸图像形状不一致,无法堆叠。这里有两种解决方案:
方案1:将batch打包成列表(适合目标检测、分割等不需要统一输入尺寸的任务)
自定义collate_fn,把batch里的图像保留为列表,标签正常堆叠:
def custom_collate_fn(batch): # batch是列表,每个元素是(__getitem__返回的img_tensor, label_tensor) imgs = [item[0] for item in batch] labels = torch.stack([item[1] for item in batch]) # 标签形状统一时可以直接堆叠 return imgs, labels # 创建DataLoader dataloader = DataLoader( VariableSizeImageDataset(path_to_imgs, path_to_label), batch_size=4, shuffle=True, collate_fn=custom_collate_fn )
方案2:对图像做padding,统一batch内尺寸(适合要求固定输入形状的模型)
如果你的模型需要固定尺寸的输入,可以在collate_fn里对当前batch的图像做padding,补到该batch的最大尺寸:
def collate_fn_with_padding(batch): imgs, labels = zip(*batch) # 获取当前batch的最大高度和宽度 max_h = max(img.shape[1] for img in imgs) max_w = max(img.shape[2] for img in imgs) padded_imgs = [] for img in imgs: c, h, w = img.shape # 计算需要补的像素数,这里默认补0,你也可以用均值或其他值 pad_h = max_h - h pad_w = max_w - w # PyTorch的pad顺序是(左, 右, 上, 下),对应最后两个维度 padded_img = torch.nn.functional.pad(img, (0, pad_w, 0, pad_h), mode='constant', value=0) padded_imgs.append(padded_img) # 堆叠成统一形状的batch Tensor padded_imgs = torch.stack(padded_imgs) labels = torch.stack(labels) return padded_imgs, labels # 使用带padding的collate_fn创建DataLoader dataloader = DataLoader( VariableSizeImageDataset(path_to_imgs, path_to_label), batch_size=4, shuffle=True, collate_fn=collate_fn_with_padding )
核心思路就是:不要提前批量处理可变尺寸的图像,而是逐个样本转换,再通过自定义collate_fn适配批量逻辑。
内容的提问来源于stack exchange,提问作者Farshid Rayhan
相关产品推荐
相关产品推荐

