Descripción de los módulos de datos PyTorch Lightning

PyTorch Lightning tiene como objetivo hacer que el código PyTorch sea más estructurado y legible, y eso no solo se limita al modelo PyTorch, sino también a los datos en sí. En PyTorch usamos DataLoaders para entrenar o probar nuestro modelo. Si bien podemos usar DataLoaders en PyTorch Lightning para entrenar el modelo también, PyTorch Lightning también nos brinda un mejor enfoque llamado DataModules. DataModule es una clase reutilizable y compartible que encapsula los cargadores de datos junto con los pasos necesarios para procesar los datos. La creación de cargadores de datos puede complicarse, por eso es mejor agrupar el conjunto de datos en forma de DataModule. Se recomienda que sepa cómo definir una red neuronal utilizando PyTorch Lightning .

Instalación de PyTorch Lightning:

La instalación de Lightning es igual que la de cualquier otra biblioteca en python.

pip install pytorch-lightning

O si desea instalarlo en un entorno conda, puede usar el siguiente comando:-

conda install -c conda-forge pytorch-lightning

Formato de módulo de datos Pytorch Lightning

Para definir un Lightning DataModule seguimos el siguiente formato:-

import pytorch-lightning as pl
from torch.utils.data import random_split, DataLoader

class DataModuleClass(pl.LightningDataModule):
    def __init__(self):
        #Define required parameters here
    
    def prepare_data(self):
        # Define steps that should be done
    # on only one GPU, like getting data.
    
    def setup(self, stage=None):
        # Define steps that should be done on 
    # every GPU, like splitting data, applying
    # transform etc.
    
    def train_dataloader(self):
        # Return DataLoader for Training Data here
    
    def val_dataloader(self):
        # Return DataLoader for Validation Data here
    
    def test_dataloader(self):
        # Return DataLoader for Testing Data here

Nota: Los nombres de las funciones anteriores deben ser exactamente iguales.

Comprender la clase DataModule

Para este artículo, usaré datos MNIST como ejemplo. Como podemos ver, el primer requisito para crear un Lightning DataModule es heredar la clase LightningDataModule en pytorch-lightning:

import pytorch-lightning as pl
from torch.utils.data import random_split, DataLoader

class DataModuleMNIST(pl.LightningDataModule):

Método __init__():

Se utiliza para almacenar información sobre el tamaño del lote, transformaciones, etc. 

def __init__(self):
    super().__init__()
    self.download_dir = ''
    self.batch_size = 32
    self.transform = transforms.Compose([
        transforms.ToTensor()
    ])

método prepare_data():

Este método se usa para definir los procesos que deben ser realizados por una sola GPU. Por lo general, se usa para manejar la tarea de descargar los datos. 

def prepare_data(self):
    datasets.MNIST(self.download_dir,
           train=True, download=True)
           
    datasets.MNIST(self.download_dir, train=False,        
           download=True)

método de instalación():

Este método se utiliza para definir el proceso que deben realizar todas las GPU disponibles. Por lo general, se usa para manejar la tarea de cargar los datos. 

def setup(self, stage=None):
    data = datasets.MNIST(self.download_dir,
             train=True, transform=self.transform)
             
    self.train_data, self.valid_data = random_split(data, [55000, 5000])
        
    self.test_data = datasets.MNIST(self.download_dir,
                        train=False, transform=self.transform)

método train_dataloader():

Este método se utiliza para crear un cargador de datos de datos de entrenamiento. En esta función, generalmente solo devuelve el cargador de datos de entrenamiento.

def train_dataloader(self):
    return DataLoader(self.train_data, batch_size=self.batch_size)

método val_dataloader():

Este método se utiliza para crear un cargador de datos de datos de validación. En esta función, generalmente solo devuelve el cargador de datos de datos de validación.

def val_dataloader(self):
   return DataLoader(self.valid_data, batch_size=self.batch_size)

método test_dataloader():

Este método se utiliza para crear un cargador de datos de prueba. En esta función, generalmente solo devuelve el cargador de datos de prueba.

def test_dataloader(self):
   return DataLoader(self.test_data, batch_size=self.batch_size)

Entrenamiento del modelo Pytorch Lightning usando DataModule:

En Pytorch Lighting, usamos Trainer() para entrenar nuestro modelo y en esto, podemos pasar los datos como DataLoader o DataModule. Usemos el modelo que definí en este artículo aquí como ejemplo:

