Python 深度学习框架 PyTorch 入门:构建简单神经网络

一、引言

在当今的科技领域,深度学习无疑是一颗耀眼的明星,它在图像识别、自然语言处理、语音识别、医疗诊断、金融预测等众多领域都取得了令人瞩目的成果,彻底改变了我们处理数据和解决复杂问题的方式。而深度学习框架作为实现深度学习算法的重要工具,其重要性不言而喻。

PyTorch 就是这样一款备受青睐的深度学习框架。它由 Facebook AI Research 团队开发并开源,以其独特的优势在深度学习领域迅速崛起,吸引了大量研究人员和开发者的关注。PyTorch 的动态计算图机制使得模型的构建和调试变得更加直观和灵活,就像是搭建积木一样,开发者可以根据自己的需求轻松地组合和调整各个组件。同时,它与 Python 语言的无缝集成,使得熟悉 Python 的开发者能够快速上手,将更多的精力投入到模型的设计和优化中,而不是花费大量时间去学习复杂的框架语法。此外,PyTorch 还拥有强大的 GPU 加速能力,能够显著缩短模型的训练时间,使得在处理大规模数据集和复杂模型时变得高效可行。不仅如此,其活跃的社区也为开发者提供了丰富的资源,包括大量的教程、文档以及开源项目,方便开发者在遇到问题时能够快速找到解决方案,不断推动深度学习技术的发展和应用。

在本文中,我们将踏上 PyTorch 的学习之旅,逐步探索如何使用它来构建简单的神经网络。我们会从 PyTorch 的基础知识开始,了解张量这一核心数据结构以及相关的运算操作,接着深入到构建神经网络的基本流程,包括网络结构的定义、损失函数和优化器的选择,最后通过一个具体的实战项目 ——MNIST 手写数字分类,将所学知识应用到实际中,亲身体验使用 PyTorch 构建和训练神经网络的全过程。通过本文的学习,希望读者能够对 PyTorch 有一个全面而深入的了解,掌握构建简单神经网络的技能,为进一步探索深度学习的奥秘打下坚实的基础。

二、PyTorch 基础知识

2.1 张量(Tensor)

2.1.1 张量的概念

张量是 PyTorch 中的基本数据结构,它可以看作是多维数组的一种扩展。在深度学习中,我们通常会处理各种维度的数据,例如图像数据可以表示为三维张量(高度、宽度、通道数),如果考虑一个包含多个图像的数据集,那么它可以被表示为四维张量(样本数、高度、宽度、通道数)。与 NumPy 中的数组类似,张量也支持多种数据类型,如整数、浮点数等,但张量具有更强大的功能,它能够在 GPU 上进行高效计算,这对于深度学习中大规模数据的处理和复杂模型的训练至关重要。

2.1.2 张量的创建

在 PyTorch 中,创建张量有多种方式,以下是一些常见的方法:

直接从数据创建:可以通过torch.tensor()函数直接将 Python 列表或 NumPy 数组转换为张量。例如:


import torch

data = [[1.0, 2.0], [3.0, 4.0]]

tensor_from_list = torch.tensor(data)

print(tensor_from_list)

上述代码将 Python 列表data转换为了一个二维张量并打印输出。

2. 创建特定形状的张量

全零张量:使用torch.zeros()函数创建全零张量。例如,创建一个形状为 (3, 4) 的全零张量:


zero_tensor = torch.zeros(3, 4)

print(zero_tensor)

全一张量:通过torch.ones()函数创建全一张量。如创建一个形状为 (2, 5) 的全一张量:


one_tensor = torch.ones(2, 5)

print(one_tensor)

随机初始化张量:利用torch.rand()函数可以创建一个在 0 到 1 之间均匀分布的随机张量。比如创建一个形状为 (4, 3) 的随机张量:


rand_tensor = torch.rand(4, 3)

print(rand_tensor)

