web-dev-qa-db-fra.com

Comment charger des jeux de données personnalisés basés sur des images dans Pytorch pour les utiliser avec un CNN?

J'ai cherché pendant des heures sur Internet pour trouver une bonne solution à mon problème. Voici quelques informations générales pertinentes pour vous aider à répondre à ma question.

Il s'agit de mon tout premier projet d'apprentissage en profondeur et je n'ai aucune idée de ce que je fais. Je connais la théorie mais pas les éléments pratiques.

Les données que j'utilise peuvent être trouvées sur kaggle à ce lien: ( https://www.kaggle.com/alxmamaev/flowers-recognition )

Je vise à classer les fleurs sur la base des images fournies dans l'ensemble de données à l'aide d'un CNN.

Voici un exemple de code que j'ai essayé d'utiliser pour charger des données jusqu'à présent, c'est ma meilleure tentative, mais comme je l'ai mentionné, je ne sais rien et les documents Pytorch n'ont pas offert beaucoup d'aide que je pouvais comprendre à mon niveau. ( 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))

Voici mes questions directes auxquelles j'ai également besoin de réponses:

  • Comment puis-je corriger mon code à charger dans l'ensemble de données dans une répartition 80/10/10 pour la formation/le test/la validation?

  • Comment créer les étiquettes/classes requises pour ces images qui sont déjà divisées par dossiers dans/images?

5
Aeryes

En regardant les données de Kaggle et votre code, il y a des problèmes dans le chargement de vos données.

Les données doivent se trouver dans un dossier différent par étiquette de classe pour que PyTorch ImageFolder le charge correctement. Dans votre cas, étant donné que toutes les données d'entraînement se trouvent dans le même dossier, PyTorch les charge en un seul train. Vous pouvez corriger cela en utilisant une structure de dossiers comme - train/daisy, train/dandelion, test/daisy, test/dandelion puis en passant le train et le dossier de test au train et testez ImageFolder respectivement. Modifiez simplement la structure du dossier et vous devriez être bon. Jetez un œil à la documentation officielle de torchvision.datasets.Imagefolder qui a un exemple similaire.


Comme vous l'avez dit, ces images qui sont déjà divisées par dossiers dans /images. PyTorch ImageFolder suppose que les images sont organisées de la manière suivante. Mais cette structure de dossiers n'est correcte que si vous utilisez toutes les images pour le train:

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

où "marguerite", "pissenlit", etc. sont des étiquettes de classe.

La structure de dossier correcte si vous souhaitez diviser l'ensemble de données en train et ensemble de test dans votre cas (notez que je sais que vous voulez diviser l'ensemble de données en train, validation et ensemble de test, mais cela n'a pas d'importance car ce n'est qu'un exemple pour faire sortir l'idée):

```
/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
```

Ensuite, vous pouvez vous référer à l'exemple de code complet suivant sur la façon d'écrire un chargeur de données:

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 __== '__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)
3
cedrickchee