class model(pl.LightningModule): 
    def __init__(self): 
        super(model, self).__init__() 
        self.fc1 = nn.Linear(28*28, 256) 
        self.fc2 = nn.Linear(256, 128) 
        self.out = nn.Linear(128, 10) 
        self.lr = 0.01
        self.loss = nn.CrossEntropyLoss() 
  
    def forward(self, x): 
        batch_size, _, _, _ = x.size() 
        x = x.view(batch_size, -1) 
        x = F.relu(self.fc1(x)) 
        x = F.relu(self.fc2(x)) 
        return self.out(x) 
  
    def configure_optimizers(self): 
        return torch.optim.SGD(self.parameters(), lr=self.lr) 
  
    def training_step(self, train_batch, batch_idx): 
        x, y = train_batch 
        logits = self.forward(x) 
        loss = self.loss(logits, y) 
        return loss 
  
    def validation_step(self, valid_batch, batch_idx): 
        x, y = valid_batch 
        logits = self.forward(x) 
        loss = self.loss(logits, y)

Ahora, para entrenar este modelo, crearemos un objeto Trainer() y lo ajustaremos() pasando nuestro modelo y módulos de datos como parámetros.

clf = model() 
mnist = DataModuleMNIST() 
trainer = pl.Trainer(gpus=1) 
trainer.fit(clf, mnist)

Debajo de la implementación completa:

Python3

# import module
import torch 
  
# To get the layers and losses for our model
from torch import nn 
import pytorch_lightning as pl 
  
# To get the activation function for our model
import torch.nn.functional as F 
  
# To get MNIST data and transforms
from torchvision import datasets, transforms
  
# To get the optimizer for our model
from torch.optim import SGD 
  
# To get random_split to split training
# data into training and validation data
# and DataLoader to create dataloaders for train, 
# valid and test data to be returned
# by our data module
from torch.utils.data import random_split, DataLoader 
  
class model(pl.LightningModule): 
    def __init__(self): 
        super(model, self).__init__() 
          
        # Defining our model architecture
        self.fc1 = nn.Linear(28*28, 256) 
        self.fc2 = nn.Linear(256, 128) 
        self.out = nn.Linear(128, 10) 
          
        # Defining learning rate
        self.lr = 0.01
          
        # Defining loss 
        self.loss = nn.CrossEntropyLoss() 
    
    def forward(self, x):
        
          # Defining the forward pass of the model
        batch_size, _, _, _ = x.size() 
        x = x.view(batch_size, -1) 
        x = F.relu(self.fc1(x)) 
        x = F.relu(self.fc2(x)) 
        return self.out(x) 
    
    def configure_optimizers(self):
        
          # Defining and returning the optimizer for our model
        # with the defines parameters
        return torch.optim.SGD(self.parameters(), lr = self.lr) 
    
    def training_step(self, train_batch, batch_idx): 
        
          # Defining training steps for our model
        x, y = train_batch 
        logits = self.forward(x) 
        loss = self.loss(logits, y) 
        return loss 
    
    def validation_step(self, valid_batch, batch_idx): 
        
        # Defining validation steps for our model
        x, y = valid_batch 
        logits = self.forward(x) 
        loss = self.loss(logits, y)
  
class DataModuleMNIST(pl.LightningDataModule):
    def __init__(self):
        super().__init__()
          
        # Directory to store MNIST Data
        self.download_dir = ''
          
        # Defining batch size of our data
        self.batch_size = 32
          
        # Defining transforms to be applied on the data
        self.transform = transforms.Compose([
            transforms.ToTensor()
        ])
  
    def prepare_data(self):
        
          # Downloading our data
        datasets.MNIST(self.download_dir, 
                       train = True, download = True)
          
        datasets.MNIST(self.download_dir,
                       train = False, download = True)
  
    def setup(self, stage=None):
        
          # Loading our data after applying the transforms
        data = datasets.MNIST(self.download_dir,
                              train = True, 
                              transform = self.transform)
          
        self.train_data, self.valid_data = random_split(data,
                                                        [55000, 5000])
  
        self.test_data = datasets.MNIST(self.download_dir,
                                        train = False,
                                        transform = self.transform)
  
    def train_dataloader(self):
        
          # Generating train_dataloader
        return DataLoader(self.train_data, 
                          batch_size = self.batch_size)
  
    def val_dataloader(self):
        
          # Generating val_dataloader
        return DataLoader(self.valid_data,
                          batch_size = self.batch_size)
  
    def test_dataloader(self):
        
        # Generating test_dataloader
        return DataLoader(self.test_data,
                          batch_size = self.batch_size)
  
clf = model() 
mnist = DataModuleMNIST() 
trainer = pl.Trainer()
trainer.fit(clf, mnist) 

Producción:

Publicación traducida automáticamente

Artículo escrito por herumbshandilya y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *