五分钟内编写Pytorch模型

磐创AI 2022-06-14
1666 字丨阅读本文需 4 分钟

如果你想在五分钟内编写Pytorch模型,需要完成四个步骤:

1.导入和预处理(数据集)数据,并对其进行批处理(数据加载器)

2.使用神经网络建立模型。

3.编写一个训练循环并运行它。

4.验证集上的验证。

由于MNIST已经做得非常彻底,我们将介绍如何导入torchvision数据集,并在五分钟内编写一些代码。出于这个原因,它不会很漂亮,但会起作用。

下载和导入数据

因为MNIST已经做得很死了,我们将搜索标准的torchvision数据集,看看是否还有其他我们想要尝试和预测的东西。

让我们来看Kuzushiji MNIST,它是由70000张图像组成的MNIST数据集的平假名替代品。

首先,我们找到每个通道的平均值和标准偏差。这背后的原因是,我们希望对训练数据进行归一化,但Pytorch变换需要提前给出归一化平均值和标准偏差。因此,我们将使用数据集找到这些值,然后重新导入它,并用预定义的值传递一个归一化转换。

kmnist = datasets.KMNIST(data_path, train=True, download=True,
                      transform = transforms.Compose([
                          transforms.ToTensor()]))

kmnist_val = datasets.KMNIST(data_path, train=False, download=True,
                          transform = transforms.ToTensor())

请注意,kmnist是一个数据集,因此循环它会为我们提供每一个图像和每一个标签。因此,如果我们在数据集中的每个图像上循环,并沿着额外的第四维叠加它们,我们将得到所有图像的张量。

imgs = torch.stack([img_t for img_t, _ in kmnist], dim=3)

imgs.shape

>>> torch.Size([1, 28, 28, 60000])

现在我们计算每个通道的平均值。请注意,调用imgs.view(1,-1)将把所有的张量压缩到第二维度。我们在这个第二维度上取像素值的平均值(因此dim=1)和标准差。

# compute mean and std per channel

mean = imgs.view(1,-1).mean(dim=1)

std = imgs.view(1,-1).std(dim=1)

mean, std

>>> (tensor([0.1918]), tensor([0.3483]))

我们现在可以重新导入数据,使用Normalize转换以及将数组转换为张量。请注意,Normalize将像素值的平均值和标准偏差作为参数。

# normalised data

t_kmnist = datasets.KMNIST(data_path, train=True,
                                      download=False, transform=transforms.Compose([
                                          transforms.ToTensor(),
                                          transforms.Normalize((0.1307),
                                                               (0.3081))
                                      ]))

t_kmnist_val = datasets.KMNIST(data_path, train=False,
                                          download=False, transform=transforms.Compose([
                                              transforms.ToTensor()]))

现在我们有了数据集,我们需要将这些数据输入数据加载器进行批处理。如果你使用的是CPU,请确保设置较小的批处理大小,并将num_workers=1(这是一个GPU问题,不要太担心)。

train_loader = torch.utils.data.DataLoader(kmnist, batch_size=128,
                                          shuffle=True,
                                          num_workers=1)

val_loader = torch.utils.data.DataLoader(kmnist_val, batch_size=128,
                                        shuffle=False,
                                        num_workers=1)

我们可以从数据集中查看一些样本。

figure = plt.figure(figsize=(10, 8))

cols, rows = 5, 5

for i in range(1, cols * rows + 1):

     sample_idx = torch.randint(len(t_kmnist), size=(1,)).item()

     img, label = t_kmnist[sample_idx]

     figure.add_subplot(rows, cols, i)

     plt.title(label)

     plt.axis("off")

     plt.imshow(img.squeeze(), cmap="gray")

     plt.show()

构建模型

这不是一篇关于如何从理论上构建深度学习模型的教程。因此,我们将在这里介绍模型实现。

首先,需要将模型实例化为nn.Module的实例。其次,你需要使用常用的Python方法初始化类。最后,你需要一个模型初始化,在这里我们定义了所有的模型层,然后是一个forward方法,在这里我们告诉模型如何获取输入并将其传递给这些层。