从已有张量创建:可以基于已有的张量创建新的张量,新张量会继承原张量的一些属性,如数据类型等。例如,使用torch.zeros_like()函数创建与给定张量形状相同的全零张量:


original_tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]])

zero_like_tensor = torch.zeros_like(original_tensor)

print(zero_like_tensor)

2.1.3 张量的属性

张量具有一些重要的属性,了解这些属性有助于我们更好地使用和操作张量。

形状(Shape):通过张量的shape属性可以获取其维度信息。例如:


tensor = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])

print(tensor.shape)

输出结果为torch.Size([2, 3]),表示该张量是一个二维张量,第一维大小为 2,第二维大小为 3。

2. 数据类型(Dtype):使用dtype属性可以查看张量的数据类型。例如:


tensor = torch.tensor([1, 2, 3], dtype=torch.float32)

print(tensor.dtype)

这里输出的是torch.float32,表示该张量的数据类型为 32 位浮点数。在深度学习中,选择合适的数据类型对于模型的性能和内存使用有一定影响,通常在处理图像等数据时,会使用torch.float32类型。

3. 设备(Device):张量可以存储在不同的设备上,如 CPU 或 GPU。通过device属性可以查看张量所在的设备。在使用 GPU 加速计算时,我们需要将张量和模型移动到 GPU 设备上。例如:


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

tensor = torch.tensor([1.0, 2.0, 3.0]).to(device)

print(tensor.device)

上述代码首先检查是否有可用的 GPU 设备,如果有则将设备设置为cuda,否则设置为cpu,然后将张量移动到相应的设备上并打印其所在设备。

2.2 张量运算

PyTorch 支持丰富多样的张量运算,这些运算为深度学习中的各种操作提供了基础。

算术运算:包括加、减、乘、除等基本算术运算。例如:


tensor1 = torch.tensor([1.0, 2.0, 3.0])

tensor2 = torch.tensor([4.0, 5.0, 6.0])

add_result = tensor1 + tensor2

sub_result = tensor1 - tensor2

mul_result = tensor1 * tensor2

div_result = tensor1 / tensor2

print("加法结果:", add_result)

print("减法结果:", sub_result)

print("乘法结果:", mul_result)

print("除法结果:", div_result)

上述代码分别对两个一维张量进行了加、减、乘、除运算,并打印出结果。这些运算都是逐元素进行的,即对应位置的元素进行相应的运算。

2. 矩阵运算:在深度学习中,矩阵乘法是非常常见且重要的运算。PyTorch 中使用torch.mm()函数进行矩阵乘法。例如:


matrix1 = torch.tensor([[1.0, 2.0], [3.0, 4.0]])

matrix2 = torch.tensor([[5.0, 6.0], [7.0, 8.0]])

matmul_result = torch.mm(matrix1, matrix2)

print("矩阵乘法结果:", matmul_result)

这里定义了两个二维矩阵matrix1和matrix2,通过torch.mm()函数进行矩阵乘法运算并输出结果。需要注意的是,矩阵乘法的维度要求是前一个矩阵的列数等于后一个矩阵的行数。

3. 逐元素操作:除了基本的算术运算外,还有许多逐元素的函数操作,如计算张量中每个元素的平方根、指数、对数等。例如,计算张量中每个元素的平方根可以使用torch.sqrt()函数:


tensor = torch.tensor([4.0, 9.0, 16.0])

sqrt_result = torch.sqrt(tensor)

print("平方根结果:", sqrt_result)

上述代码对张量中的每个元素计算平方根并打印结果。类似的逐元素操作函数还有torch.exp()(计算指数)、torch.log()(计算自然对数)等,这些函数在深度学习中的激活函数、损失函数等计算中经常会用到。

4. 聚合操作:聚合操作是对张量的元素进行汇总计算,得到一个标量或低维张量。常见的聚合操作有求和、求均值、求最大值等。例如:

求和:使用torch.sum()函数对张量元素求和。例如:


