当谈到基于MLP(多层感知器)的机器学习例子时,一个常见的任务是使用MLP对手写数字进行分类。MLP是一种前馈神经网络,它由多个全连接层组成。以下是一个基于MLP的手写数字分类例子,并给每一行添加了详细注释:
- import torch
- import torch.nn as nn
- import torch.optim as optim
- from torchvision import datasets, transforms
- # 设置随机种子,以便结果可复现
- torch.manual_seed(42)
- # 定义数据预处理的管道
- transform = transforms.Compose([
- transforms.ToTensor(), # 将图像转换为张量
- transforms.Normalize((0.5,), (0.5,)) # 归一化
- ])
- # 加载并预处理MNIST数据集
- trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
- trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True)
- testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
- testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False)
首先,我们导入必要的库和模块,包括PyTorch、torchvision和torchvision.transforms。然后,我们设置了随机种子,以确保结果的可重现性。
接下来,我们定义了一个数据预处理的管道transform
。在这个例子中,我们将图像转换为张量,并进行归一化处理。
然后,我们使用torchvision.datasets.MNIST
加载MNIST手写数字数据集。通过设置root
指定数据集的存储路径,train=True
表示加载训练集,download=True
表示如果数据集不存在,则下载数据集。我们还传入了之前定义的数据预处理管道transform
。
通过torch.utils.data.DataLoader
,我们创建了训练集和测试集的数据加载器。batch_size
参数指定每个批次的样本数量,shuffle=True
表示在每个epoch中打乱数据。
- # 定义MLP模型
- class MLP(nn.Module):
- def __init__(self):
- super(MLP, self).__init__()
- self.fc1 = nn.Linear(28 * 28, 128) # 全连接层,输入大小为28*28,输出大小为128
- self.relu = nn.ReLU() # ReLU激活函数
- self.fc2 = nn.Linear(128, 10) # 全连接层,输入大小为128,输出大小为10(类别数)
- def forward(self, x):
- x = x.view(x.size(0), -1) # 展平输入张量
- x = self.relu(self.fc1(x))
- x = self.fc2(x)
- return x
我们定义了一个简单的MLP模型。这个MLP模型包含了两个全连接层(fc1
和fc2
),并使用ReLU激活函数。
在__init__
方法中,我们定义了模型的各个层次和参数。第一个全连接层的输入大小为28*28(输入图像的像素数),输出大小为128。第二个全连接层的输入大小为128,输出大小为10(类别数)。
在forward
方法中,我们定义了模型的前向传播过程。我们首先将输入张量展平成一维向量,然后通过第一个全连接层和ReLU激活函数得到特征表示,最后通过第二个全连接层获得输出。
- # 实例化模型和损失函数
- net = MLP()
- criterion = nn.CrossEntropyLoss() # 交叉熵损失函数
- optimizer = optim.SGD(net.parameters(), lr=0.01) # 随机梯度下降优化器
我们实例化了之前定义的MLP模型,并定义了损失函数和优化器。在这个例子中,我们使用交叉熵损失函数和随机梯度下降(SGD)优化器。
- # 训练模型
- for epoch in range(5): # 进行5个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 % 1000 == 999:
- print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 1000:.3f}')
- running_loss = 0.0
- print('Finished training')
在训练阶段,我们使用训练集对模型进行训练。我们遍历数据加载器中的每个批次,将输入数据和标签加载到设备上。然后,我们将梯度缓存清零(通过optimizer.zero_grad()
),执行前向传播、反向传播和优化步骤。损失函数用于计算输出和标签之间的损失,并通过反向传播计算梯度。优化器根据梯度更新模型的参数。我们还计算并打印出每个epoch的平均损失。
- # 在测试集上评估模型
- 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 on the test set: {100 * correct / total:.2f}%')
在测试阶段,我们使用测试集对训练好的模型进行评估。对于每个样本,我们计算模型的输出并找到最高分数对应的类别索引。然后,我们将预测结果与真实标签进行比较,计算分类正确的样本数。最后,我们计算并打印出模型在测试集上的准确率。
这个基于MLP的手写数字分类例子展示了如何使用深度学习来解决实际问题。通过构建一个MLP模型并对其进行训练,我们能够对手写数字进行分类,并获得模型在测试集上的准确率评估。多层感知器多层感知器多层感知器