📜  使用 Pytorch Lightning 训练神经网络

📅  最后修改于: 2022-05-13 01:58:08.214000             🧑  作者: Mango

使用 Pytorch Lightning 训练神经网络

介绍:

PyTorch Lightning 是一个为 PyTorch 提供高级接口的库。 PyTorch 的问题在于,每次开始一个项目时,您都必须重写那些训练和测试循环。 PyTorch Lightning 不仅减少了样板代码,还提供了在训练神经网络时可能会派上用场的附加功能,从而解决了这个问题。我喜欢 Lightning 的一件事是代码非常有条理和可重用,不仅如此,它还减少了训练和测试循环,同时保留了 PyTorch 众所周知的灵活性。一旦你学会了如何使用它,你就会看到它的代码与 PyTorch 的代码有多相似。

安装 PyTorch 闪电:

安装 Lightning 与在Python安装任何其他库相同。

pip install pytorch-lightning

或者,如果您想在 conda 环境中安装它,您可以使用以下命令:-



conda install -c conda-forge pytorch-lightning

PyTorch 闪电模型格式:

如果你曾经使用过 PyTorch 你一定知道定义 PyTorch 模型遵循以下格式

from torch import nn

class model(nn.Module):
    def __init__(self):
        # Define Model Here
        
    def forward(self, x):
        # Define Forward Pass Here

这就是我们在 PyTorch 中定义模型的方式,在定义循环之后,我们通常在类外定义损失、优化器和训练。在 PyTorch Lightning 中,定义模型的方式类似,只是我们在模型本身中添加了损失、优化器和训练步骤。要定义闪电模型,我们遵循以下格式:-

import pytorch-lightning as pl

class model(pl.LightningModule):
    def __init__(self):
        # Define Model Here
        
    def forward(self, x):
        # Define Forward Pass Here
    
    def configure_optimizers(self):
       # Define Optimizer Here
       
    def training_step(self, train_batch, batch_idx):
        # Define Training loop steps here
        
    def validation_step(self, valid_batch, batch_idx):
        # Define Validation loop steps here

注意:上述函数的名称应完全相同。

训练我们的神经网络:

加载我们的数据:

在本教程中,我们将使用 MNIST 数据集,因此我们将首先加载我们的数据并在之后定义模型。要为 Lightning 模型加载数据,您可以像在 PyTorch 中一样定义 DataLoaders 并在 pl.Trainer()函数传递训练数据加载器和验证数据加载器,或者您可以使用 LightingDataModule 做同样的事情,除了现在您在Python执行这些步骤班级。要创建数据加载器,我们遵循以下步骤:-

通过创建 DataLoaders 加载数据:



from torchvision import datasets,transforms
from torch.utils.data import DataLoader

transform = transforms.Compose([
    transforms.ToTensor()
])

train = datasets.MNIST('',train = True, download = True, transform=transform)
test = datasets.MNIST('',train = False, download = True, transform=transform)

trainloader = DataLoader(train, batch_size= 32, shuffle=True)
testloader = DataLoader(test, batch_size= 32, shuffle=True)

要创建LightningDataModule,我们遵循以下步骤:-

通过创建 LightningDataModule 加载数据:

import pytorch-lightning as pl
from torchvision import datasets,transforms
from torch.utils.data import DataLoader

class Data(pl.LightningDataModule):
    def prepare_data(self):
        transform=transforms.Compose([
            transforms.ToTensor()
        ])
      
        self.train_data = datasets.MNIST('', train=True, download=True, transform=transform)
        self.test_data = datasets.MNIST('', train=False, download=True, transform=transform)

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

    def val_dataloader(self):
        return DataLoader(self.test_data, batch_size= 32, shuffle=True)

注意:上述函数的名称应完全相同。

这就是您创建闪电数据模块的方式。创建数据加载器可能会变得混乱,这就是为什么最好以数据模块的形式对数据集进行分组。

定义我们的神经网络

在 PyTorch 照明中定义模型与在 PyTorch 中定义模型几乎相同,除了现在我们将模型类中的所有内容都放在一起。

from torch import nn
import pytorch_lightning as pl
import torch.nn.functional as F
from torch.optim import SGD

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