tensor = torch.tensor([1.0, 2.0, 3.0, 4.0])

sum_result = torch.sum(tensor)

print("求和结果:", sum_result)

求均值:通过torch.mean()函数计算张量元素的均值。如:


mean_result = torch.mean(tensor)

print("均值结果:", mean_result)

求最大值:利用torch.max()函数可以找到张量中的最大值及其索引。例如:


max_value, max_index = torch.max(tensor, dim=0)

print("最大值:", max_value)

print("最大值索引:", max_index)

这里dim=0表示在维度 0 上进行操作,对于一维张量,就是在整个张量上进行操作。如果是多维张量,可以根据需要指定在哪个维度上进行聚合操作。

2.3 自动求导

在深度学习中,反向传播算法是计算梯度并更新模型参数的关键步骤,而自动求导则是实现反向传播的重要手段。PyTorch 的autograd模块为我们提供了强大的自动求导功能。

启用自动求导:要让张量参与自动求导,只需在创建张量时将requires_grad参数设置为True。例如:


x = torch.tensor([2.0, 3.0], requires_grad=True)

print(x.requires_grad)

上述代码创建了一个一维张量x,并将requires_grad设置为True,打印结果为True,表示该张量会自动跟踪其计算历史,以便后续进行梯度计算。

2. 计算梯度:当我们对具有requires_grad=True的张量进行一系列运算后,可以通过调用backward()方法来计算梯度。例如,定义一个简单的函数y = x^2,并计算y关于x的梯度:


x = torch.tensor([2.0, 3.0], requires_grad=True)

y = x ** 2

y.backward(torch.tensor([1.0, 1.0]))

print(x.grad)

在上述代码中,首先计算了y = x^2,然后调用y.backward()方法计算梯度。由于y是一个张量,在调用backward()时需要传入一个与y形状相同的张量作为梯度的 “种子”,这里传入了torch.tensor([1.0, 1.0])。计算完成后,x.grad中就保存了y关于x的梯度值,对于y = x^2,其梯度为2x,因此输出结果为tensor([4., 6.])。

3. 计算图与自动求导:在 PyTorch 中,当启用自动求导后,对张量的每一步运算都会构建一个计算图。计算图记录了张量之间的运算关系,在反向传播过程中,根据这个计算图从最终的输出张量开始,按照链式法则自动计算每个参与运算的张量的梯度。这种动态计算图机制使得 PyTorch 的自动求导非常灵活,能够适应各种复杂的模型结构和运算。例如,对于一个包含多个层和非线性激活函数的神经网络,在正向传播过程中,输入数据通过各个层的运算得到最终输出,这个过程构建了计算图;在反向传播时,根据计算图自动计算每个参数的梯度,以便更新模型参数。

自动求导功能极大地简化了深度学习中梯度计算的过程,让开发者无需手动推导复杂的梯度公式,专注于模型的设计和训练,提高了开发效率和模型实现的准确性。

三、构建神经网络的基本流程

3.1 定义网络结构

在 PyTorch 中,构建神经网络需要继承torch.nn.Module类,这是 PyTorch 中所有神经网络模块的基类。通过继承这个类并实现__init__和forward方法,我们可以定义自己的网络结构。

创建一个简单的全连接神经网络


import torch

import torch.nn as nn

class SimpleNet(nn.Module):

def __init__(self, input_size, hidden_size1, hidden_size2, output_size):

super(SimpleNet, self).__init__()

self.fc1 = nn.Linear(input_size, hidden_size1)

self.relu1 = nn.ReLU()

self.fc2 = nn.Linear(hidden_size1, hidden_size2)

self.relu2 = nn.ReLU()

self.fc3 = nn.Linear(hidden_size2, output_size)

def forward(self, x):

out = self.fc1(x)

out = self.relu1(out)

out = self.fc2(out)

out = self.relu2(out)

out = self.fc3(out)

return out

