Exercício – Importar e limpar dados das fotos

Concluído

Agora que sabemos como limpar e separar os dados, podemos aplicar de fato esses princípios ao nosso projeto de classificação de rochas.

Preparar os dados

Precisamos criar dois conjuntos de dados com base nas fotos da NASA para o nosso projeto de classificação. Um conjunto de dados é para treinamento e o outro é para teste. As imagens precisam ser limpas e separadas antes de serem carregadas em conjuntos de dados para processamento. Os dados devem ser processados de maneira aleatória e não na ordem exata em que foram fornecidos pela NASA.

Usaremos código para executar essas quatro etapas a fim de preparar nossos dados:

  • Etapa 1. Obter os dados: informe ao computador em que local obter os dados de imagem.
  • Etapa 2. Limpar os dados: cortar as imagens para deixá-las do mesmo tamanho.
  • Etapa 3. Separar os dados: separe os dados com o embaralhamento e a seleção aleatória.
  • Etapa 4. Carregar conjuntos de dados aleatórios: prepare amostras aleatórias para treinar e testar os conjuntos de dados.

Etapa 1: Obter os dados

Precisamos informar ao computador em que local ele pode encontrar os dados. Em nosso exemplo, usamos as imagens de rochas fornecidas pela NASA. Já baixamos e armazenamos as fotos na pasta Dados que está na mesma pasta de projeto que o nosso arquivo do Jupyter notebook. Vamos dizer ao computador para carregar os dados de imagem da pasta Dados.

Etapa 2: Limpar os dados

As fotos de rochas da NASA vêm em tamanhos diferentes: pequenas, médias e grandes. Vamos cortar as imagens para que elas fiquem do mesmo tamanho (224 x 224 pixels). Redimensionamos as imagens porque os computadores esperam que elas sejam do mesmo tamanho. Se as imagens variam em tamanho, elas não são tão fáceis para o computador processar. Usamos a classe torchvision transforms.Compose para redimensionar as imagens com as dimensões desejadas e armazenar as imagens modificadas em variáveis locais.

Etapa 3: Separar os dados

20% das imagens limpas são para treinamento e os 80% restantes são para testes. O computador deve escolher imagens aleatoriamente e não usá-las na ordem exata em que foram fornecidas pela NASA. Usamos duas técnicas para fazer a separação: embaralhamento e seleção aleatória.

Criamos uma lista de índice que corresponde ao número de imagens. Usamos essa lista para localizar o índice da imagem que representa 20% dos dados. Armazenamos esse local em uma variável chamada split. Vamos embaralhar a lista de índices e, usando o local da imagem em split, criamos nossos dois conjuntos de dados para treinamento e para testes. Os conjuntos resultantes consistem em imagens que são limpas e são selecionadas aleatoriamente.

Usamos a função load_split_train_test a fim de obter os dados embaralhados para treinamento e testes.

Etapa 4: Carregar conjuntos de dados aleatórios

Para carregar imagens aleatórias por meio de nossos dois conjuntos de dados, chamamos a função SubsetRandomSampler da biblioteca torch.utils.data.sampler. Carregaremos amostras aleatórias de 16 imagens cada.

Adicionar código para limpar e separar os dados

Estamos prontos para adicionar código a fim de limpar e separar os dados.

  1. No Visual Studio Code, retorne ao arquivo do Jupyter Notebook.

  2. Adicione o código a seguir em uma nova célula para importar a PIL (Python Imaging Library). Usaremos essa biblioteca para visualizar as imagens. Depois de adicionar o novo código, execute a célula.

    # 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)
    

Depois de executar a célula, você deverá ver os dois tipos de classificação de rocha na saída: ['Basalt', 'Highland'].

Agora os dados de rochas espaciais estão importados, limpos e separados. Estamos prontos para treinar nosso modelo com 80% dos dados e executar testes com os 20% restantes.