📜  在PyTorch中使用Logistic逻辑回归识别手写数字

📅  最后修改于: 2020-04-29 01:00:46             🧑  作者: Mango

Logistic逻辑回归是一种非常常用的统计方法,它使我们能够根据一组自变量来预测二进制输出。先前已在本文介绍了逻辑回归的各种属性及其Python实现。现在,我们将了解如何在PyTorch中实现这一点,PyTorch是Facebook正在开发的一种非常流行的深度学习库。
现在,我们将看到如何使用PyTorch中的Logistic回归对MNIST数据集中的手写数字进行分类。首先,您需要将PyTorch安装到Python环境中。最简单的方法是使用pipconda工具。访问pytorch.org并安装您想要使用的Python解释器和程序包管理器的版本。
安装了PyTorch之后,现在让我们看一下代码。编写下面给出的三行代码,以导入所需的库函数和对象。

import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.autograd import Variable

此处,torch.nn模块包含该模型所需的代码,torchvision.datasets包含MNIST数据集。它包含我们将在此处使用的手写数字数据集。该torchvision.transforms模块包含的对象转换成其他各种方法。在这里,我们将使用它从图像转换为PyTorch张量。另外,torch.autograd模块除其他外还包含Variable类,我们将在定义张量时使用该类。
接下来,我们将下载数据集并将其加载到内存中。

# MNIST数据集(图像和标签)
train_dataset = dsets.MNIST(root ='./data',
                            train = True,
                            transform = transforms.ToTensor(),
                            download = True)
test_dataset = dsets.MNIST(root ='./data',
                           train = False,
                           transform = transforms.ToTensor())
# 数据集加载器(输入点线)
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
                                           batch_size = batch_size,
                                           shuffle = True)
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
                                          batch_size = batch_size,
                                          shuffle = False)

现在,我们将定义超级参数。

# 超级参数
input_size = 784
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001

在我们的数据集中,图片尺寸为28 * 28。因此,我们的输入大小为784。此外,其中还有10位数字,因此,我们可以有10个不同的输出。因此,我们将num_classes设置为10。此外,我们将在整个数据集上训练五次。最后,我们将分小批训练每个图像100张,以防止由于内存溢出而导致程序崩溃。

此后,我们将定义如下模型。在这里,我们将模型初始化为torch.nn.Module的子类,然后定义正向传递。在我们编写的代码中,softmax是在每次前向传递期间内部计算的,因此我们不需要在forward()函数中指定它。

class LogisticRegression(nn.Module):
    def __init__(self, input_size, num_classes):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, num_classes)
    def forward(self, x):
        out = self.linear(x)
        return out

定义了类之后,现在我们为该对象实例化一个对象。

model = LogisticRegression(input_size, num_classes)

接下来,我们设置损失函数和优化器。在这里,我们将使用交叉熵损失,而对于优化器,我们将使用随机梯度下降算法,其学习速率为0.001,如上面的hyper参数所定义。

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = learning_rate)

现在,我们将开始培训。在这里,我们将执行以下任务:

  1. 将所有梯度重置为0。
  2. 前向传播。
  3. 计算损失。
  4. 执行反向传播。
  5. 更新所有权重。
    # 训练模型
    for epoch in range(num_epochs):
        for i, (images, labels) in enumerate(train_loader):
            images = Variable(images.view(-1, 28 * 28))
            labels = Variable(labels)
            # 前向传播 + 计算损失 + 反向传播
            optimizer.zero_grad()
            outputs = model(images)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            if (i + 1) % 100 == 0:
                print('Epoch: [% d/% d], Step: [% d/% d], Loss: %.4f'
                      % (epoch + 1, num_epochs, i + 1,
                         len(train_dataset) // batch_size, loss.data[0]))

最后,我们将使用以下代码测试模型。

# 测试模型
correct = 0
total = 0
for images, labels in test_loader:
    images = Variable(images.view(-1, 28 * 28))
    outputs = model(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum()
print('Accuracy of the model on the 10000 test images: % d %%' % (
            100 * correct / total))

假设您正确执行了所有步骤,您将获得82%的准确度,与使用一种特殊类型的神经网络结构的当今最新模型相距甚远。供您参考,您可以在下面找到本文的完整代码:

import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.autograd import Variable
# MNIST数据集(图像和标签)
train_dataset = dsets.MNIST(root ='./data',
                            train = True,
                            transform = transforms.ToTensor(),
                            download = True)
test_dataset = dsets.MNIST(root ='./data',
                           train = False,
                           transform = transforms.ToTensor())
# 数据集加载器(输入点线)
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
                                           batch_size = batch_size,
                                           shuffle = True)
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
                                          batch_size = batch_size,
                                          shuffle = False)
# 超级参数
input_size = 784
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001
# 模型
class LogisticRegression(nn.Module):
    def __init__(self, input_size, num_classes):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, num_classes)
    def forward(self, x):
        out = self.linear(x)
        return out
model = LogisticRegression(input_size, num_classes)
# 损失与优化
# Softmax是内部计算的.
# 设置要更新的参数.
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = learning_rate)
# 训练模型
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        images = Variable(images.view(-1, 28 * 28))
        labels = Variable(labels)
        # 前向传播 + 计算损失 + 反向传播
        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        if (i + 1) % 100 == 0:
            print('Epoch: [% d/% d], Step: [% d/% d], Loss: %.4f'
                  % (epoch + 1, num_epochs, i + 1,
                     len(train_dataset) // batch_size, loss.data[0]))
# 测试模型
correct = 0
total = 0
for images, labels in test_loader:
    images = Variable(images.view(-1, 28 * 28))
    outputs = model(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum()
print('Accuracy of the model on the 10000 test images: % d %%' % (
            100 * correct / total))