在上述代码中,我们定义了一个名为SimpleNet的类,它继承自nn.Module。

__init__方法:在__init__方法中,我们定义了网络的各个层。这里使用了全连接层(nn.Linear),全连接层是神经网络中最基本的层之一,它将输入的每个神经元与下一层的每个神经元都进行连接。self.fc1 = nn.Linear(input_size, hidden_size1)定义了第一个全连接层,将输入大小为input_size的张量映射到大小为hidden_size1的隐藏层。接着使用了 ReLU 激活函数(nn.ReLU),self.relu1 = nn.ReLU(),ReLU 函数能够为神经网络引入非线性,使得模型能够学习到更复杂的模式。随后又定义了第二个全连接层self.fc2 = nn.Linear(hidden_size1, hidden_size2)和对应的 ReLU 激活函数self.relu2 = nn.ReLU(),以及最后一个全连接层self.fc3 = nn.Linear(hidden_size2, output_size),将隐藏层输出映射到最终的输出大小为output_size。

forward方法:forward方法定义了数据在网络中的前向传播过程。输入数据x首先通过第一个全连接层self.fc1,然后经过 ReLU 激活函数self.relu1,接着依次通过第二个全连接层、ReLU 激活函数以及第三个全连接层,最终返回输出结果。在 PyTorch 中,当我们调用模型实例对输入数据进行预测时,实际上就是调用了这个forward方法。

网络结构的灵活性:通过这种方式定义网络结构,我们可以非常灵活地构建各种不同架构的神经网络。例如,如果想要增加或减少隐藏层的数量,只需要在__init__方法中相应地添加或删除全连接层和激活函数的定义,并在forward方法中调整数据的传播路径即可。同时,我们还可以根据不同的任务需求,选择合适的输入大小、隐藏层大小和输出大小,以适应不同的数据特征和问题复杂度。

3.2 选择损失函数和优化器

损失函数

交叉熵(Cross – Entropy)损失函数:交叉熵损失函数在分类任务中广泛应用,特别是在多分类问题中。它结合了 softmax 激活函数和负对数似然损失,能够直接衡量预测的概率分布与真实标签的概率分布之间的差异。在 PyTorch 中,对于多分类问题,常用nn.CrossEntropyLoss()来计算交叉熵损失,该函数会自动对输入进行 softmax 操作并计算损失。例如:


import torch

import torch.nn as nn

# 假设模型输出的logits(未经过softmax的原始分数)

logits = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])

# 假设真实标签

labels = torch.tensor([2, 0])

criterion = nn.CrossEntropyLoss()

loss = criterion(logits, labels)

print("交叉熵损失值:", loss.item())

上述代码中,logits是模型输出的未经过 softmax 处理的分数,labels是真实标签,通过nn.CrossEntropyLoss()计算两者之间的交叉熵损失。在实际应用中,分类任务的模型输出通常会经过nn.CrossEntropyLoss()来计算损失,以优化模型的分类性能。

2. 优化器:优化器的作用是根据损失函数计算出的梯度,更新模型的参数,以最小化损失函数,从而使模型的预测结果更接近真实标签。PyTorch 提供了多种优化器,不同的优化器适用于不同的场景和模型。

随机梯度下降(SGD):随机梯度下降是最基础的优化器之一,它根据每次计算的小批量数据的梯度来更新参数。在 PyTorch 中,可以使用torch.optim.SGD()来创建 SGD 优化器实例。例如:


import torch

import torch.nn as nn

import torch.optim as optim

# 定义一个简单的模型

class SimpleModel(nn.Module):

def __init__(self):

super(SimpleModel, self).__init__()

self.fc = nn.Linear(10, 1)

def forward(self, x):

return self.fc(x)

model = SimpleModel()

# 定义优化器,学习率设置为0.01

optimizer = optim.SGD(model.parameters(), lr=0.01)

