pytorch的核心库是torch,根据不同领域细分可以分成计算机视觉、自然语言处理和语音处理,这三个领域分别有自己对应的库,即torchvision、torchtext、torchaudio。如图8所示
图 8 pytorch基础架构
核心库torch中,根据功能又可以细分下面几个模块。如图9所示
图 9 torch核心模块
搭建深度学习模型可执行一下6个步骤:
1)导入相关资源库
2)准备数据
3)搭建模型:定义网络结构及前向传播
4)实例化模型:定义损失函数和优化器
5)模型训练:定义epoch和batch_size
测试模型: 选择合适的性能指标
首先导库,这里需要torch库。torch.nn 其中nn代表neural network 神经网络。torch.optim 其中optim代表优化器。torchvision 是计算机视觉库。用来处理图像的。torchvision.transform是用来做图像预处理的。
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
下面这段代码是使用pytorch的图像处理库torchvision中的transforms模块预处理流程。具体来说,这段代码定义了一个Compose对象,该对象会按照定义的顺序执行多个图像转换操作。
transforms.ToTensor(): 这个转换会将PIL图像或者NumPy ndarray转换为PyTorch的Tensor格式。默认情况下,该操作会将输入的图像数据从[0, 255]缩放到[0.0, 1.0],并且会自动调整图像的channels维度。
transforms.Normalize((0.5,), (0.5,)): 这个转换会对图像进行标准化。给定的两个参数分别是均值和标准差。在这里,它们都是0.5,这意味着每个通道的图像数据会被减去0.5(即其均值)然后除以0.5(即其标准差)。标准化是一个常见的预处理步骤,可以帮助模型更快地收敛,并且有时可以提高模型的性能。
简单来说,下面这段代码将一个PIL图像或者NumPy ndarray转换为PyTorch Tensor,并将其标准化到均值为0,标准差为0.5。
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
pytorch的torchvision库中有mnist数据集。我们可以使用下面这段代码进行加载。其中
root=‘./data’: 这指定了数据集的存储位置。在这个例子中,数据集将被下载并存储在当前目录下的data文件夹中。
train=True: 这表示我们想要加载训练数据集。train=False 表示我们想要加载测试训练集
download=True: 如果数据集尚未在指定的root路径中,则下载数据集。
transform=transform: 这指定了一个预处理流程,该流程应用于加载的每个图像。在这个例子中,图像首先会被转换为PyTorch的Tensor,然后被标准化。
train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
下面这段代码是使用pytorch的torch.utils.DataLoader来创建一个数据加载器,以便可以批量、有打乱地加载数据。
dataset=train_dataset: 指定要使用的数据集,即之前加载的train_dataset。
batch_size=64: 这指定了每个批次的大小。这意味着在每次迭代中,模型将接收到64个图像。
shuffle=True: 这意味着在每个训练时代开始时,数据将被随机打乱。这对于训练模型是有益的,因为它可以帮助防止模型过度拟合并确保它不会总是看到相同的数据顺序。
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)
上面这段代码创建了两个数据加载器:一个用于训练数据,另一个用于测试数据。这样,在训练和测试数据时,可以更方便地批量获取数据,同时可以控制是否打乱。
第一段代码:
class SimpleNN(nn.Module):
这行定义了一个新的类SimpleNN,它继承了PyTorch的nn.Module。在PyTorch中,神经网络模型都是从nn.Module派生的。
def init(self):
这是类的初始化函数,当你创建这个类的一个实例时,这个函数会被调用。
super(SimpleNN, self).init()
这行代码调用了父类nn.Module的初始化函数。这是PyTorch的标准做法,确保父类中的所有初始化操作都被正确执行。
self.flatten = nn.Flatten()
这行定义了一个名为flatten的层,该层是一个平铺层(或展平层)。它的作用是将输入的数据从多维的形式转换成一维的形式,方便输入到全连接层。这里它适用于处理28x28的图像数据(例如MNIST数据集中的手写数字图像)。
self.fc1 = nn.Linear(28 * 28, 128)
这行定义了一个全连接层(或线性层)fc1。它的输入特征数是28 * 28(因为一个28x28的图像被展平后是一维的,长度为784),输出特征数是128。
self.relu = nn.ReLU()
这行定义了一个ReLU(Rectified Linear Unit)激活函数层。ReLU激活函数的作用是:对于输入的每个元素,如果它大于0,则保持不变;如果它小于0,则将其设置为0。这有助于模型学习非线性特征。
self.fc2 = nn.Linear(128, 10)
这行定义了另一个全连接层fc2。它的输入特征数是128(来自上一个ReLU激活函数层),输出特征数是10。这意味着这个网络是为一个有10个类别的分类任务设计的。
简而言之,这个网络结构是这样的:输入数据首先通过一个平铺层,然后经过一个全连接层和ReLU激活函数,最后再经过一个全连接层得到输出。
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.flatten = nn.Flatten()
self.fc1 = nn.Linear(28 * 28, 128)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.flatten(x)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
第二段代码:
这段代码定义了一个简单的前向传播函数,它是用于一个神经网络模型。这个模型包括两个全连接层(或线性层)和一个ReLU激活函数。以下是对代码的逐行解释:
def forward(self, x):
这是定义了一个名为forward的方法,它接受一个参数x,通常表示输入数据。
x = self.flatten(x)
这行代码将输入数据x传递给一个名为flatten的层。这个层的作用是将输入数据从多维的形式转换成一维的形式,方便后续的全连接层处理。
x = self.fc1(x)
这行代码将平铺后的数据x传递给一个名为fc1的全连接层。全连接层的目的是将输入数据的每个元素与权重矩阵中的每个元素相乘,然后加偏置项。
x = self.relu(x)
这行代码将上一步全连接层的输出x传递给一个ReLU激活函数。ReLU激活函数的作用是:对于输入的每个元素,如果它大于0,则保持不变;如果它小于0,则将其设置为0。这有助于模型学习非线性特征。
x = self.fc2(x)
这行代码将ReLU激活函数层的输出x传递给另一个全连接层fc2。全连接层的目的是对数据进行进一步的线性变换和组合。
return x
最后,这个方法返回经过上述所有层处理后的输出数据x。
简而言之,这个forward方法描述了数据从输入到输出的完整流程:首先通过平铺层,然后经过两个全连接层和ReLU激活函数,最后得到输出。
下面这段Python代码是使用PyTorch库来定义一个简单的神经网络模型,并设置一个损失函数和一个优化器。下面是对代码的逐行解释:
model = SimpleNN()
这行代码创建了一个SimpleNN类的实例,即一个简单的神经网络模型。
criterion = nn.CrossEntropyLoss()
这行代码定义了一个交叉熵损失函数。交叉熵损失常用于分类问题,特别是当输出有多个类别时。
optimizer = optim.SGD(model.parameters(), lr=0.01)
这行代码定义了一个随机梯度下降(Stochastic Gradient Descent, SGD)优化器。SGD是一种常用的优化算法,用于最小化损失函数。
model.parameters()返回模型中所有可训练的参数(权重和偏置)。
lr=0.01设置学习率为0.01,这是SGD算法中用于更新参数的学习速率。
这段代码为训练神经网络模型做了初步的设置。通常,在PyTorch中,你还需要定义训练循环、前向传播、后向传播等步骤来训练和评估模型。
model = SimpleNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
num_epochs = 10: 定义了一个变量num_epochs,表示训练的轮数(epochs),这里设置为10。
for epoch in range(num_epochs):
这是一个for循环,从0开始,直到num_epochs - 1,用于遍历所有的训练轮次。
for images, labels in train_loader:
这里是一个嵌套的for循环,遍历train_loader。train_loader是一个数据加载器,通常用于批量加载训练数据。在每次迭代中,它会返回一批图像数据(images)和对应的标签(labels)。
optimizer.zero_grad(): 在进行反向传播之前,需要将之前的梯度清零。这是为了确保梯度是累加到当前梯度上,而不是与之前的梯度相加。
outputs = model(images): 将输入的图像数据传递给模型,得到输出结果。
loss = criterion(outputs, labels): 使用定义的损失函数(在这里是交叉熵损失)计算模型的输出与真实标签之间的损失。
loss.backward(): 这一步是反向传播的核心。它计算损失相对于模型参数的梯度。
optimizer.step(): 使用之前计算的梯度来更新模型的权重。这是模型参数优化的实际步骤。
print(f’Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
在每个epoch结束后,打印该epoch的损失值。这有助于了解训练过程中的损失变化。
总之,这段代码描述了一个神经网络模型的训练过程:它从数据加载器中获取一批批次的图像和标签,计算损失,进行反向传播,并更新模型的权重。这个过程会重复多次(由num_epochs定义),以使模型能够“学习”并逐渐改善其预测性能。
num_epochs = 10
for epoch in range(num_epochs):
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
下面这段代码是用于计算神经网络模型在测试数据集上的准确率。以下是代码的逐行解释:
model.eval(): 将模型设置为评估模式。在PyTorch中,模型有两个模式:训练模式(model.train())和评估模式(model.eval())。在评估模式下,某些层(如Dropout和BatchNorm)的行为会与训练模式不同。
correct = 0, total = 0: 初始化两个变量,分别用于累计正确的预测数和总预测数。
with torch.no_grad():: 这一行及其以下的代码块表示不计算梯度,因为我们在评估模式,不需要梯度信息。
for images, labels in test_loader:: 遍历测试数据集中的所有批次。
outputs = model(images): 将图像数据传递给模型进行预测。
_, predicted = torch.max(outputs.data, 1): 找到预测值中最大值的索引,这通常是分类问题中的预测类别。
total += labels.size(0): 更新总预测数的计数。
correct += (predicted == labels).sum().item(): 检查预测的类别是否与真实标签匹配,并更新正确的预测数。
accuracy = correct / total: 计算准确率。
print(f’Test Accuracy: {accuracy * 100:.2f}%'): 打印准确率。
总的来说,这段代码的目的是评估模型在测试数据集上的性能,并打印出准确率。
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = correct / total
print(f'Test Accuracy: {accuracy * 100:.2f}%')
前几天只发布了纯代码,用pytorch搭建神经网路实现mnist手写数字识别,不知道同学们是否进行了操作。同时对知识的巨大黑洞有所了解,本次更改更加详细。希望大家能通过此文了解人工智能与神经网络的关系。同时也清楚大数据与人工智能的关系。同时在实战中,快速补充不了解的知识点。
作业:搞清epoch、batchsize的关系,提前预习优化器相关的知识。
参考文献: