1.导入必要的库。
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import confusion_matrix, classification_report
import seaborn as sns
![图片[1] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a24496b67.png)
2.定义数据转换并下载并加载数据集
定义将图像转为张量并标准化的转换方式,代码会自动下载Fashion-MNIST训练集和测试集并加载,同时定义10个服装类别的名称。
# 定义数据转换:将图像数据转换为张量,并标准化(使用MNIST的均值和标准差)
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,)) # 单通道,均值和标准差都是0.5
])
# 下载并加载训练集和测试集
trainset = torchvision.datasets.FashionMNIST(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,
shuffle=True, num_workers=2)
testset = torchvision.datasets.FashionMNIST(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64,
shuffle=False, num_workers=2)
# 定义类别名称
classes = ('T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot')
![图片[2] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a26b40839.png)
3.获取一批训练数据并显示图像
从训练数据加载器中获取一批数据,通过子图展示5张图像及对应类别名称,实现样本数据可视化。
# 获取一批训练数据
dataiter = iter(trainloader)
images, labels = next(dataiter)
# 显示图像
fig, axes = plt.subplots(1, 5, figsize=(12, 3))
for i in range(5):
ax = axes[i]
# 反标准化:img = (img * 0.5) + 0.5
ax.imshow(images[i].squeeze(), cmap='gray')
ax.set_title(classes[labels[i].item()])
ax.axis('off')
plt.show()
![图片[3] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a28dbe444.png)
4.定义MLP并初始化
定义含输入层到隐藏层全连接、ReLU激活、Dropout正则化及隐藏层到输出层全连接的MLP模型,初始化模型并打印结构。
class MLP(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(MLP, self).__init__()
# 第一个全连接层: 输入层 -> 隐藏层
self.fc1 = nn.Linear(input_size, hidden_size)
# 非线性激活函数 ReLU
self.relu = nn.ReLU()
# Dropout层,随机丢弃一部分神经元,防止过拟合
self.dropout = nn.Dropout(0.5)
# 第二个全连接层: 隐藏层 -> 输出层
self.fc2 = nn.Linear(hidden_size, num_classes)
# 注意:我们不在最后一层使用Softmax,因为CrossEntropyLoss自带Softmax
def forward(self, x):
# 将图像展平 [batch_size, 1, 28, 28] -> [batch_size, 784]
x = x.view(-1, 28*28)
# 前向传播
out = self.fc1(x)
out = self.relu(out)
out = self.dropout(out) # 只在训练时起作用
out = self.fc2(out)
return out
# 尝试使用GPU设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")
# 初始化模型并移动到指定设备
input_size = 784 # 28x28
hidden_size = 256 # 隐藏层神经元数量,可调整
num_classes = 10
model = MLP(input_size, hidden_size, num_classes).to(device)
# 打印模型结构
print(model)
![图片[4] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a2dcedbb4.png)
和源代码不同的是,我这里使用GPU设备进行训练。
5.损失函数和优化器
选择交叉熵损失函数(适配多分类)和Adam优化器(设置学习率0.001)用于模型训练。
# 损失函数:交叉熵损失,适用于多分类问题
criterion = nn.CrossEntropyLoss()
# 优化器:Adam,一种自适应学习率的优化算法,通常效果比SGD更好
optimizer = optim.Adam(model.parameters(), lr=0.001)
![图片[5] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a30a4a0a7.png)
6.进行训练并绘制曲线
设置训练轮次为10,每轮将模型设为训练模式,遍历训练数据,完成前向传播、损失计算、反向传播及参数优化,统计每轮损失和准确率并绘制训练曲线。
num_epochs = 10
train_losses = []
train_accuracies = []
for epoch in range(num_epochs):
# 设置为训练模式(启用Dropout)
model.train()
running_loss = 0.0
correct = 0
total = 0
for i, (images, labels) in enumerate(trainloader):
# 将数据移动到CUDA设备
images = images.to(device)
labels = labels.to(device)
# 前向传播
outputs = model(images)
loss = criterion(outputs, labels)
# 反向传播和优化
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播,计算梯度
optimizer.step() # 更新参数
# 统计损失和准确率
running_loss += loss.item()
_, predicted = torch.max(outputs.data, 1) # 获取预测类别
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 计算每个epoch的平均损失和准确率
epoch_loss = running_loss / len(trainloader)
epoch_acc = 100 * correct / total
train_losses.append(epoch_loss)
train_accuracies.append(epoch_acc)
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.2f}%')
# 绘制训练过程曲线
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
ax1.plot(train_losses)
ax1.set_title('Training Loss')
ax1.set_xlabel('Epoch')
ax1.set_ylabel('Loss')
ax2.plot(train_accuracies)
ax2.set_title('Training Accuracy')
ax2.set_xlabel('Epoch')
ax2.set_ylabel('Accuracy (%)')
plt.show()
训练轮数为10时,Train Acc大概在87%,然后我又尝试了epochs改为20。最高Train Acc到了89.34%。改为40,最高Train Acc 91.50%
![图片[6] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a35fdc3ed.png)
![图片[7] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a3b4499e4.png)
7.模型评估
将模型设为评估模式,关闭梯度计算,遍历测试数据完成预测,统计测试准确率,生成分类报告和混淆矩阵并可视化。
# 设置为评估模式(禁用Dropout)
model.eval()
all_labels = []
all_preds = []
with torch.no_grad(): # 关闭梯度计算
correct = 0
total = 0
for images, labels in testloader:
# 将测试数据也移动到CUDA设备
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 收集所有预测和标签以生成详细报告(需要移回CPU)
all_labels.extend(labels.cpu().numpy())
all_preds.extend(predicted.cpu().numpy())
test_accuracy = 100 * correct / total
print(f'Test Accuracy of the model on the 10000 test images: {test_accuracy:.2f}%')
# 生成并打印分类报告
print("\nClassification Report:")
print(classification_report(all_labels, all_preds, target_names=classes))
# 生成混淆矩阵
cm = confusion_matrix(all_labels, all_preds)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=classes, yticklabels=classes)
plt.title('Confusion Matrix')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.xticks(rotation=45)
plt.yticks(rotation=0)
plt.show()
![图片[8] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a3fc55912.png)
上图是epochs为20时的测试结果,下图是epochs为40时的测试结果。Test Acc从88.41%提升到了89.01%
![图片[9] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a428ae077.png)
8.模型测试
从测试数据加载器中获取一批数据,用训练好的模型预测,通过子图展示 10 张图像的真实类别与预测类别(正确为绿色、错误为红色)。
# 获取一批测试数据
dataiter = iter(testloader)
images, labels = next(dataiter)
# 将数据移动到CUDA设备进行预测
images_cuda = images.to(device)
outputs = model(images_cuda)
_, preds = torch.max(outputs, 1)
# 显示图像及预测结果
fig, axes = plt.subplots(2, 5, figsize=(15, 6))
for i, ax in enumerate(axes.flat):
ax.imshow(images[i].squeeze(), cmap='gray') # 使用原始CPU上的图像进行显示
ax.set_title(f'True: {classes[labels[i]]}\nPred: {classes[preds[i].item()]}',
color=('green' if preds[i] == labels[i].to(device) else 'red'))
ax.axis('off')
plt.tight_layout()
plt.show()
![图片[10] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a46210634.png)
9.观察训练曲线
![图片[11] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a47316104.png)
![图片[12] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a47f2caa6.png)
可以看到Train Loss在随着轮数增加在逐步减小,前期(前 10 轮)下降陡峭,后期(20 轮后)下降速率放缓并伴随震荡。波动可能源于优化器梯度更新的随机性(Adam 自适应调整学习率时的参数震荡),以及 Dropout 层的正则化影响(训练时随机失活神经元,导致每轮前向传播的网络结构略有差异)。曲线未完全平稳,说明 40 轮后模型仍有学习潜力。
然后Train Acc轮数增加在抖动上升。最终在第20轮达到最高89.65%的Train Acc。之后设置为40轮时,Train Acc最高达到了91.50%,但与测试集存在约2.5% 的差距,结合 Dropout 的使用,说明过拟合风险低,差距主要源于 MLP 对图像空间特征的提取能力不足(相较于 CNN,全连接层可能丢失局部结构信息)。
10.记录测试准确率
![图片[13] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a4884a134.png)
上图是epochs为20时的测试结果,下图是epochs为40时的测试结果。Test Acc从88.41%提升到了89.01%
![图片[14] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a4933b15b.png)
测试集准确率为89.01%,处于Fashion-MNIST数据集上MLP 模型的合理区间(85%–90%),验证了模型结构有效性。对比训练准确率,差距约 2.5%,反映了模型复杂度依旧不足,因为MLP 无法充分捕捉图像的空间关联性,如边缘、纹理的局部模式。
11.分析混淆矩阵
![图片[15] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a4a8e4a0c.png)
上图是epochs为20时的测试结果,下图是epochs为40时的测试结果。Test Acc从88.41%提升到了89.01%,混淆矩阵中对角线上的数值明显增加。
![图片[16] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a4b6916aa.png)
12.其他调整
除了上面对epochs的两次调整外,下面对学习率和优化器进行调整和替换。均在epochs=20下进行。
初始lr=0.001,修改为lr=0.01,可见Train Acc一直在70%左右波动,最终是71.64%。学习率过大无法拟合特征。观察下方图像也可以看出,振幅明显增大且无拟合趋势。
![图片[17] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a4cf70b80.png)
初始lr=0.001,修改为lr=0.0001(减小到原来的1/10),训练曲线如下:
![图片[18] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a4e6c0ae0.png)
可见学习率减少到原来的1/10后,训练Loss和Acc曲线都更加稳定,但Train Acc变化也较之前慢。
尽管Adam等自适应学习率算法收敛快,但是有研究表明传统的SGD(随机梯度下降)配合动量(Momentum)在训练后期,往往能找到一个更平坦的损失函数区域,从而获得更好的泛化能力。调整Adam优化器为SGD + Momentum,这时代码为。
# 损失函数:交叉熵损失,适用于多分类问题
criterion = nn.CrossEntropyLoss()
# 优化器:SGD + Momentum,在某些情况下泛化能力比Adam更好
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
使用此优化器策略训练模型20轮,训练结果如下,
![图片[19] - AI科研 编程 读书笔记 - 【人工智能】【Python】多层感知机应用实验 - AI科研 编程 读书笔记 - 小竹の笔记本](https://img.smallbamboo.cn/i/2025/11/01/6905a52d224f9.png)
可以看到Loss和Acc曲线都比之前Adam优化器更加平稳和稳定。
2. 论文总结类文章中涉及的图表、数据等素材,版权归原出版商及论文作者所有,仅为学术交流目的引用;若相关权利人认为存在侵权,请联系本网站删除,联系方式:i@smallbamboo.cn。
3. 违反上述声明者,将依法追究其相关法律责任。




























暂无评论内容