在上述代码中,我们定义了一个简单的全连接模型SimpleModel,然后使用torch.optim.SGD()创建了一个 SGD 优化器实例optimizer,并将模型的参数model.parameters()和学习率lr=0.01传递给它。学习率决定了每次参数更新的步长,学习率过大可能导致模型无法收敛甚至发散,学习率过小则会使训练过程变得缓慢。

Adam 优化器:Adam 优化器是一种自适应学习率的优化算法,它结合了动量(Momentum)和 RMSProp 算法的优点,能够在训练过程中自动调整学习率,在许多情况下表现出色,是目前应用较为广泛的优化器之一。在 PyTorch 中,使用torch.optim.Adam()来创建 Adam 优化器。例如:


import torch

import torch.nn as nn

import torch.optim as optim

# 定义模型

model = nn.Sequential(

nn.Linear(10, 20),

nn.ReLU(),

nn.Linear(20, 1)

)

# 定义Adam优化器,学习率设置为0.001

optimizer = optim.Adam(model.parameters(), lr=0.001)

这里定义了一个包含两个全连接层和一个 ReLU 激活函数的模型,然后通过torch.optim.Adam()创建了 Adam 优化器,并设置学习率为0.001。在实际训练中,我们可以根据模型的训练情况,适时调整优化器的参数,如学习率,以达到更好的训练效果。

3.3 数据处理与加载

数据预处理:在将数据输入到神经网络进行训练之前,通常需要对数据进行预处理。数据预处理的目的是将数据转换为适合模型输入的格式,并对数据进行标准化、归一化等操作,以提高模型的训练效果和收敛速度。

标准化:标准化是将数据的特征值转换为具有零均值和单位方差的形式。在 PyTorch 中,可以使用torchvision.transforms.Normalize()来对图像数据进行标准化。例如,对于图像数据,常见的标准化操作是将每个通道的像素值减去均值并除以标准差:


import torchvision.transforms as transforms

# 定义标准化操作,假设图像数据的均值和标准差

transform = transforms.Compose([

transforms.ToTensor(),

transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))

])

上述代码中,transforms.Compose()用于组合多个数据转换操作,首先将数据转换为张量(transforms.ToTensor()),然后使用transforms.Normalize()对数据进行标准化,这里假设图像数据的每个通道的均值和标准差均为0.5。

归一化:归一化是将数据的特征值映射到指定的范围内,常见的是将数据映射到 [0, 1] 或 [-1, 1] 之间。对于图像数据,可以通过简单的除法操作实现归一化,例如将像素值除以 255,将其映射到 [0, 1] 范围内:


import torchvision.transforms as transforms

transform = transforms.Compose([

transforms.ToTensor(),

transforms.Lambda(lambda x: x / 255.0)

])

这里使用transforms.Lambda()自定义了一个转换函数,将张量中的每个元素除以 255.0,实现归一化。

2. 数据加载:在深度学习中,通常会处理大规模的数据集,为了高效地加载和处理数据,PyTorch 提供了torch.utils.data模块,其中的Dataset类和DataLoader类是数据加载的核心组件。

自定义数据集类:我们可以通过继承torch.utils.data.Dataset类来自定义数据集。例如,对于一个简单的图像数据集,假设图像存储在一个文件夹中,标签存储在一个文本文件中,我们可以这样定义数据集类:


import torch

from torch.utils.data import Dataset

from PIL import Image

import os

class CustomImageDataset(Dataset):

def __init__(self, img_dir, label_file, transform=None):

self.img_dir = img_dir

self.labels = []

self.transform = transform

with open(label_file, 'r') as f:

for line in f.readlines():

img_name, label = line.strip().split()

self.labels.append(int(label))

def __len__(self):

return len(self.labels)

def __getitem__(self, idx):

img_path = os.path.join(self.img_dir, f"{idx}.jpg")

image = Image.open(img_path).convert('RGB')

if self.transform:

image = self.transform(image)

label = torch.tensor(self.labels[idx])