我们将进一步讨论 training_step() 与 Pytorch 中训练循环中的步骤有何不同以及 Lightning 模型和 Pytorch 模型之间的其他差异。

训练我们的模型

要在 Pytorch 中训练模型,您首先必须编写训练循环,但 Lightning 中的 Trainer 类使任务更容易。在 Lightning 中训练模型:-

# Create Model Object
clf = model()
# Create Data Module Object
mnist = Data()
# Create Trainer Object
trainer = pl.Trainer(gpus=1,accelerator='dp',max_epochs=5)
trainer.fit(clf,mnist)

注意: `dp` 是 DataParallel(在同一台机器的 GPU 之间拆分批处理)。



注意:如果您通过创建数据加载器加载了数据,您可以通过trainer.fit(clf,trainloader,testloader)来拟合训练器。

PyTorch 模型和闪电模型的区别:

我们可以看到PyTorch和闪电模型之间的第一个区别是模型类继承的类:-

火炬

class model(nn.Module):

PyTorch -闪电

class model(pl.LightningModule):

__init__() 方法

Pytorch和 Lightning 模型中,我们使用 __init__() 方法来定义我们的层,因为在 Lightning 中,我们将所有东西放在一起,我们还可以定义其他超参数,例如优化器的学习率和损失函数。

火炬

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)

Pytorch-闪电

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

转发()方法:

Pytorch和 Lightning 模型中,我们都使用 forward() 方法来定义我们的前向传递,因此两者都是相同的。

PyTorchPyTorch -Lightning

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)

定义优化器:

PyTorch 中,我们通常通过直接创建对象来定义优化器,但在PyTorch -lightning 中,我们在configure_optimizers()方法下定义优化器。另一件要注意的事情是,在PyTorch 中,我们将模型对象参数作为优化器的参数传递,但在 Lightning 中,我们传递self.parameters(),因为类是模型本身。

火炬

from torch.optim import SGD
clf = model()    # Pytorch Model Object
optimizer = SGD(clf.parameters(),lr=0.01)

PyTorch -闪电

def configure_optimizers(self):
    return SGD(self.parameters(),lr = self.lr)

注意:您也可以在 Lightning 中创建多个优化器。

训练循环(步骤):

说这就是 Lightning 从PyTorch 中脱颖而出的原因并没有。在 PyTorch 中,我们定义了完整的训练循环,而在 Lightning 中,我们使用 Trainer() 来完成这项工作。但是我们仍然定义了训练时将要执行的步骤。

火炬

epochs = 5

for i in range(epochs):
    train_loss = 0.0
    for data,label in trainloader:
        if is_gpu:
            data, label = data.cuda(), label.cuda()
        output = model(data)
        optimizer.zero_grad()
        loss = criterion(output,label)
        loss.backward()
        optimizer.step()
        
        train_loss += loss.item() * data.size(0)
    print(f'Epoch: {i+1} / {epochs} \t\t\t Training Loss:{train_loss/len(trainloader)}')

PyTorch-闪电

def training_step(self, train_batch, batch_idx):
    x, y = train_batch
    logits = self.forward(x)
    loss = self.loss(logits,y)
    return loss


看看我们如何在训练步骤中只编写必要的步骤(粗体)。

代码

Python3
import torch
from torch import nn
import pytorch_lightning as pl
import torch.nn.functional as F
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
from torch.optim import SGD
  
  
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)
  
  
class Data(pl.LightningDataModule):
    def prepare_data(self):
        transform = transforms.Compose([
            transforms.ToTensor()
        ])
  
        self.train_data = datasets.MNIST(
            '', train=True, download=True, transform=transform)
        self.test_data = datasets.MNIST(
            '', train=False, download=True, transform=transform)
  
    def train_dataloader(self):
        return DataLoader(self.train_data, batch_size=32, shuffle=True)
  
    def val_dataloader(self):
        return DataLoader(self.test_data, batch_size=32, shuffle=True)
  
  
clf = model()
mnist = Data()
trainer = pl.Trainer(gpus=1, accelerator='dp', max_epochs=5)
trainer.fit(clf, mnist)