Esercizio: Importare e pulire dati da foto

Completato

Dopo aver appreso i principi della pulizia e della separazione dei dati, è possibile applicarli al progetto di classificazione delle rocce.

Preparare i dati

È necessario creare due set di dati dalle foto della NASA per il progetto di classificazione. Un set di dati è per il training e l'altro per il test. Le immagini devono essere pulite e separate prima di essere caricate nei set di dati per l'elaborazione. I dati devono essere elaborati in modo casuale e non nell'ordine esatto in cui sono stati forniti dalla NASA.

Si userà il codice per eseguire questi quattro passaggi per preparare i dati:

  • Passaggio 1. Ottenere i dati: indicare al computer dove ottenere i dati dell'immagine.
  • Passaggio 2. Pulire i dati: ritagliare le immagini in modo che siano delle stesse dimensioni.
  • Passaggio 3. Separare i dati separare i dati tramite riorganizzandoli e sfruttando la selezione casuale.
  • Passaggio 4. Caricare set di dati casuali: preparare campioni casuali per i set di dati di training e di test.

Passaggio 1: Ottenere i dati

È necessario far sapere al computer dove può trovare i dati. In questo esempio vengono usate le immagini di rocce fornite dalla NASA. Le foto sono già state scaricate e archiviate nella cartella Data nella stessa cartella di progetto del file Jupyter Notebook. Si indicherà al computer di caricare i dati dell'immagine dalla cartella Data.

Passaggio 2: Eseguire la pulizia dei dati

Le foto di rocce della NASA sono di dimensioni diverse: piccole, medie e grandi. Le immagini verranno ritagliate in modo che siano delle stesse dimensioni (224 × 224 pixel). Le immagini vengono ridimensionate perché i computer si aspettano che le immagini abbiano le stesse dimensioni. Se le dimensioni sono variabili, non sarà facile per il computer elaborare le immagini. La classe torchvision transforms.Compose viene utilizzata per ridimensionare le immagini in base alle dimensioni preferite e archiviare le immagini modificate in variabili locali.

Passaggio 3: Separare i dati

Il 20% delle immagini pulite è per il training e l'altro 80% per i test. Il computer deve selezionare le immagini in modo casuale e non usarle nell'ordine esatto in cui sono state fornite dalla NASA. Per eseguire la separazione vengono usate due tecniche: la riorganizzazione e la selezione casuale.

Viene creato un elenco di indici che corrisponde al numero di immagini. Questo elenco viene utilizzato per trovare l'indice dell'immagine che rappresenta il 20% dei dati. Questa posizione viene archiviata in una variabile denominata split. L'elenco di indici viene riorganizzato e, usando il percorso dell'immagine in split, vengono creati i due set di dati per il training e il test. I set risultanti sono costituiti da immagini pulite e selezionate in modo casuale.

Viene usata la funzione load_split_train_test per ottenere i dati casuali per il training e il test.

Passaggio 4: Caricare set di dati casuali

Per caricare immagini casuali dai due set di dati, viene chiamata la funzione SubsetRandomSampler dalla libreria torch.utils.data.sampler. Verranno caricati esempi casuali di 16 immagini ognuno.

Aggiungere codice per pulire e separare i dati

Si è pronti ad aggiungere il codice per pulire e separare i dati.

  1. In Visual Studio Code tornare al file di Jupyter Notebook.

  2. Aggiungere il codice seguente in una nuova cella per importare la Python Imaging Library (PIL). Questa libreria verrà usata per visualizzare le immagini. Dopo aver aggiunto il nuovo codice, eseguire la cella.

    # Tell the machine what folder contains the image data
    data_dir = './Data'
    
    # Read the data, crop and resize the images, split data into two groups: test and train
    def load_split_train_test(data_dir, valid_size = .2):
    
        # Transform the images to train the model
        train_transforms = transforms.Compose([
                                           transforms.RandomResizedCrop(224),
                                           transforms.Resize(224),
                                           transforms.ToTensor(),
                                           ])
    
        # Transform the images to test the model
        test_transforms = transforms.Compose([transforms.RandomResizedCrop(224),
                                              transforms.Resize(224),
                                              transforms.ToTensor(),
                                          ])
    
        # Create two variables for the folders with the training and testing images
        train_data = datasets.ImageFolder(data_dir, transform=train_transforms)
        test_data = datasets.ImageFolder(data_dir, transform=test_transforms)
    
        # Get the number of images in the training folder
        num_train = len(train_data)
    
        # Create a list of numbers from 0 to the number of training images - 1
        # Example: For 10 images, the variable is the list [0,1,2,3,4,5,6,7,8,9]
        indices = list(range(num_train))
    
        # If valid_size is .2, find the index of the image that represents 20% of the data
        # If there are 10 images, a split would result in 2
        # split = int(np.floor(.2 * 10)) -> int(np.floor(2)) -> int(2) -> 2
        split = int(np.floor(valid_size * num_train))
    
        # Randomly shuffle the indices
        # For 10 images, an example would be that indices is now the list [2,5,4,6,7,1,3,0,9,8]
        np.random.shuffle(indices)
    
        from torch.utils.data.sampler import SubsetRandomSampler
    
        # With the indices randomly shuffled, 
        # grab the first 20% of the shuffled indices, and store them in the training index list
        # grab the remainder of the shuffled indices, and store them in the testing index list
        # Given our example so far, this would result is:
        # train_idx is the list [1,5] 
        # test_idx is the list [4,6,7,1,3,0,9,8]
        train_idx, test_idx = indices[split:], indices[:split]
    
        # Create samplers to randomly grab items from the training and testing indices lists
        train_sampler = SubsetRandomSampler(train_idx)
        test_sampler = SubsetRandomSampler(test_idx)
    
        # Create loaders to load 16 images from the train and test data folders
        # Images are chosen based on the shuffled index lists and by using the samplers
        trainloader = torch.utils.data.DataLoader(train_data, sampler=train_sampler, batch_size=16)
        testloader = torch.utils.data.DataLoader(test_data, sampler=test_sampler, batch_size=16)
    
        # Return the loaders so you can grab images randomly from the training and testing data folders
        return trainloader, testloader
    
    # Using the function that shuffles images,
    # create a trainloader to load 20% of the images
    # create a testloader to load 80% of the images
    trainloader, testloader = load_split_train_test(data_dir, .2)
    
    # Print the type of rocks that are included in the trainloader
    print(trainloader.dataset.classes)
    

Dopo aver eseguito la cella, nell'output dovrebbero essere visualizzati i due tipi di classificazione delle rocce: ['Basalt', 'Highland'].

I dati delle rocce spaziali vengono ora importati, puliti e separati. È ora possibile eseguire il training del modello con l'80% dei dati ed eseguire i test con il rimanente 20%.