作为一名计算机工程专业的学生,我一直在寻找提高技能和加深知识的方法。最近,我一直专注于学习PyTorch,一个强大的深度学习框架。为了帮助巩固我迄今为止学到的东西,并有可能帮助其他PyTorch新手,我决定写这篇博文,详细介绍使用PyTorch构建基本神经网络所涉及的步骤。我希望你觉得它很有帮助,信息丰富。让我们开始吧!
卷积神经网络(CNN)在图像分类任务中取得了令人难以置信的成功。在本博客中,我们将使用PyTorch构建一个简单的CNN,对来自MNIST数据集的手写数字进行分类。我们将经历该过程的每一步,包括定义模型、加载和预处理数据、训练模型以及评估其性能。
进口
用PyTorch构建神经网络的第一步是导入必要的库和模块,在这个代码片段中,我们导入了torch库,以及其他几个模块如nn(用于定义神经网络层)、optim(用于定义优化算法)、datasets和transforms(用于加载和处理数据)。
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import DataLoader
import torchvision.datasets as datasets
import torchvision.transforms as transforms
定义模型
下一步是定义模型架构。我们创建一个名为CNN的类,它扩展了PyTorch提供的nn.Module类。CNN类有一个定义网络层的__init__方法。我们使用两个卷积层,每个层后面都有一个ReLU激活函数和一个最大池化层。第二个卷积层的输出然后通过一个全连接层,该层产生网络的最终输出。
# Create CNN
class CNN(nn.Module):
def __init__(self, in_channels=1, num_classes=10):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(
in_channels=in_channels,
out_channels=8,
kernel_size=(3, 3),
stride=(1, 1),
padding=(1, 1)
)
self.pool1 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2))
self.conv2 = nn.Conv2d(
in_channels=8,
out_channels=16,
kernel_size=(3, 3),
stride=(1, 1),
padding=(1, 1)
)
self.fc1 = nn.Linear(16 * 7 * 7, num_classes)
def forward(self, x):
batch = x.shape[0]
return self.fc1(self.pool1(F.relu(self.conv2(self.pool1(F.relu(self.conv1(x)))))).reshape(batch, -1))
检查模型形状
在训练我们的模型之前,我们希望确保它已经被正确定义并产生预期的输出形状。我们创建模型的一个实例,并传入一个大小为(64, 1, 28, 28)的随机张量,以查看输出形状将是什么。预期的输出形状是(64, 10)因为我们试图将手写数字分类为十个类(0-9)之一。
# Checking if it is correct shape
model = CNN()
x = torch.rand(64, 1, 28, 28)
print(model(x).shape)
设置设备和超参数
接下来,我们设置PyTorch将用于计算的设备。如果GPU可用,我们将使用它,否则,我们将使用CPU。我们还设置了一些超参数,包括学习率、批处理大小和纪元数。
# Set Device
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
设置超参数
在我们可以训练我们的神经网络之前,我们需要定义一些超参数,例如学习率、批量大小和纪元数。在这个例子中,我们定义学习率为0.001,批量大小为64,训练10纪元。
input_size = 784
num_classes = 10
learning_rate = 0.001
batch_size = 64
num_epochs = 10
加载和预处理数据
我们使用PyTorch的内置MNIST数据集来加载我们的数据。我们为训练集和测试集创建单独的数据加载器,这将允许我们在训练期间批量迭代数据。我们还对数据应用ToTensor()变换,它将图像转换为PyTorch张量并将像素值缩放为0到1之间。
# Loading Data
train_data = datasets.MNIST(root="dataset/", train=True, transform=transforms.ToTensor(), download=True)
train_loader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
test_data = datasets.MNIST(root="dataset/", train=False, transform=transforms.ToTensor(), download=True)
test_loader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)
初始化网络并定义损失和优化器
我们创建了CNN模型的一个实例,并将其移动到我们之前指定的设备。我们还定义了我们将使用的损失函数,即交叉熵损失,以及优化器,即Adam。
# Init Network
model = CNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(params= model.parameters(), lr=learning_rate)
训练模型
现在我们已经定义了我们的模型,加载了数据,并初始化了必要的组件,我们可以通过批量迭代训练数据并使用反向传播更新模型参数来训练我们的神经网络。我们循环遍历指定数量的时期的训练数据,对于每批,我们计算损失,计算梯度,并使用优化器更新模型参数。
# Training
for epoch in range(num_epochs):
for batch_idx, (data, labels) in enumerate(train_loader):
data = data.to(device=device)
labels = labels.to(device=device)
scores = model(data)
loss = criterion(scores, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
评估模型
训练后,我们想评估我们的模型在测试集上的性能。我们迭代测试集,计算模型预测的准确性,并打印出最终的准确性。
# Test
num_correct = 0
num_samples = 0
model.eval()
with torch.no_grad():
for data, labels in test_loader:
data = data.to(device=device)
labels = labels.to(device=device)
scores = model(data)
_, predictions = torch.max(scores, dim=1)
num_correct += (predictions == labels).sum()
num_samples += predictions.size(0)
print(f'Got {num_correct} / {num_samples} with accuracy {float(num_correct) / float(num_samples) * 100:.2f}')
model.train()
Output : Got 9871 / 10000 with accuracy 98.71
注意:与神经网络模型在相同数据中的97.12%相比,神经网络模型实现了98.71%的更高准确率。这表明CNN架构在捕获图像数据中的复杂空间模式方面更加有效。
可视化预测
最后,我们通过从测试集中选择10个随机图像并将它们与它们的真实标签和预测标签一起绘制来可视化模型的预测。我们可以从图表中看到我们的模型对手写数字的分类程度。
总之,我们使用PyTorch构建了一个简单的CNN来对来自MNIST数据集的手写数字进行分类。我们经历了该过程的每一步,从定义模型架构到评估其性能,我们能够在测试集上实现高水平的准确性。
# Test and plot 10 random images
model.eval()
with torch.no_grad():
fig, axs = plt.subplots(2, 5, figsize=(12, 6))
axs = axs.flatten()
for i, (data, labels) in enumerate(test_loader):
if i >= 10: # Break after 10 images
break
data = data.to(device=device)
labels = labels.to(device=device)
scores = model(data)
_, predictions = torch.max(scores, dim=1)
# Plot images and predictions
img = data.cpu().numpy().reshape(-1, 28, 28)
axs[i].imshow(img[0], cmap='gray')
axs[i].set_title(f"Label: {labels[0]} - Prediction: {predictions[0]}")
plt.tight_layout()
plt.show()
model.train()
输出(你的可能不同,因为它们是随机选择的)
如果你想得到完整的代码
# Imports
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import DataLoader
import torchvision.datasets as datasets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
# Create CNN
class CNN(nn.Module):
def __init__(self, in_channels=1, num_classes=10):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(
in_channels=in_channels,
out_channels=8,
kernel_size=(3, 3),
stride=(1, 1),
padding=(1, 1)
)
self.pool1 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2))
self.conv2 = nn.Conv2d(
in_channels=8,
out_channels=16,
kernel_size=(3, 3),
stride=(1, 1),
padding=(1, 1)
)
self.fc1 = nn.Linear(16 * 7 * 7, num_classes)
def forward(self, x):
batch = x.shape[0]
return self.fc1(self.pool1(F.relu(self.conv2(self.pool1(F.relu(self.conv1(x)))))).reshape(batch, -1))
# Checking if it is correct shape
model = CNN()
x = torch.rand(64, 1, 28, 28)
print(model(x).shape)
# Set Device
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
# HyperParams
input_size = 784
num_classes = 10
learning_rate = 0.001
batch_size = 64
num_epochs = 10
# Loading Data
train_data = datasets.MNIST(root="dataset/", train=True, transform=transforms.ToTensor(), download=True)
train_loader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
test_data = datasets.MNIST(root="dataset/", train=False, transform=transforms.ToTensor(), download=True)
test_loader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)
# Init Network
model = CNN().to(device)
# Loss and Optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(params=model.parameters(), lr=learning_rate)
# Training
for epoch in range(num_epochs):
for batch_idx, (data, labels) in enumerate(train_loader):
data = data.to(device=device)
labels = labels.to(device=device)
scores = model(data)
loss = criterion(scores, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Test
num_correct = 0
num_samples = 0
model.eval()
with torch.no_grad():
for data, labels in test_loader:
data = data.to(device=device)
labels = labels.to(device=device)
scores = model(data)
_, predictions = torch.max(scores, dim=1)
num_correct += (predictions == labels).sum()
num_samples += predictions.size(0)
print(f'Got {num_correct} / {num_samples} with accuracy {float(num_correct) / float(num_samples) * 100:.2f}')
model.train()
# Test and plot 10 random images
model.eval()
with torch.no_grad():
fig, axs = plt.subplots(2, 5, figsize=(12, 6))
axs = axs.flatten()
for i, (data, labels) in enumerate(test_loader):
if i >= 10: # Break after 10 images
break
data = data.to(device=device)
labels = labels.to(device=device)
scores = model(data)
_, predictions = torch.max(scores, dim=1)
# Plot images and predictions
img = data.cpu().numpy().reshape(-1, 28, 28)
axs[i].imshow(img[0], cmap='gray')
axs[i].set_title(f"Label: {labels[0]} - Prediction: {predictions[0]}")
plt.tight_layout()
plt.show()
model.train()
结论
在本博客中,我们探索了使用PyTorch实现卷积神经网络。我们首先使用nn. Module类定义模型的架构,然后加载并预处理MNIST数据集。然后,我们使用训练数据训练模型,并使用测试数据评估其性能。
在整个博客中,我们了解了深度学习中的不同概念,包括卷积层、池化层、全连接层、反向传播、交叉熵损失和亚当优化器。我们还学习了如何使用PyTorch DataLoader和torchvision. datasets模块加载和预处理数据。
到本博客结束时,我们已经对如何在PyTorch中实现一个简单的CNN以及如何在真实世界的数据集上训练和评估其性能有了扎实的理解。我们希望本博客为您自己的深度学习项目提供了一个有用的起点,并希望您对深度学习的迷人世界有所了解。