在 PyTorch 中从零开始创建神经网络!
1221
2022.09.16
2022.09.16
发布于 未知归属地

介绍

在本中,我将指导您在 pytorch 中从头开始创建一个简单的神经网络。这是一个实用教程。在接下来的教程中,我们将看到有关神经网络理论的更多细节。

客观的 :

本文的目标是学习如何在 pytorch 中创建神经网络并在数据集上对其进行训练。为此,我们将创建一个能够识别手写数字的模型。

要求

  • Python 与 PyTorch 一起安装。
  • 对神经网络理论和机器学习有基本的了解。
  • 基本的 Python 编程技能。

神经网络有什么用?

通常,神经网络用于基于一组标记数据来逼近数学函数。在经典编程中,我们必须有规则、输入并产生输出。相比之下,对于神经网络,我们有输入(数据)和输出(标签),并且通过优化程序,我们改变神经网络的参数,直到模型在数据集上得到很好的训练。

什么是PyTorch?

一个开源机器学习框架,可加速从研究原型设计到生产部署的路径。

PyTorch 是 Meta 开发的基于 Torch 的用于机器学习的开源 Python 库。PyTorch 允许执行深度学习所需的张量计算。请注意,PyTorch 不是我们可以用于机器学习的唯一库,还可以使用其他库,例如 keras & tensorflow、scikit-learn、theano...。

导入依赖

首先,让我们为我们的项目导入基本依赖项,在接下来的几行中,我将尝试解释这些依赖项的用途,我为每个模块提供的示例列表显然并不详尽:

  • torch:是创建张量的基本库,例如
  • torch.nn:是一个模块模块,它允许我们使用线性层、ReLU 和 Conv 层等层。
  • torch.optim:允许我们使用像 SGD 和 Adam 优化器这样的优化器。
  • torch.nn.functional:允许我们使用像 sigmoid 和 relu 这样的函数。
  • torchvision.transforms:使用将应用于数据的转换。
  • DataLoader:使用批处理加载数据集并对其应用转换。
  • torchvision.datasets:加载一些数据集,如 mnist
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torchvision.datasets as datasets

创建全连接网络

现在,让我们创建一个全连接网络,为此我们将首先创建一个名为neural_network的类,该类继承自nn.Module,我们继承自该父类以便能够使用一些方法,例如forward,基本上,当这个方法是定义后,当我们将模型应用于给定的输入 x 时,将直接调用它。

我们的类将 input_size 和 num_classes 作为输入,input_size 表示我们神经网络的输入数量,在我们的例子中,我们将使用大小为 28x28 的图像,因此 input_size 将等于 784。至于 num_classes 它将等于 10因为我们要预测从 0 到 9 的数字。

fc1表示第一层,我们使用一个Linear,输入数等于28x28=784,输出数等于50,然后fc2表示第二层,输入数等于前一层的输出,输出数等于num类(又名 10)。

# Create a fully connected network
class neural_network(nn.Module):
    def __init__(self, input_size, num_classes):
        super(neural_network, self).__init__()
        self.input_size = input_size
        self.num_classes = num_classes

        self.fc1 = nn.Linear(self.input_size, 50)
        self.fc2 = nn.Linear(50, self.num_classes)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        return F.sigmoid(self.fc2(x))

定义设备和超参数

当模型太复杂且数据集太大时,我们选择使用 GPU 而不是 CPU 来加快训练和优化过程。但是,我们想检查GPU是否可用,如果是我们可以使用它,如果没有,我们将使用CPU并避免错误:“cuda device is not available”。

# Define device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

GPU 比 CPU 更快的事实是由于 GPU 并行执行操作,这使得它们更适合处理图像、视频和信号。而 CPU 只执行串行计算。这并不意味着 GPU 比 CPU 更好。事实上,CPU 对于运行所有其他软件(如操作系统本身)很重要。

我们现在将定义训练神经网络所需的参数。input_size 参数表示输入层中神经元的数量。batch_size 表示我们每次训练神经网络的图像数量。learning_rate 表示梯度下降的步长。num_classes 表示类的数量。最后,num_epochs 是训练迭代次数。

# Hyperparameters
input_size = 28 * 28
batch_size = 64
learning_rate = 0.001
num_classes = 10
num_epochs = 20

定义数据增强

什么是数据增强,我们为什么需要它?

神经网络遇到的一些问题包括欠拟合和过拟合。当神经网络无法从训练数据集中学习必要的特征并且在训练数据集本身上产生低精度时,就会出现欠拟合。例如,这可能是因为训练数据集太大而 epoch 数太少。过拟合问题发生在神经网络熟记训练数据集时,这意味着模型在训练数据集上完美地工作(高精度),但在测试数据集上,模型表现不佳。这可能是因为训练数据集不足以使模型能够泛化新的看不见的数据。为了解决这个问题,我们可以尝试添加更多数据,但这通常具有挑战性。我们能做的,就是扩充数据,

# Data-augmentation
data_transforms = transforms.Compose(
    [transforms.ToTensor(),
    transforms.Resize(size=(28,28))]
)

有关 pytorch 中的数据增强和图像转换的更多详细信息,请参阅:PyTorch 转换

加载数据集

现在我们已经创建了模型,定义了必要的超参数和设备,是时候加载数据集了。在本教程中,我们将使用著名的 MNIST 数据集,该数据集包含从 0 到 9 的手写数字。我们的目标是建立一个能够区分这些数字的模型。

# Load dataset
train_data = datasets.MNIST(root='dataset/', download=True, train=True, transform=data_transforms)
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)

test_data = datasets.MNIST(root='dataset/', download=False, train=False, transform=transforms.ToTensor())
test_dataloader = DataLoader(dataset=test_data, batch_size=2, shuffle=False)

请注意,为了评估我们模型的性能,我们将数据集拆分为训练和测试数据。

定义模型

现在,我们将使用我们之前创建的类并定义模型。我们添加 .to(device) 以将模型参数移动到定义的设备,GPU 或 CPU。

# Define the model
model = neural_network(input_size, num_classes).to(device)

损失函数和优化器

在定义模型并加载数据集之后,我们现在定义优化器,它将优化我们的神经网络的参数。为此,我们将使用 Adam 优化器。对于损失函数,我们使用定义如下的交叉熵损失函数:

# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

训练模型

现在,一切都设置好了,我们将训练我们的模型并同时检查它在训练集和验证集上的准确性。

def check_accuracy(loader, model):
    if loader.dataset.train:
        print("Checking the accuracy on training dataset...")
    else:
        print("Checking the accuracy on validation dataset...")

    num_corrects = 0.0
    num_samples = 0.0

    model.eval()

    with torch.no_grad():
        for x, y in loader:
            x.to(device)
            y.to(device)
            x = x.reshape(x.shape[0], -1)
            predictions = model(x)
            _, predictions = predictions.max(1)
            num_corrects += (predictions == y).sum()
            num_samples += batch_size
        print(f"Got the following accuracy : {num_corrects / num_samples}")
    model.train()
for idx, (image, target) in enumerate(train_dataloader):
    # Move everything to device
    image = image.to(device)
    target = target.to(device)
    # Reshape
    image = image.reshape(image.shape[0], -1) # (64, 28*28)
    # predict 
    prediction = model(image) 
    # compute the loss
    loss = criterion(prediction, target)
    # update the parameters 
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    check_accuracy(test_dataloader, model)
评论 (0)