You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch加载多JSON标注图像及自定义数据集微调问题咨询

如何将自定义Dataset与PyTorch微调示例的DataLoader结合

嘿,我来帮你搞定这个问题!你已经写好了自定义的lDataSet,接下来只需要把它替换掉官方示例里的ImageFolder,再做一些小调整就能完美适配啦,具体步骤如下:

1. 修正并完善自定义Dataset

先把你Dataset里的小bug和缺失的部分补上,比如数据转换、标注处理,还有适配数据增强:

import os
import json
import cv2
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms

class lDataSet(Dataset):
    def __init__(self, path_to_imgs, path_to_json, transform=None):
        self.path_to_imgs = path_to_imgs
        self.path_to_json = path_to_json
        # 确保只获取jpg文件,避免其他干扰文件
        self.img_ids = [f.split('.')[0] for f in os.listdir(path_to_imgs) if f.endswith('.jpg')]
        self.transform = transform

    def __getitem__(self, idx):
        img_id = self.img_ids[idx]
        # 读取图像并转成RGB(cv2默认是BGR)
        img = cv2.imread(os.path.join(self.path_to_imgs, f"{img_id}.jpg"))
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        
        # 加载并处理COCO格式的标注
        with open(os.path.join(self.path_to_json, f"{img_id}.json")) as f:
            annot = json.load(f)
        
        # 提取需要的标注信息(比如bbox、类别id,根据你的任务调整)
        bboxes = []
        labels = []
        for obj in annot['annotations']:
            bboxes.append(obj['bbox'])
            labels.append(obj['category_id'])
        
        # 转成Tensor格式
        bboxes = torch.tensor(bboxes, dtype=torch.float32)
        labels = torch.tensor(labels, dtype=torch.long)
        
        # 应用数据增强
        if self.transform:
            # 注意:如果用torchvision的transform,需要先把numpy转成PIL图像
            img = transforms.ToPILImage()(img)
            img = self.transform(img)
        
        return img, {'bboxes': bboxes, 'labels': labels}

    def __len__(self):
        return len(self.img_ids)

这里主要做了这些优化:

  • 过滤出仅jpg格式的图像,避免读取无效文件
  • 把cv2读取的BGR图像转成RGB,符合PyTorch的默认格式
  • 解析COCO标注里的bbox和类别,并转成Tensor
  • 支持传入数据增强的transform,和官方示例对齐

2. 替换官方示例的数据集创建部分

官方示例里用ImageFolder创建数据集,现在换成你的lDataSet:

# 定义数据增强(和官方示例保持一致)
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

# 定义数据根目录
data_dir = "/home"

# 创建训练和验证数据集(替换ImageFolder为自定义Dataset)
image_datasets = {
    'train': lDataSet(
        path_to_imgs=os.path.join(data_dir, 'training/images'),
        path_to_json=os.path.join(data_dir, 'training/json_annotations'),
        transform=data_transforms['train']
    ),
    'val': lDataSet(
        path_to_imgs=os.path.join(data_dir, 'validation/images'),
        path_to_json=os.path.join(data_dir, 'validation/json_annotations'),
        transform=data_transforms['val']
    )
}

3. 创建DataLoader(和官方示例基本一致)

这一步只需要加个小适配,因为每张图的目标数量可能不一样:

batch_size = 8
dataloaders_dict = {
    x: DataLoader(
        image_datasets[x], 
        batch_size=batch_size, 
        shuffle=True, 
        num_workers=4,
        # 处理变长标注:默认collate函数会报错,用这个lambda把图像和标注分别打包成列表
        collate_fn=lambda batch: tuple(zip(*batch))
    ) for x in ['train', 'val']
}

4. 在训练循环中使用

现在你可以像官方示例那样在训练循环里迭代DataLoader了,比如:

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

# 假设你已经定义好了适配多目标任务的模型(比如基于Faster R-CNN的模型)
model = ... # 初始化你的模型
model = model.to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

# 训练循环示例
for epoch in range(10):
    print(f'Epoch {epoch}/{9}')
    print('-' * 10)

    for phase in ['train', 'val']:
        if phase == 'train':
            model.train()
        else:
            model.eval()
        
        running_loss = 0.0
        for imgs, annotations in dataloaders_dict[phase]:
            imgs = [img.to(device) for img in imgs]
            # 把标注转移到设备上
            annotations = [{k: v.to(device) for k, v in ann.items()} for ann in annotations]
            
            with torch.set_grad_enabled(phase == 'train'):
                outputs = model(imgs, annotations)
                loss = sum(loss_val for loss_val in outputs.values())
                
                if phase == 'train':
                    optimizer.zero_grad()
                    loss.backward()
                    optimizer.step()
            
            running_loss += loss.item() * len(imgs)
        
        epoch_loss = running_loss / len(image_datasets[phase])
        print(f'{phase} Loss: {epoch_loss:.4f}')

这样就完美把你的自定义数据集和官方的微调流程结合起来啦,核心就是用自己的lDataSet替换掉ImageFolder,再根据多目标任务的特性处理变长标注~

内容的提问来源于stack exchange,提问作者bibinwilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:26:14