return image, label

在上述代码中,CustomImageDataset类继承自Dataset类,__init__方法用于初始化数据集,读取标签文件并存储标签;__len__方法返回数据集的大小;__getitem__方法根据索引获取图像和对应的标签,并对图像进行预处理(如果有定义transform)。

使用 DataLoader 加载数据:DataLoader类用于将数据集包装成可迭代的对象,并可以设置批量大小、是否打乱数据等参数。例如:


from torch.utils.data import DataLoader

# 创建自定义数据集实例

dataset = CustomImageDataset(img_dir='path/to/images', label_file='path/to/labels.txt', transform=transform)

# 创建DataLoader实例,批量大小设置为32,打乱数据

dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

通过DataLoader,我们可以方便地按批次加载数据,在训练模型时进行迭代:


for batch_images, batch_labels in dataloader:

# 在这里进行模型的训练操作

pass

这样就可以在每次迭代中获取一个批次的图像数据和对应的标签,用于模型的训练和优化。

四、实战项目:MNIST 手写数字分类

4.1 项目介绍

MNIST 数据集是深度学习领域中非常经典的数据集,它由 60,000 张训练图像和 10,000 张测试图像组成,每张图像都是一个手写数字(0 – 9),图像大小为 28×28 像素,是灰度图像。我们的目标是使用 PyTorch 构建一个简单的神经网络,对 MNIST 数据集中的手写数字进行分类,通过这个实战项目,将前面所学的 PyTorch 知识应用到实际中,加深对构建神经网络流程的理解。

4.2 数据准备

数据下载与加载:PyTorch 的torchvision.datasets模块提供了方便的函数来下载和加载 MNIST 数据集。同时,我们可以使用torchvision.transforms模块对数据进行预处理。例如:


import torchvision

import torchvision.transforms as transforms

# 定义数据预处理操作,将数据转换为张量并归一化

transform = transforms.Compose([

transforms.ToTensor(),

transforms.Normalize((0.1307,), (0.3081,))

])

# 下载并加载训练数据集

trainset = torchvision.datasets.MNIST(root='./data', train=True,

download=True, transform=transform)

trainloader = torchvision.datasets.DataLoader(trainset, batch_size=64,

shuffle=True, num_workers=2)

# 下载并加载测试数据集

testset = torchvision.datasets.MNIST(root='./data', train=False,

download=True, transform=transform)

testloader = torchvision.datasets.DataLoader(testset, batch_size=64,

shuffle=False, num_workers=2)

上述代码中,首先定义了数据预处理操作,将图像数据转换为张量,并使用 MNIST 数据集的均值(0.1307,)和标准差(0.3081,)进行标准化。然后分别下载并加载训练数据集和测试数据集,并使用DataLoader将数据集包装成可迭代的对象,设置批量大小为 64,训练集打乱数据,以提高模型的泛化能力。

2. 查看数据样本:为了直观地了解 MNIST 数据集的样子,我们可以查看一些数据样本:


import matplotlib.pyplot as plt

import numpy as np

# 获取一个批次的图像和标签

images, labels = next(iter(trainloader))

# 显示前4张图像

for i in range(4):

plt.subplot(1, 4, i + 1)

plt.imshow(images[i][0], cmap='gray')

plt.title(f"Label: {labels[i]}")

plt.axis('off')

plt.show()

这段代码从训练数据加载器中获取一个批次的图像和标签,然后使用matplotlib库显示前 4 张图像及其对应的标签,以便我们对数据有一个更直观的认识。

4.3 模型构建

我们使用前面介绍的方法构建一个简单的全连接神经网络模型来对 MNIST 手写数字进行分类:


import torch

import torch.nn as nn

import torch.nn.functional as F

class Net(nn.Module):

def __init__(self):

super(Net, self).__init__()

self.fc1 = nn.Linear(28 * 28, 128)

self.fc2 = nn.Linear(128, 64)

