pytorch读取VOC数据集

简单介绍VOC数据集

首先介绍下VOC2007数据集(下图是VOC数据集格式,为了叙述方便,我这里只放了两张图像)
在这里插入图片描述
Main文件夹内的trainval.txt中的内容如下:存储了图像的名称不加后缀。

000009
000052

Annotations中存储的是标注文件,以xml文件存储。这里简单截个图说明一下:

<annotation>
   <folder>VOC2007</folder>
   <filename>000009.jpg</filename>               # !存储图像名称,若转换voc数据集,记住命名格式最好是相同
   <source>
      <database>The VOC2007 Database</database>
      <annotation>PASCAL VOC2007</annotation>
      <image>flickr</image>
      <flickrid>325443404</flickrid>
   </source>
   <owner>
      <flickrid>autox4u</flickrid>
      <name>Perry Aidelbaum</name>
   </owner>
   <size>                                          # 存储着图像的宽和高以及深度
      <width>500</width>                               
      <height>375</height>
      <depth>3</depth>
   </size>
   <segmented>0</segmented>
   <object>                                        # 存储着对象
      <name>horse</name>
      <pose>Right</pose>
      <truncated>0</truncated>
      <difficult>0</difficult>                   # 是否是困难检测目标
      <bndbox>                                     # 图像中的box
         <xmin>69</xmin>
         <ymin>172</ymin>
         <xmax>270</xmax>
         <ymax>330</ymax>
      </bndbox>
   </object>
</annotation>

pytorch读取脚本

然后你可以通过以下脚本进行读取–>(读取脚本在SSD中的方式也挺好,这里仅仅提供一种最mini的读取方式)。

import torch
import xml.etree.ElementTree as ET
import os
import cv2
import numpy as np
from torchvision import transforms

class VOCDataset(torch.utils.data.Dataset):

    CLASSES_NAME = (
        "__background__ ",                 # 记得加上背景类
        "pottedplant",
        "person",
        "horse",
    )
    # 初始化类
    def __init__(self, root_dir, resize_size=[800, 1024], split='trainval', use_difficult=False):

        self.root = root_dir
        self.use_difficult = use_difficult
        self.imgset = split

        self._annopath = os.path.join(self.root, "Annotations", "%s.xml")
        self._imgpath = os.path.join(self.root, "JPEGImages", "%s.jpg")
        self._imgsetpath = os.path.join(self.root, "ImageSets", "Main", "%s.txt")

        # 读取trainval.txt中内容
        with open(self._imgsetpath % self.imgset) as f:     # % 是python字符串中的一个转义字符可以百度下,不难
            self.img_ids = f.readlines()
        self.img_ids = [x.strip() for x in self.img_ids]    # ['000009', '000052']

        self.name2id = dict(zip(VOCDataset.CLASSES_NAME, range(len(VOCDataset.CLASSES_NAME))))
        self.resize_size = resize_size
        self.mean = [0.485, 0.456, 0.406]      # voc数据集中所有图像矩阵的均值和方差,为后续图像归一化做准备
        self.std = [0.229, 0.224, 0.225]
        print("INFO=====>voc dataset init finished  ! !")

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

    def _read_img_rgb(self, path):
        return cv2.cvtColor(cv2.imread(path), cv2.COLOR_BGR2RGB)

    def __getitem__(self, index):

        img_id = self.img_ids[index]
        img = self._read_img_rgb(self._imgpath % img_id)

        anno  = ET.parse(self._annopath % img_id).getroot()  # 读取xml文档的根节点
        boxes = []
        classes = []

        for obj in anno.iter("object"):
            difficult = int(obj.find("difficult").text) == 1
            if not self.use_difficult and difficult:
                continue
            _box = obj.find("bndbox")
            box = [
                _box.find("xmin").text,
                _box.find("ymin").text,
                _box.find("xmax").text,
                _box.find("ymax").text,
            ]
            TO_REMOVE = 1                                  # 由于像素是网格存储,坐标2实质表示第一个像素格,所以-1
            box = tuple(
                map(lambda x: x - TO_REMOVE, list(map(float, box)))
            )
            boxes.append(box)

            name = obj.find("name").text.lower().strip()
            classes.append(self.name2id[name])             # 将类别映射回去

        boxes = np.array(boxes, dtype=np.float32)

        #将img,box和classes转成tensor
        img = transforms.ToTensor()(img)    # transforms 自动将 图像进行了归一化,
        boxes = torch.from_numpy(boxes)
        classes = torch.LongTensor(classes)

        return img, boxes, classes
