如何在Pytorch中获取自定义数据集的class_to_idx映射

时间:2019-02-17 14:36:06

标签: python-3.x image-processing computer-vision pytorch

我正在尝试对Oxford102类别数据集上的CNN(vgg19)进行迁移学习,该数据集由8189个从1到102标记的花朵样本组成。而不是使用ImageFolder加载数据,这需要将数据结构化为火车的繁琐过程,有效和测试文件夹,每个类都是保存我的图像的子文件夹,我决定使用

之后的Custom Dataset类加载它

https://pytorch.org/tutorials/beginner/data_loading_tutorial.html

我为项目编写的代码的一部分

    data_dir_path = 'data/images/'
    labels_path = 'data/imagelabels.mat'
    class_label_path = 'data/class_label_map'

    # standard normalization for Imagenet models mean: [0.485, 0.456,0.406],
    # std :[0.229, 0.224, 0.225]

    data_transforms = {
'train': transforms.Compose([
    transforms.RandomRotation(45),
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406],
                         [0.229, 0.224, 0.225])
]),
'valid': transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406],
                         [0.229, 0.224, 0.225])
]),
'test': transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406],
                         [0.229, 0.224, 0.225])
]),
   }


    class MyDataset(Dataset):

        def __init__(self, image_labels, data_dir, transform=None):

    """

    :param image_labels_path: path to our labels
    :param root_dir: the directory which houses our images
    :param transform: apply any transform on our sample
    """

    self.image_labels = image_labels
    self.root_dir = data_dir
    self.transform = transform

        def __len__(self):
    label_dict = scipy.io.loadmat(self.image_labels)
    return len(label_dict['labels'][0])

        def __getitem__(self, idx):

    image_path_list = [os.path.join(self.root_dir, filename) for filename in os.listdir(self.root_dir)]

    image = Image.open(image_path_list[idx])

    label_dict = scipy.io.loadmat(self.image_labels)
    label_list = label_dict['labels'][0]

    # label index for pytorch should start form zero
    # so subtract -1 from each class
    label_list[:] = [i - 1 for i in label_list]
    label = label_list[idx]  

    if self.transform:
        image = self.transform(image)

    return image, label

    image_datasets = {x: MyDataset(image_labels=labels_path, data_dir=data_dir_path, transform=data_transforms[x]) for x in
              ['train', 'valid', 'test']}

我从nn.Module继承的模型类实例是

    classifier = Neural(25088, [4096], 102)

由于Pytorch希望标签从0开始,因此我从标签列表中减去了-1。因此,对于102个标签,从0到101。如果我做错了,请纠正我,因为如果我不减去一个,则会收到“当前目标> = 0,而当前目标<= n_classes失败”错误。

class_label_map是将类标签映射到花朵名称的字典

    {
"1": "pink primrose",
"2": "hard-leaved pocket orchid",
"3": "canterbury bells",
"4": "sweet pea",
"5": "english marigold",
"6": "tiger lily",
"7": "moon orchid",
"8": "bird of paradise",
"9": "monkshood",
"10": "globe thistle",
"11": "snapdragon",
    }

我的大问题是要获得一个class_to_idx映射,我该怎么做,如果我将花朵形象化,它们的花朵名称将与图像不匹配,我的花朵的花朵名称将完全不同。

首先我创建了一个映射,方法是在减去1之前先用键将我的原始标签作为键,然后再赋一个值。例子

    class_to_idx = {77:76, 73:72, 1:0, 65:64......102:101...65:54}

这毫无疑问是错误的,因为我的图像标签完全错误。

在我的data_dir_path ='data / images'中,我的图像的第一个标签是77,减去一个就得到76。 这是否意味着所有标签76的索引都是0,如果下一个类是72,那是否意味着所有标签72的索引都是1?所以...

    class_to_idx = {76:0, 72:1, 0:2, 65:3....and so on}

ImageFolder似乎具有class_to_idx属性,如果在我的数据集上使用该属性,则会引发错误,

    image_datasets['train'].class_to_idx

   AttributeError: 'MyDataset' object has no attribute 'class_to_idx'

显然是这种情况,因为我的数据集类不包含任何此类属性。

但是,很认真的是,如何将我的班级映射到索引?这是非常重要的,因为我需要检查点模型并再次加载回模型以发出预测。这听起来确实很傻,但是我真的不知道该怎么办,请帮忙?

1 个答案:

答案 0 :(得分:0)

我很久以前就完成了这件事,为此我想给我两毛钱关于我哪里出了问题,这真令人尴尬。我没有对image_path_list进行排序。它们出现在我的数据文件夹中的顺序与标签文件夹列表中的相应标签不匹配。这是因为Python正在以任意顺序将它们从数据文件夹中读取到image_path_list中。一个简单的排序将所有内容整理出来。

    image_path_list = sort([os.path.join(self.root_dir, filename) for filename in os.listdir(self.root_dir)])