4 votes

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 l'internet pour trouver une bonne solution à mon problème. Voici quelques informations générales pertinentes pour vous aider à répondre à ma question.

C'est mon tout premier projet d'apprentissage profond 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 cherche à classifier les fleurs à partir des images fournies dans le jeu de données en utilisant un CNN.

Voici quelques exemples 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 suis désemparé et la documentation de Pytorch n'a 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 besoin de réponses :

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

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

7voto

cedrickchee Points 354

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 être dans un dossier différent par étiquette de classe pour PyTorch. ImageFolder pour le charger correctement. Dans votre cas, comme toutes les données d'entraînement se trouvent dans le même dossier, PyTorch les charge comme un seul ensemble d'entraînement. Vous pouvez corriger cela en utilisant une structure de dossier comme - train/daisy , train/dandelion , test/daisy , test/dandelion puis en passant le dossier train et test au dossier train et test ImageFolder respectivement. Il suffit de modifier la structure des dossiers et tout devrait bien se passer. Jetez un coup d'œil à la documentation officielle de torchvision.datasets.Imagefolder qui présente 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 dossier n'est correcte que si vous utilisez toutes les images de la rame :

```
/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 voulez diviser l'ensemble de données en train et test dans votre cas (notez que je sais que vous voulez diviser l'ensemble de données en train, validation, et test, mais cela n'a pas d'importance car c'est juste un exemple pour faire passer 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 dataloader :

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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X