self.fc3 = nn.Linear(64, 10)

def forward(self, x):

x = x.view(-1, 28 * 28)

x = F.relu(self.fc1(x))

x = F.relu(self.fc2(x))

x = self.fc3(x)

return x

在这个模型中,输入层将 28×28 的图像展平为一维向量,然后经过两个隐藏层,每个隐藏层后使用 ReLU 激活函数,最后通过输出层得到 10 个类别的预测分数,对应 0 – 9 这 10 个数字。

4.4 模型训练

定义损失函数和优化器:对于分类任务,我们选择交叉熵损失函数nn.CrossEntropyLoss(),优化器选择 Adam 优化器torch.optim.Adam():


net = Net()

criterion = nn.CrossEntropyLoss()

optimizer = torch.optim.Adam(net.parameters(), lr=0.001)

训练模型:在训练过程中,我们通过迭代训练数据加载器,将数据输入模型进行前向传播,计算损失,然后进行反向传播更新模型参数。代码如下:


for epoch in range(10): # 训练10个epoch

running_loss = 0.0

for i, data in enumerate(trainloader, 0):

inputs, labels = data

optimizer.zero_grad()

outputs = net(inputs)

loss = criterion(outputs, labels)

loss.backward()

optimizer.step()

running_loss += loss.item()

if i % 200 == 199: # 每200个批次打印一次损失

print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 200:.3f}')

running_loss = 0.0

print('Finished Training')

在上述代码中,外层循环控制训练的轮数(epoch),内层循环迭代训练数据加载器。在每次迭代中,首先将优化器的梯度清零(optimizer.zero_grad()),然后进行前向传播得到模型的输出(outputs = net(inputs)),接着计算损失(loss = criterion(outputs, labels)),再进行反向传播计算梯度(loss.backward()),最后使用优化器更新模型参数(optimizer.step())。同时,每隔 200 个批次打印一次平均损失,以便观察模型的训练情况。

4.5 模型评估

训练完成后,我们使用测试数据集来评估模型的性能,计算模型在测试集上的准确率:


correct = 0

total = 0

with torch.no_grad():

for data in testloader:

images, labels = data

outputs = net(images)

_, predicted = torch.max(outputs.data, 1)

total += labels.size(0)

correct += (predicted == labels).sum().item()

print(f'Accuracy of the network on the 10000 test images: {100 * correct / total}%')

上述代码中,通过遍历测试数据加载器,将测试图像输入模型得到预测结果,然后统计预测正确的样本数量,最后计算出模型在测试集上的准确率并打印输出。通过评估模型在测试集上的性能,我们可以了解模型的泛化能力,判断模型是否能够在实际应用中有效地对新数据进行分类。

五、总结与展望

通过本文的学习,我们从 PyTorch 的基础知识入手,了解了张量的概念、创建、属性和运算,以及自动求导的原理和使用方法。接着深入学习了构建神经网络的基本流程,包括网络结构的定义、损失函数和优化器的选择,以及数据处理与加载。最后通过 MNIST 手写数字分类的实战项目,将理论知识应用到实际中,完整地体验了使用 PyTorch 构建、训练和评估神经网络的全过程。

然而,本文所介绍的内容只是 PyTorch 和深度学习的冰山一角。在未来的学习和实践中,我们可以进一步探索更复杂的神经网络架构,如卷积神经网络(CNN)、循环神经网络(RNN)及其变体 LSTM、GRU 等,这些网络在图像、语音、自然语言处理等领域有着更强大的表现。同时,我们还可以研究更多的优化技巧和训练策略,如学习率调整策略、正则化方法等,以提高模型的性能和泛化能力。此外,随着深度学习技术的不断发展,PyTorch 也在持续更新和完善,新的功能和特性不断涌现,我们需要保持学习的热情,紧跟技术发展的步伐,将 PyTorch 应用到更多实际场景中,解决更多复杂的问题。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容