if __name__ == '__main__':
    dataset = VOCDataset('E://Z_summary_net/Read_VOC/VOCdevkit/VOC2007/') # 实例化一个对象
    img,box,cls = dataset[0]          # 返回第一张图像及box和对应的类别
    print(img.shape)
    print(box)
    print(cls)

    # 这里简单做一下可视化
    # 由于opencv读入是矩阵,而img现在是tensor,因此,首先将tensor转成numpy.array
    img_ = (img.numpy()*255).astype(np.uint8).transpose(1,2,0)# 注意由于图像像素分布0-255,所以转成uint8
    print(img_.shape)
    cv2.imshow('test',img_)
    cv2.waitKey(0)

注意

这里有一个细节:torch将box、classes和img转换成张量tensor。假如现在我想利用OpenCV重新还原出图像来,那么存在一个问题:就是经过transforms.ToTensor()的img已经被进行了归一化,img的像素矩阵除以了255。因此,要想还原cv2中的numpy数组,需要*255。另外,由于cv2需要读取[W,H,C]的矩阵,因此,还需要通过transpose(1,2,0)交换一下维度。
最后,贴上transforms.ToTensor()的源码:

if isinstance(pic, np.ndarray):
    # handle numpy array
    if pic.ndim == 2:
        pic = pic[:, :, None]
    img = torch.from_numpy(pic.transpose((2, 0, 1)))     # 交换维度
    # backward compatibility
    if isinstance(img, torch.ByteTensor):                 # /255 归一化
        return img.float().div(255)
    else:
        return img
好的,下面是使用 PyTorch 和 Pascal VOC 数据集进行训练的一些步骤: 1. 下载 Pascal VOC 数据集并解压缩。您可以从 http://host.robots.ox.ac.uk/pascal/VOC/ 下载数据集并按照指示解压缩。 2. 安装 PyTorch。您可以从 PyTorch 网站(https://pytorch.org/get-started/locally/)获取安装说明并安装 PyTorch。 3. 安装 torchvision。您可以使用以下命令安装 torchvision: ``` pip install torchvision ``` 4. 准备数据集。您需要将 Pascal VOC 数据集转换为 PyTorch 可以读取的格式。您可以使用以下代码: ``` from torchvision import datasets, transforms data_transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) train_dataset = datasets.VOCDetection(root='path/to/PascalVOC', year='2012', image_set='train', transform=data_transform) val_dataset = datasets.VOCDetection(root='path/to/PascalVOC', year='2012', image_set='val', transform=data_transform) ``` 将 "/path/to/PascalVOC" 替换为您解压缩数据集的路径。 5. 定义模型。您可以使用现有的模型,如 ResNet 或 VGG,也可以自己定义模型。这里是一个使用 ResNet18 的示例: ``` import torch.nn as nn import torchvision.models as models model = models.resnet18(pretrained=True) # 替换最后一层全连接层 num_classes = 20 # Pascal VOC 数据集中有20个类别 model.fc = nn.Linear(model.fc.in_features, num_classes) ``` 6. 定义损失函数和优化器。这里使用交叉熵损失和随机梯度下降(SGD)优化器: ``` import torch.optim as optim criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9) ``` 7. 训练模型。您可以使用以下代码训练模型: ``` from torch.utils.data import DataLoader train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False) num_epochs = 10 for epoch in range(num_epochs): # 训练模型 model.train() for images, labels in train_loader: optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() # 在验证集上评估模型 model.eval() with torch.no_grad(): total_correct = 0 total_samples = 0 for images, labels in val_loader: outputs = model(images) _, predicted = torch.max(outputs, 1) total_correct += (predicted == labels).sum().item() total_samples += labels.size(0) val_accuracy = total_correct / total_samples print('Epoch [{}/{}], Val Accuracy: {:.2f}%'.format(epoch+1, num_epochs, val_accuracy*100)) ``` 在每个 epoch 结束时,模型在验证集上进行评估,并打印准确率。 希望这些步骤可以帮助您开始使用 PyTorch 和 Pascal VOC 数据集进行训练。如果您需要更详细的说明或者代码示例,请告诉我!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值