如何将基于自定义图像的数据集加载到 Pytorch 中以与 CNN 一起使用?

Posted

技术标签:

【中文标题】如何将基于自定义图像的数据集加载到 Pytorch 中以与 CNN 一起使用?【英文标题】:How do I load custom image based datasets into Pytorch for use with a CNN? 【发布时间】:2019-01-05 17:15:46 【问题描述】:

我已经在互联网上搜索了几个小时,以找到解决我问题的好方法。以下是一些相关的背景信息,可帮助您回答我的问题。

这是我的第一个深度学习项目,我不知道自己在做什么。我知道理论,但不知道实际要素。

我使用的数据可以在 kaggle 的这个链接上找到: (https://www.kaggle.com/alxmamaev/flowers-recognition)

我的目标是使用 CNN 根据数据集中提供的图像对花朵进行分类。

到目前为止,这是我尝试用来加载数据的一些示例代码,这是我最好的尝试,但正如我所提到的,我一无所知,Pytorch 文档并没有提供我能理解的太多帮助。 (https://pastebin.com/fNLVW1UW)

    # Loads the images for use with the CNN.
def load_images(image_size=32, batch_size=64, root="../images"):
    transform = transforms.Compose([
        transforms.Resize(32),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

    train_set = datasets.ImageFolder(root=root, train=True, transform=transform)
    train_loader = torch.utils.data.DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=2)

    return train_loader


# Defining variables for use with the CNN.
classes = ('daisy', 'dandelion', 'rose', 'sunflower', 'tulip')
train_loader_data = load_images()

# Training samples.
n_training_samples = 3394
train_sampler = SubsetRandomSampler(np.arange(n_training_samples, dtype=np.int64))

# Validation samples.
n_val_samples = 424
val_sampler = SubsetRandomSampler(np.arange(n_training_samples, n_training_samples + n_val_samples, dtype=np.int64))

# Test samples.
n_test_samples = 424
test_sampler = SubsetRandomSampler(np.arange(n_test_samples, dtype=np.int64))

以下是我需要回答的直接问题:

如何修复我的代码以加载到数据集中以 80/10/10 拆分进行训练/测试/验证?

如何为这些已按 /images 中的文件夹划分的图像创建所需的标签/类?

【问题讨论】:

【参考方案1】:

查看来自 Kaggle 的数据和您的代码,您的数据加载存在问题。

数据应该位于每个类标签的不同文件夹中,以便 PyTorch ImageFolder 正确加载它。在您的情况下,由于所有训练数据都在同一个文件夹中,PyTorch 将其作为一个训练集加载。您可以通过使用像 train/daisytrain/dandeliontest/daisytest/dandelion 这样的文件夹结构来更正此问题,然后将 train 和 test 文件夹分别传递给 train 和 test ImageFolder。只需更改文件夹结构,您应该会很好。看看torchvision.datasets.Imagefolder的官方文档,里面有类似的例子。


正如你所说,这些图像已经被/images 中的文件夹分割。 PyTorch ImageFolder 假定图像按以下方式组织。但是这个文件夹结构只有在你将所有图像都用于训练集时才是正确的:

```
/images/daisy/100080576_f52e8ee070_n.jpg
/images/daisy/10140303196_b88d3d6cec.jpg
.
.
.
/images/dandelion/10043234166_e6dd915111_n.jpg
/images/dandelion/10200780773_c6051a7d71_n.jpg
```

其中“雏菊”、“蒲公英”等是类标签。

如果您想在您的案例中将数据集拆分为训练集和测试集,则正确的文件夹结构(请注意,我知道您想将数据集拆分为训练集、验证集和测试集,但这并不重要只是一个例子来说明这个想法):

```
/images/train/daisy/100080576_f52e8ee070_n.jpg
/images/train/daisy/10140303196_b88d3d6cec.jpg
.
.
/images/train/dandelion/10043234166_e6dd915111_n.jpg
/images/train/dandelion/10200780773_c6051a7d71_n.jpg
.
.
/images/test/daisy/300080576_f52e8ee070_n.jpg
/images/test/daisy/95140303196_b88d3d6cec.jpg
.
.
/images/test/dandelion/32143234166_e6dd915111_n.jpg
/images/test/dandelion/65200780773_c6051a7d71_n.jpg
```

然后,您可以参考以下完整代码示例了解如何编写数据加载器:

import os
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import torch.utils.data as data
import torchvision
from torchvision import transforms

EPOCHS = 2
BATCH_SIZE = 10
LEARNING_RATE = 0.003
TRAIN_DATA_PATH = "./images/train/"
TEST_DATA_PATH = "./images/test/"
TRANSFORM_IMG = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(256),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225] )
    ])

train_data = torchvision.datasets.ImageFolder(root=TRAIN_DATA_PATH, transform=TRANSFORM_IMG)
train_data_loader = data.DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True,  num_workers=4)
test_data = torchvision.datasets.ImageFolder(root=TEST_DATA_PATH, transform=TRANSFORM_IMG)
test_data_loader  = data.DataLoader(test_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=4) 

class CNN(nn.Module):
    # omitted...

if __name__ == '__main__':

    print("Number of train samples: ", len(train_data))
    print("Number of test samples: ", len(test_data))
    print("Detected Classes are: ", train_data.class_to_idx) # classes are detected by folder structure

    model = CNN()    
    optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)
    loss_func = nn.CrossEntropyLoss()    

    # Training and Testing
    for epoch in range(EPOCHS):        
        for step, (x, y) in enumerate(train_data_loader):
            b_x = Variable(x)   # batch x (image)
            b_y = Variable(y)   # batch y (target)
            output = model(b_x)[0]          
            loss = loss_func(output, b_y)   
            optimizer.zero_grad()           
            loss.backward()                 
            optimizer.step()

            if step % 50 == 0:
                test_x = Variable(test_data_loader)
                test_output, last_layer = model(test_x)
                pred_y = torch.max(test_output, 1)[1].data.squeeze()
                accuracy = sum(pred_y == test_y) / float(test_y.size(0))
                print('Epoch: ', epoch, '| train loss: %.4f' % loss.data[0], '| test accuracy: %.2f' % accuracy)

【讨论】:

太棒了。这帮助很大。我按照你的建议让它工作了。非常感谢您的帮助和时间。 我改变了我的代码,但现在我在运行程序时得到了奇怪的结果。 Epoch 1, Train Accuracy: 0 , TrainLoss: 0.1286807805299759 , Test Accuracy: 0 Epoch 2, Train Accuracy: 0 , TrainLoss:0.12216705083847046,测试精度:0【参考方案2】:

现在有一个简单的拆分包,称为“拆分文件夹”。见here。 例如

import splitfolders
splitfolders.ratio(image_path, output="output", seed=43, ratio=(.8,.1,.1))

【讨论】:

以上是关于如何将基于自定义图像的数据集加载到 Pytorch 中以与 CNN 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

使用PyTorch进行数据处理

如何将 numpy 数组列表加载到 pytorch 数据集加载器?

ccc-pytorch-宝可梦自定义数据集实战-加载数据部分

PyTorch自定义数据集处理/dataset/DataLoader等

PyTorch自定义数据集处理/dataset/DataLoader等

使用 PyTorch 和 TorchVision 对自定义数据集进行训练-有效-测试拆分