class Net(nn.Module):

  def __init__(self):

      super(Net, self).__init__()

      self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5,
                              stride=1, padding=2)
              self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1,
                              padding=2)
              self.layer1 = nn.Sequential(self.conv1, nn.ReLU(), nn.MaxPool2d(kernel_size=2))
              self.layer2 = nn.Sequential(self.conv2, nn.ReLU(), nn.MaxPool2d(kernel_size=2))        
              self.out = nn.Linear(32*7*7, 10) # output 10 classes

      def forward(self, x):
              x = self.layer1(x)      

      x = self.layer2(x)      

     # flatten the output of conv2 to (batch_size, 32*7*7)      

      x = x.view(x.size(0), -1)
             output = self.out(x)
            return output

在这个阶段,通过从dataloader中给出一个示例来调试模型总是很重要的。然后,我们将该图像传递给模型,并检查它是否输出了正确大小的内容。

img, _ = next(iter(train_loader))

img = img[0]

model = Net()

model(img.unsqueeze(0)).shape

>>> torch.Size([1, 10])

完美的我们构建了一个模型,该模型采用K-MNIST图像,并输出10个类,代表每个可能的数字0到9的10种不同概率。

编写和运行训练循环像

往常一样,我们的训练步骤是相似的。前向传播,计算损失,重置梯度(Pytorch)。反向传播以计算有关损失的梯度。用这些梯度更新我们的权重。

def training_loop(n_epochs, model, loss_fn, optimiser, train_loader):

  model.train()  

  total_step = len(train_loader)

  for n in range(1, n_epochs+1):      

      for i, (imgs, labels) in enumerate(train_loader):
                      output = model(Variable(imgs)) # forward pass
                      loss = loss_fn(output, Variable(labels)) # compute loss
                      optimiser.zero_grad() # reset gradients
                      loss.backward() # backpropagation
                      optimiser.step() # update the weights
                      if (i+1) % (n_epochs/10) == 0:
                             print ('{} Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'

                     .format(datetime.datetime.now(), n, n_epochs,
                                  i + 1, total_step, loss.item()))

然后,我们实例化我们的模型,设置Adam优化器,并使用交叉熵损失(因为这是一个多类分类问题)。

model = Net()

optimiser = torch.optim.Adam(model.parameters(), lr=1e-2)

loss_fn = nn.CrossEntropyLoss()

然后把这些参数传递给训练循环。

training_loop(
         n_epochs = 10,
         model = model,  

  loss_fn = loss_fn,
         optimiser = optimiser,
         train_loader = train_loader

验证模型

迭代验证数据加载器中的图像和标签,前向传播,通过在输出张量中找到值最高的索引(记住,我们输出了10个概率的向量)得到预测。data.squeeze()以获取实际的标量本身。最后,统计预测值与标签相等的样本数量,除以标签总数。

def validate(model, train_loader, val_loader):      
        model.eval() # set to eval mode to avoid batchnorm
        with torch.no_grad(): # avoid calculating gradients
               correct, total = 0, 0
               for images, labels in val_loader:
                      test_output = model(images)
                      pred_y = torch.max(test_output, 1)[1].data.squeeze()
                      accuracy = (pred_y == labels).sum().item() / float(labels.size(0))
               print('VALIDATION SET ACCURACY: %.2f' % accuracy)
    validate(model, train_loader, val_loader)

>>> VALIDATION SET ACCURACY: 0.95

验证集准确率为95%。

结论

让模型变得更好:

· 在模型训练时打印验证集指标:显然,很高兴看到训练损失随着每个epoch而减少。但是,直到我们在训练后对模型进行验证,我们才真正了解模型的性能。如果在运行过程中打印验证准确性,你将更好地了解模型的成功。

· 早停:一旦验证的准确性在一定时期内(称为耐心)没有提高,就回到表现最好的epoch并使用这些权重。看看其他指标:例如曲线下面积(AUC)。

· 实现其他网络架构:自CNN引入以来,计算机视觉已经取得了长足的进步。你可以尝试其他体系结构来提高性能。

免责声明:凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处本网。非本网作品均来自其他媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如您发现有任何侵权内容,请依照下方联系方式进行沟通,我们将第一时间进行处理。

0赞 好资讯,需要你的鼓励
来自:磐创AI
0

参与评论

登录后参与讨论 0/1000

为你推荐

加载中...