创建网站为啥要钱网站建设用什么代码
之前学习了图像数据的格式以及模型定义的过程,发现和之前结构化数据的略有不同,主要差异体现在2处
1. 模型定义的时候需要展平图像
2. 由于数据过大,需要将数据集进行分批次处理,这往往涉及到了dataset和dataloader来规范代码的组织
现在我们把注意力放在训练和测试代码的规范写法上
1.单通道图片的规范写法
# 先继续之前的代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader , Dataset # DataLoader 是 PyTorch 中用于加载数据的工具
from torchvision import datasets, transforms # torchvision 是一个用于计算机视觉的库,datasets 和 transforms 是其中的模块
import matplotlib.pyplot as plt
import warnings
# 忽略警告信息
warnings.filterwarnings("ignore")
# 设置随机种子,确保结果可复现
torch.manual_seed(42)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")
使用设备: cuda
# 1. 数据预处理
transform = transforms.Compose([transforms.ToTensor(), # 转换为张量并归一化到[0,1]transforms.Normalize((0.1307,), (0.3081,)) # MNIST数据集的均值和标准差
])# 2. 加载MNIST数据集
train_dataset = datasets.MNIST(root='./data',train=True,download=True,transform=transform
)test_dataset = datasets.MNIST(root='./data',train=False,transform=transform
)# 3. 创建数据加载器
batch_size = 64 # 每批处理64个样本
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 4. 定义模型、损失函数和优化器
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten() # 将28x28的图像展平为784维向量self.layer1 = nn.Linear(784, 128) # 第一层:784个输入,128个神经元self.relu = nn.ReLU() # 激活函数self.layer2 = nn.Linear(128, 10) # 第二层:128个输入,10个输出(对应10个数字类别)def forward(self, x):x = self.flatten(x) # 展平图像x = self.layer1(x) # 第一层线性变换x = self.relu(x) # 应用ReLU激活函数x = self.layer2(x) # 第二层线性变换,输出logitsreturn x# 初始化模型
model = MLP()
model = model.to(device) # 将模型移至GPU(如果可用)# from torchsummary import summary # 导入torchsummary库
# print("\n模型结构信息:")
# summary(model, input_size=(1, 28, 28)) # 输入尺寸为MNIST图像尺寸criterion = nn.CrossEntropyLoss() # 交叉熵损失函数,适用于多分类问题
optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam优化器
# 5. 训练模型(记录每个 iteration 的损失)
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):model.train() # 设置为训练模式# 新增:记录每个 iteration 的损失all_iter_losses = [] # 存储所有 batch 的损失iter_indices = [] # 存储 iteration 序号(从1开始)for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):# enumerate() 是 Python 内置函数,用于遍历可迭代对象(如列表、元组)并同时获取索引和值。# batch_idx:当前批次的索引(从 0 开始)# (data, target):当前批次的样本数据和对应的标签,是一个元组,这是因为dataloader内置的getitem方法返回的是一个元组,包含数据和标签。# 只需要记住这种固定写法即可data, target = data.to(device), target.to(device) # 移至GPU(如果可用)optimizer.zero_grad() # 梯度清零output = model(data) # 前向传播loss = criterion(output, target) # 计算损失loss.backward() # 反向传播optimizer.step() # 更新参数# 记录当前 iteration 的损失(注意:这里直接使用单 batch 损失,而非累加平均)iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1) # iteration 序号从1开始# 统计准确率和损失running_loss += loss.item() #将loss转化为标量值并且累加到running_loss中,计算总损失_, predicted = output.max(1) # output:是模型的输出(logits),形状为 [batch_size, 10](MNIST 有 10 个类别)# 获取预测结果,max(1) 返回每行(即每个样本)的最大值和对应的索引,这里我们只需要索引total += target.size(0) # target.size(0) 返回当前批次的样本数量,即 batch_size,累加所有批次的样本数,最终等于训练集的总样本数correct += predicted.eq(target).sum().item() # 返回一个布尔张量,表示预测是否正确,sum() 计算正确预测的数量,item() 将结果转换为 Python 数字# 每100个批次打印一次训练信息(可选:同时打印单 batch 损失)if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx+1):.4f}')# 测试、打印 epoch 结果epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totalepoch_test_loss, epoch_test_acc = test(model, test_loader, criterion, device)print(f'Epoch {epoch+1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%')# 绘制所有 iteration 的损失曲线plot_iter_losses(all_iter_losses, iter_indices)# 保留原 epoch 级曲线(可选)#plot_metrics(train_losses, test_losses, train_accuracies, test_accuracies, epochs)return epoch_test_acc # 返回最终测试准确率
之前我们用mlp训练鸢尾花数据集的时候并没有用函数的形式来封装训练和测试过程,这样写会让代码更加具有逻辑-----隔离参数和内容。
1. 后续直接修改参数就行,不需要去找到对应操作的代码
2. 方便复用,未来有多模型对比时,就可以复用这个函数
这里我们先不写早停策略,因为规范的早停策略需要用到验证集,一般还需要划分测试集
1. 划分数据集:训练集(用于训练)、验证集(用于早停和调参)、测试集(用于最终报告性能)。
2. 在训练过程中,使用验证集触发早停。
3. 训练结束后,仅用测试集运行一次测试函数,得到最终准确率。
测试函数和绘图函数均被封装在了train函数中,但是test和绘图函数在定义train函数之后,这是因为在 Python 中,函数定义的顺序不影响调用,只要在调用前已经完成定义即可。
# 6. 测试模型(不变)
def test(model, test_loader, criterion, device):model.eval() # 设置为评估模式test_loss = 0correct = 0total = 0with torch.no_grad(): # 不计算梯度,节省内存和计算资源for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()avg_loss = test_loss / len(test_loader)accuracy = 100. * correct / totalreturn avg_loss, accuracy # 返回损失和准确率
如果打印每一个bitchsize的损失和准确率,会看的更加清晰,更加直观
# 7. 绘制每个 iteration 的损失曲线
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序号)')plt.ylabel('损失值')plt.title('每个 Iteration 的训练损失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()
# 8. 执行训练和测试(设置 epochs=2 验证效果)
import matplotlib.pyplot as plt
# 1. 指定默认字体(以黑体 SimHei 为例),确保你的系统里已经安装了 SimHei
plt.rcParams['font.sans-serif'] = ['SimHei']
# 2. 解决负号 '-' 显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falseepochs = 2
print("开始训练模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, device, epochs)
print(f"训练完成!最终测试准确率: {final_accuracy:.2f}%")
开始训练模型...
Epoch: 1/2 | Batch: 100/938 | 单Batch损失: 0.0142 | 累计平均损失: 0.0744
Epoch: 1/2 | Batch: 200/938 | 单Batch损失: 0.0397 | 累计平均损失: 0.0729
Epoch: 1/2 | Batch: 300/938 | 单Batch损失: 0.0559 | 累计平均损失: 0.0784
Epoch: 1/2 | Batch: 400/938 | 单Batch损失: 0.0359 | 累计平均损失: 0.0775
Epoch: 1/2 | Batch: 500/938 | 单Batch损失: 0.0154 | 累计平均损失: 0.0780
Epoch: 1/2 | Batch: 600/938 | 单Batch损失: 0.0763 | 累计平均损失: 0.0796
Epoch: 1/2 | Batch: 700/938 | 单Batch损失: 0.0951 | 累计平均损失: 0.0807
Epoch: 1/2 | Batch: 800/938 | 单Batch损失: 0.0150 | 累计平均损失: 0.0804
Epoch: 1/2 | Batch: 900/938 | 单Batch损失: 0.0777 | 累计平均损失: 0.0789
Epoch 1/2 完成 | 训练准确率: 97.62% | 测试准确率: 96.94%
Epoch: 2/2 | Batch: 100/938 | 单Batch损失: 0.0575 | 累计平均损失: 0.0647
Epoch: 2/2 | Batch: 200/938 | 单Batch损失: 0.0523 | 累计平均损失: 0.0642
Epoch: 2/2 | Batch: 300/938 | 单Batch损失: 0.0662 | 累计平均损失: 0.0634
Epoch: 2/2 | Batch: 400/938 | 单Batch损失: 0.0647 | 累计平均损失: 0.0626
Epoch: 2/2 | Batch: 500/938 | 单Batch损失: 0.0254 | 累计平均损失: 0.0606
Epoch: 2/2 | Batch: 600/938 | 单Batch损失: 0.0161 | 累计平均损失: 0.0610
Epoch: 2/2 | Batch: 700/938 | 单Batch损失: 0.0364 | 累计平均损失: 0.0609
Epoch: 2/2 | Batch: 800/938 | 单Batch损失: 0.0113 | 累计平均损失: 0.0616
Epoch: 2/2 | Batch: 900/938 | 单Batch损失: 0.0140 | 累计平均损失: 0.0610
Epoch 2/2 完成 | 训练准确率: 98.05% | 测试准确率: 97.65%

训练完成!最终测试准确率: 97.65%
在 PyTorch 中处理张量(Tensor)时,展平(Flatten)、维度调整(如 view/reshape)等操作通常不会影响第一个维度,即批量维度 batch_size。下面详细介绍不同任务下张量形状以及这些操作的关键点。
图像任务中的张量形状
输入张量的形状通常为 (batch_size, channels, height, width),例如 (batch_size, 3, 28, 28),这里的 batch_size 代表一次输入的样本数量。
NLP 任务中的张量形状
输入张量的形状可能为 (batch_size, sequence_length),batch_size 同样是第一个维度。
1. Flatten 操作
- 功能:将张量展平为一维数组,但会保留批量维度。
- 示例:以图像数据为例,输入形状为
(batch_size, 3, 28, 28),Flatten 后的形状为(batch_size, 3×28×28),也就是(batch_size, 2352)。第一个维度batch_size保持不变,后面的所有维度被展平成一个维度。
2. view/reshape 操作
- 功能:调整张量维度,不过必须显式保留或指定批量维度。
- 示例:输入形状为
(batch_size, 3, 28, 28),若调整为(batch_size, -1),会展平为两个维度,保留batch_size,第二个维度会由 PyTorch 自动计算为3×28×28 = 2352。
总结
- 批量维度不变性:不管是进行 flatten、view 还是 reshape 操作,第一个维度
batch_size通常都保持不变。 - 动态维度指定:使用
-1能让 PyTorch 自动计算该维度的大小,但要保证其他维度指定合理,避免出现形状不匹配的错误
代码汇总
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as npplt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题# 1. 数据预处理
transform = transforms.Compose([transforms.ToTensor(), # 转换为张量并归一化到[0,1]transforms.Normalize((0.1307,), (0.3081,)) # MNIST数据集的均值和标准差
])# 2. 加载MNIST数据集
train_dataset = datasets.MNIST(root='./data',train=True,download=True,transform=transform
)test_dataset = datasets.MNIST(root='./data',train=False,transform=transform
)# 3. 创建数据加载器
batch_size = 64 # 每批处理64个样本
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 4. 定义模型、损失函数和优化器
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten() # 将28x28的图像展平为784维向量self.layer1 = nn.Linear(784, 128) # 第一层:784个输入,128个神经元self.relu = nn.ReLU() # 激活函数self.layer2 = nn.Linear(128, 10) # 第二层:128个输入,10个输出(对应10个数字类别)def forward(self, x):x = self.flatten(x) # 展平图像x = self.layer1(x) # 第一层线性变换x = self.relu(x) # 应用ReLU激活函数x = self.layer2(x) # 第二层线性变换,输出logitsreturn x# 检查GPU是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 初始化模型
model = MLP()
model = model.to(device) # 将模型移至GPU(如果可用)criterion = nn.CrossEntropyLoss() # 交叉熵损失函数,适用于多分类问题
optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam优化器# 5. 训练模型(记录每个 iteration 的损失)
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):model.train() # 设置为训练模式# 新增:记录每个 iteration 的损失all_iter_losses = [] # 存储所有 batch 的损失iter_indices = [] # 存储 iteration 序号(从1开始)for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device) # 移至GPU(如果可用)optimizer.zero_grad() # 梯度清零output = model(data) # 前向传播loss = criterion(output, target) # 计算损失loss.backward() # 反向传播optimizer.step() # 更新参数# 记录当前 iteration 的损失(注意:这里直接使用单 batch 损失,而非累加平均)iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1) # iteration 序号从1开始# 统计准确率和损失(原逻辑保留,用于 epoch 级统计)running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()# 每100个批次打印一次训练信息(可选:同时打印单 batch 损失)if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx+1):.4f}')# 原 epoch 级逻辑(测试、打印 epoch 结果)不变epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totalepoch_test_loss, epoch_test_acc = test(model, test_loader, criterion, device)print(f'Epoch {epoch+1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%')# 绘制所有 iteration 的损失曲线plot_iter_losses(all_iter_losses, iter_indices)# 保留原 epoch 级曲线(可选)# plot_metrics(train_losses, test_losses, train_accuracies, test_accuracies, epochs)return epoch_test_acc # 返回最终测试准确率# 6. 测试模型
def test(model, test_loader, criterion, device):model.eval() # 设置为评估模式test_loss = 0correct = 0total = 0with torch.no_grad(): # 不计算梯度,节省内存和计算资源for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()avg_loss = test_loss / len(test_loader)accuracy = 100. * correct / totalreturn avg_loss, accuracy # 返回损失和准确率# 7.绘制每个 iteration 的损失曲线
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序号)')plt.ylabel('损失值')plt.title('每个 Iteration 的训练损失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 8. 执行训练和测试(设置 epochs=2 验证效果)
epochs = 2
print("开始训练模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, device, epochs)
print(f"训练完成!最终测试准确率: {final_accuracy:.2f}%")
2.彩色图片的规范写法
彩色的通道也是在第一步被直接展平,其他代码一致
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 设置中文字体支持
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题# 1. 数据预处理
transform = transforms.Compose([transforms.ToTensor(), # 转换为张量transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 标准化处理
])# 2. 加载CIFAR-10数据集
train_dataset = datasets.CIFAR10(root='./data',train=True,download=True,transform=transform
)test_dataset = datasets.CIFAR10(root='./data',train=False,transform=transform
)# 3. 创建数据加载器
batch_size = 64
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# 4. 定义MLP模型(适应CIFAR-10的输入尺寸)
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten() # 将3x32x32的图像展平为3072维向量self.layer1 = nn.Linear(3072, 512) # 第一层:3072个输入,512个神经元self.relu1 = nn.ReLU()self.dropout1 = nn.Dropout(0.2) # 添加Dropout防止过拟合self.layer2 = nn.Linear(512, 256) # 第二层:512个输入,256个神经元self.relu2 = nn.ReLU()self.dropout2 = nn.Dropout(0.2)self.layer3 = nn.Linear(256, 10) # 输出层:10个类别def forward(self, x):# 第一步:将输入图像展平为一维向量x = self.flatten(x) # 输入尺寸: [batch_size, 3, 32, 32] → [batch_size, 3072]# 第一层全连接 + 激活 + Dropoutx = self.layer1(x) # 线性变换: [batch_size, 3072] → [batch_size, 512]x = self.relu1(x) # 应用ReLU激活函数x = self.dropout1(x) # 训练时随机丢弃部分神经元输出# 第二层全连接 + 激活 + Dropoutx = self.layer2(x) # 线性变换: [batch_size, 512] → [batch_size, 256]x = self.relu2(x) # 应用ReLU激活函数x = self.dropout2(x) # 训练时随机丢弃部分神经元输出# 第三层(输出层)全连接x = self.layer3(x) # 线性变换: [batch_size, 256] → [batch_size, 10]return x # 返回未经过Softmax的logits# 检查GPU是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 初始化模型
model = MLP()
model = model.to(device) # 将模型移至GPU(如果可用)criterion = nn.CrossEntropyLoss() # 交叉熵损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam优化器# 5. 训练模型(记录每个 iteration 的损失)
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):model.train() # 设置为训练模式# 记录每个 iteration 的损失all_iter_losses = [] # 存储所有 batch 的损失iter_indices = [] # 存储 iteration 序号for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device) # 移至GPUoptimizer.zero_grad() # 梯度清零output = model(data) # 前向传播loss = criterion(output, target) # 计算损失loss.backward() # 反向传播optimizer.step() # 更新参数# 记录当前 iteration 的损失iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1)# 统计准确率和损失running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()# 每100个批次打印一次训练信息if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx+1):.4f}')# 计算当前epoch的平均训练损失和准确率epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / total# 测试阶段model.eval() # 设置为评估模式test_loss = 0correct_test = 0total_test = 0with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total_test += target.size(0)correct_test += predicted.eq(target).sum().item()epoch_test_loss = test_loss / len(test_loader)epoch_test_acc = 100. * correct_test / total_testprint(f'Epoch {epoch+1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%')# 绘制所有 iteration 的损失曲线plot_iter_losses(all_iter_losses, iter_indices)return epoch_test_acc # 返回最终测试准确率# 6. 绘制每个 iteration 的损失曲线
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序号)')plt.ylabel('损失值')plt.title('每个 Iteration 的训练损失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 7. 执行训练和测试
epochs = 20 # 增加训练轮次以获得更好效果
print("开始训练模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, device, epochs)
print(f"训练完成!最终测试准确率: {final_accuracy:.2f}%")# # 保存模型
torch.save(model.state_dict(), 'cifar10_mlp_model.pth')
print("模型已保存为: cifar10_mlp_model.pth")
开始训练模型...
Epoch: 1/20 | Batch: 100/782 | 单Batch损失: 1.7904 | 累计平均损失: 1.9090
Epoch: 1/20 | Batch: 200/782 | 单Batch损失: 1.6536 | 累计平均损失: 1.8282
Epoch: 1/20 | Batch: 300/782 | 单Batch损失: 1.7602 | 累计平均损失: 1.7951
Epoch: 1/20 | Batch: 400/782 | 单Batch损失: 1.4138 | 累计平均损失: 1.7680
Epoch: 1/20 | Batch: 500/782 | 单Batch损失: 1.7272 | 累计平均损失: 1.7464
Epoch: 1/20 | Batch: 600/782 | 单Batch损失: 1.5540 | 累计平均损失: 1.7293
Epoch: 1/20 | Batch: 700/782 | 单Batch损失: 1.5621 | 累计平均损失: 1.7149
Epoch 1/20 完成 | 训练准确率: 39.76% | 测试准确率: 45.72%
Epoch: 2/20 | Batch: 100/782 | 单Batch损失: 1.4234 | 累计平均损失: 1.4822
Epoch: 2/20 | Batch: 200/782 | 单Batch损失: 1.7541 | 累计平均损失: 1.4845
Epoch: 2/20 | Batch: 300/782 | 单Batch损失: 1.6140 | 累计平均损失: 1.4740
Epoch: 2/20 | Batch: 400/782 | 单Batch损失: 1.2613 | 累计平均损失: 1.4687
Epoch: 2/20 | Batch: 500/782 | 单Batch损失: 1.4625 | 累计平均损失: 1.4652
Epoch: 2/20 | Batch: 600/782 | 单Batch损失: 1.5894 | 累计平均损失: 1.4621
Epoch: 2/20 | Batch: 700/782 | 单Batch损失: 1.4148 | 累计平均损失: 1.4607
Epoch 2/20 完成 | 训练准确率: 48.09% | 测试准确率: 48.80%
Epoch: 3/20 | Batch: 100/782 | 单Batch损失: 1.5773 | 累计平均损失: 1.3501
Epoch: 3/20 | Batch: 200/782 | 单Batch损失: 1.4302 | 累计平均损失: 1.3547
Epoch: 3/20 | Batch: 300/782 | 单Batch损失: 1.3767 | 累计平均损失: 1.3573
Epoch: 3/20 | Batch: 400/782 | 单Batch损失: 1.3314 | 累计平均损失: 1.3523
Epoch: 3/20 | Batch: 500/782 | 单Batch损失: 1.6178 | 累计平均损失: 1.3496
Epoch: 3/20 | Batch: 600/782 | 单Batch损失: 1.4505 | 累计平均损失: 1.3465
Epoch: 3/20 | Batch: 700/782 | 单Batch损失: 1.1824 | 累计平均损失: 1.3452
Epoch 3/20 完成 | 训练准确率: 52.37% | 测试准确率: 50.56%
Epoch: 4/20 | Batch: 100/782 | 单Batch损失: 1.2351 | 累计平均损失: 1.2093
Epoch: 4/20 | Batch: 200/782 | 单Batch损失: 1.1662 | 累计平均损失: 1.2265
Epoch: 4/20 | Batch: 300/782 | 单Batch损失: 1.0464 | 累计平均损失: 1.2388
Epoch: 4/20 | Batch: 400/782 | 单Batch损失: 1.1036 | 累计平均损失: 1.2433
Epoch: 4/20 | Batch: 500/782 | 单Batch损失: 1.1212 | 累计平均损失: 1.2446
Epoch: 4/20 | Batch: 600/782 | 单Batch损失: 1.0947 | 累计平均损失: 1.2491
Epoch: 4/20 | Batch: 700/782 | 单Batch损失: 1.1910 | 累计平均损失: 1.2516
Epoch 4/20 完成 | 训练准确率: 55.61% | 测试准确率: 51.33%
Epoch: 5/20 | Batch: 100/782 | 单Batch损失: 1.0214 | 累计平均损失: 1.1296
Epoch: 5/20 | Batch: 200/782 | 单Batch损失: 1.1460 | 累计平均损失: 1.1433
Epoch: 5/20 | Batch: 300/782 | 单Batch损失: 1.4491 | 累计平均损失: 1.1637
Epoch: 5/20 | Batch: 400/782 | 单Batch损失: 1.2085 | 累计平均损失: 1.1706
Epoch: 5/20 | Batch: 500/782 | 单Batch损失: 1.0740 | 累计平均损失: 1.1654
Epoch: 5/20 | Batch: 600/782 | 单Batch损失: 1.2676 | 累计平均损失: 1.1696
Epoch: 5/20 | Batch: 700/782 | 单Batch损失: 1.2532 | 累计平均损失: 1.1692
Epoch 5/20 完成 | 训练准确率: 58.37% | 测试准确率: 51.46%
Epoch: 6/20 | Batch: 100/782 | 单Batch损失: 1.0454 | 累计平均损失: 1.0594
Epoch: 6/20 | Batch: 200/782 | 单Batch损失: 1.0509 | 累计平均损失: 1.0537
Epoch: 6/20 | Batch: 300/782 | 单Batch损失: 1.0184 | 累计平均损失: 1.0596
Epoch: 6/20 | Batch: 400/782 | 单Batch损失: 1.1266 | 累计平均损失: 1.0651
Epoch: 6/20 | Batch: 500/782 | 单Batch损失: 1.0278 | 累计平均损失: 1.0729
Epoch: 6/20 | Batch: 600/782 | 单Batch损失: 1.1594 | 累计平均损失: 1.0795
Epoch: 6/20 | Batch: 700/782 | 单Batch损失: 0.8570 | 累计平均损失: 1.0858
Epoch 6/20 完成 | 训练准确率: 61.44% | 测试准确率: 52.64%
Epoch: 7/20 | Batch: 100/782 | 单Batch损失: 1.2671 | 累计平均损失: 0.9824
Epoch: 7/20 | Batch: 200/782 | 单Batch损失: 1.1727 | 累计平均损失: 0.9852
Epoch: 7/20 | Batch: 300/782 | 单Batch损失: 0.9716 | 累计平均损失: 0.9853
Epoch: 7/20 | Batch: 400/782 | 单Batch损失: 1.2981 | 累计平均损失: 0.9914
Epoch: 7/20 | Batch: 500/782 | 单Batch损失: 1.0398 | 累计平均损失: 0.9988
Epoch: 7/20 | Batch: 600/782 | 单Batch损失: 1.1840 | 累计平均损失: 1.0058
Epoch: 7/20 | Batch: 700/782 | 单Batch损失: 0.8444 | 累计平均损失: 1.0076
Epoch 7/20 完成 | 训练准确率: 63.90% | 测试准确率: 52.28%
Epoch: 8/20 | Batch: 100/782 | 单Batch损失: 1.0768 | 累计平均损失: 0.8986
Epoch: 8/20 | Batch: 200/782 | 单Batch损失: 0.7581 | 累计平均损失: 0.9011
Epoch: 8/20 | Batch: 300/782 | 单Batch损失: 1.0310 | 累计平均损失: 0.9126
Epoch: 8/20 | Batch: 400/782 | 单Batch损失: 1.0216 | 累计平均损失: 0.9196
Epoch: 8/20 | Batch: 500/782 | 单Batch损失: 0.9290 | 累计平均损失: 0.9230
Epoch: 8/20 | Batch: 600/782 | 单Batch损失: 1.1564 | 累计平均损失: 0.9321
Epoch: 8/20 | Batch: 700/782 | 单Batch损失: 0.9449 | 累计平均损失: 0.9341
Epoch 8/20 完成 | 训练准确率: 66.65% | 测试准确率: 53.76%
Epoch: 9/20 | Batch: 100/782 | 单Batch损失: 0.7789 | 累计平均损失: 0.8067
Epoch: 9/20 | Batch: 200/782 | 单Batch损失: 0.9299 | 累计平均损失: 0.8151
Epoch: 9/20 | Batch: 300/782 | 单Batch损失: 0.8397 | 累计平均损失: 0.8345
Epoch: 9/20 | Batch: 400/782 | 单Batch损失: 0.9787 | 累计平均损失: 0.8443
Epoch: 9/20 | Batch: 500/782 | 单Batch损失: 0.9820 | 累计平均损失: 0.8557
Epoch: 9/20 | Batch: 600/782 | 单Batch损失: 0.9470 | 累计平均损失: 0.8624
Epoch: 9/20 | Batch: 700/782 | 单Batch损失: 0.5111 | 累计平均损失: 0.8643
Epoch 9/20 完成 | 训练准确率: 68.94% | 测试准确率: 52.94%
Epoch: 10/20 | Batch: 100/782 | 单Batch损失: 0.7480 | 累计平均损失: 0.7373
Epoch: 10/20 | Batch: 200/782 | 单Batch损失: 0.8224 | 累计平均损失: 0.7505
Epoch: 10/20 | Batch: 300/782 | 单Batch损失: 0.6956 | 累计平均损失: 0.7619
Epoch: 10/20 | Batch: 400/782 | 单Batch损失: 0.6835 | 累计平均损失: 0.7747
Epoch: 10/20 | Batch: 500/782 | 单Batch损失: 0.7085 | 累计平均损失: 0.7842
Epoch: 10/20 | Batch: 600/782 | 单Batch损失: 0.8720 | 累计平均损失: 0.7947
Epoch: 10/20 | Batch: 700/782 | 单Batch损失: 0.9251 | 累计平均损失: 0.7987
Epoch 10/20 完成 | 训练准确率: 71.24% | 测试准确率: 53.55%
Epoch: 11/20 | Batch: 100/782 | 单Batch损失: 0.6318 | 累计平均损失: 0.6929
Epoch: 11/20 | Batch: 200/782 | 单Batch损失: 0.6757 | 累计平均损失: 0.6932
Epoch: 11/20 | Batch: 300/782 | 单Batch损失: 0.7484 | 累计平均损失: 0.7100
Epoch: 11/20 | Batch: 400/782 | 单Batch损失: 0.9914 | 累计平均损失: 0.7196
Epoch: 11/20 | Batch: 500/782 | 单Batch损失: 0.6336 | 累计平均损失: 0.7272
Epoch: 11/20 | Batch: 600/782 | 单Batch损失: 0.7916 | 累计平均损失: 0.7353
Epoch: 11/20 | Batch: 700/782 | 单Batch损失: 1.1167 | 累计平均损失: 0.7403
Epoch 11/20 完成 | 训练准确率: 73.29% | 测试准确率: 53.76%
Epoch: 12/20 | Batch: 100/782 | 单Batch损失: 0.4731 | 累计平均损失: 0.6154
Epoch: 12/20 | Batch: 200/782 | 单Batch损失: 0.8286 | 累计平均损失: 0.6266
Epoch: 12/20 | Batch: 300/782 | 单Batch损失: 0.6437 | 累计平均损失: 0.6312
Epoch: 12/20 | Batch: 400/782 | 单Batch损失: 0.8005 | 累计平均损失: 0.6481
Epoch: 12/20 | Batch: 500/782 | 单Batch损失: 0.6693 | 累计平均损失: 0.6617
Epoch: 12/20 | Batch: 600/782 | 单Batch损失: 0.9348 | 累计平均损失: 0.6692
Epoch: 12/20 | Batch: 700/782 | 单Batch损失: 0.7892 | 累计平均损失: 0.6763
Epoch 12/20 完成 | 训练准确率: 75.44% | 测试准确率: 52.22%
Epoch: 13/20 | Batch: 100/782 | 单Batch损失: 0.4983 | 累计平均损失: 0.5792
Epoch: 13/20 | Batch: 200/782 | 单Batch损失: 0.5304 | 累计平均损失: 0.5980
Epoch: 13/20 | Batch: 300/782 | 单Batch损失: 0.6533 | 累计平均损失: 0.5965
Epoch: 13/20 | Batch: 400/782 | 单Batch损失: 0.5487 | 累计平均损失: 0.6061
Epoch: 13/20 | Batch: 500/782 | 单Batch损失: 0.7773 | 累计平均损失: 0.6120
Epoch: 13/20 | Batch: 600/782 | 单Batch损失: 0.5234 | 累计平均损失: 0.6200
Epoch: 13/20 | Batch: 700/782 | 单Batch损失: 0.4946 | 累计平均损失: 0.6289
Epoch 13/20 完成 | 训练准确率: 77.42% | 测试准确率: 52.99%
Epoch: 14/20 | Batch: 100/782 | 单Batch损失: 0.5823 | 累计平均损失: 0.5240
Epoch: 14/20 | Batch: 200/782 | 单Batch损失: 0.4711 | 累计平均损失: 0.5373
Epoch: 14/20 | Batch: 300/782 | 单Batch损失: 0.6223 | 累计平均损失: 0.5475
Epoch: 14/20 | Batch: 400/782 | 单Batch损失: 0.7798 | 累计平均损失: 0.5570
Epoch: 14/20 | Batch: 500/782 | 单Batch损失: 0.7869 | 累计平均损失: 0.5654
Epoch: 14/20 | Batch: 600/782 | 单Batch损失: 0.5371 | 累计平均损失: 0.5741
Epoch: 14/20 | Batch: 700/782 | 单Batch损失: 0.6660 | 累计平均损失: 0.5780
Epoch 14/20 完成 | 训练准确率: 79.11% | 测试准确率: 53.29%
Epoch: 15/20 | Batch: 100/782 | 单Batch损失: 0.6153 | 累计平均损失: 0.4789
Epoch: 15/20 | Batch: 200/782 | 单Batch损失: 0.5215 | 累计平均损失: 0.4800
Epoch: 15/20 | Batch: 300/782 | 单Batch损失: 0.4932 | 累计平均损失: 0.4922
Epoch: 15/20 | Batch: 400/782 | 单Batch损失: 0.5748 | 累计平均损失: 0.5021
Epoch: 15/20 | Batch: 500/782 | 单Batch损失: 0.3828 | 累计平均损失: 0.5131
Epoch: 15/20 | Batch: 600/782 | 单Batch损失: 0.6003 | 累计平均损失: 0.5231
Epoch: 15/20 | Batch: 700/782 | 单Batch损失: 0.4369 | 累计平均损失: 0.5310
Epoch 15/20 完成 | 训练准确率: 80.88% | 测试准确率: 52.40%
Epoch: 16/20 | Batch: 100/782 | 单Batch损失: 0.4601 | 累计平均损失: 0.4886
Epoch: 16/20 | Batch: 200/782 | 单Batch损失: 0.4358 | 累计平均损失: 0.4687
Epoch: 16/20 | Batch: 300/782 | 单Batch损失: 0.5492 | 累计平均损失: 0.4742
Epoch: 16/20 | Batch: 400/782 | 单Batch损失: 0.5176 | 累计平均损失: 0.4740
Epoch: 16/20 | Batch: 500/782 | 单Batch损失: 0.4523 | 累计平均损失: 0.4816
Epoch: 16/20 | Batch: 600/782 | 单Batch损失: 0.3831 | 累计平均损失: 0.4884
Epoch: 16/20 | Batch: 700/782 | 单Batch损失: 0.6017 | 累计平均损失: 0.4974
Epoch 16/20 完成 | 训练准确率: 82.17% | 测试准确率: 52.83%
Epoch: 17/20 | Batch: 100/782 | 单Batch损失: 0.3020 | 累计平均损失: 0.4483
Epoch: 17/20 | Batch: 200/782 | 单Batch损失: 0.5741 | 累计平均损失: 0.4420
Epoch: 17/20 | Batch: 300/782 | 单Batch损失: 0.3837 | 累计平均损失: 0.4373
Epoch: 17/20 | Batch: 400/782 | 单Batch损失: 0.4105 | 累计平均损失: 0.4478
Epoch: 17/20 | Batch: 500/782 | 单Batch损失: 0.5657 | 累计平均损失: 0.4576
Epoch: 17/20 | Batch: 600/782 | 单Batch损失: 0.8343 | 累计平均损失: 0.4670
Epoch: 17/20 | Batch: 700/782 | 单Batch损失: 0.4963 | 累计平均损失: 0.4722
Epoch 17/20 完成 | 训练准确率: 83.35% | 测试准确率: 53.14%
Epoch: 18/20 | Batch: 100/782 | 单Batch损失: 0.5670 | 累计平均损失: 0.4302
Epoch: 18/20 | Batch: 200/782 | 单Batch损失: 0.3529 | 累计平均损失: 0.4118
Epoch: 18/20 | Batch: 300/782 | 单Batch损失: 0.3723 | 累计平均损失: 0.4149
Epoch: 18/20 | Batch: 400/782 | 单Batch损失: 0.4320 | 累计平均损失: 0.4268
Epoch: 18/20 | Batch: 500/782 | 单Batch损失: 0.2337 | 累计平均损失: 0.4275
Epoch: 18/20 | Batch: 600/782 | 单Batch损失: 0.3357 | 累计平均损失: 0.4324
Epoch: 18/20 | Batch: 700/782 | 单Batch损失: 0.4760 | 累计平均损失: 0.4395
Epoch 18/20 完成 | 训练准确率: 84.29% | 测试准确率: 52.75%
Epoch: 19/20 | Batch: 100/782 | 单Batch损失: 0.4392 | 累计平均损失: 0.3653
Epoch: 19/20 | Batch: 200/782 | 单Batch损失: 0.4176 | 累计平均损失: 0.3638
Epoch: 19/20 | Batch: 300/782 | 单Batch损失: 0.5161 | 累计平均损失: 0.3729
Epoch: 19/20 | Batch: 400/782 | 单Batch损失: 0.4500 | 累计平均损失: 0.3827
Epoch: 19/20 | Batch: 500/782 | 单Batch损失: 0.3229 | 累计平均损失: 0.3938
Epoch: 19/20 | Batch: 600/782 | 单Batch损失: 0.4433 | 累计平均损失: 0.3977
Epoch: 19/20 | Batch: 700/782 | 单Batch损失: 0.5879 | 累计平均损失: 0.4078
Epoch 19/20 完成 | 训练准确率: 85.20% | 测试准确率: 52.77%
Epoch: 20/20 | Batch: 100/782 | 单Batch损失: 0.3346 | 累计平均损失: 0.3452
Epoch: 20/20 | Batch: 200/782 | 单Batch损失: 0.4884 | 累计平均损失: 0.3555
Epoch: 20/20 | Batch: 300/782 | 单Batch损失: 0.3396 | 累计平均损失: 0.3539
Epoch: 20/20 | Batch: 400/782 | 单Batch损失: 0.5147 | 累计平均损失: 0.3635
Epoch: 20/20 | Batch: 500/782 | 单Batch损失: 0.4240 | 累计平均损失: 0.3694
Epoch: 20/20 | Batch: 600/782 | 单Batch损失: 0.5196 | 累计平均损失: 0.3768
Epoch: 20/20 | Batch: 700/782 | 单Batch损失: 0.3149 | 累计平均损失: 0.3807
Epoch 20/20 完成 | 训练准确率: 86.26% | 测试准确率: 52.61%

训练完成!最终测试准确率: 52.61%
模型已保存为: cifar10_mlp_model.pth
# 7. 执行训练和测试
epochs = 20 # 增加训练轮次以获得更好效果
print("开始训练模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, device, epochs)
print(f"训练完成!最终测试准确率: {final_accuracy:.2f}%")
发现MLP(多层感知机)在图像任务上表现较差(即使增加深度和轮次也只能达到 50-55% 准确率),主要原因与图像数据的空间特性和MLP 的结构缺陷密切相关。
1. MLP 的每一层都是全连接层,输入图像会被展平为一维向量(如 CIFAR-10 的 32x32x3 图像展平为 3072 维向量)。图像中相邻像素通常具有强相关性(如边缘、纹理),但 MLP 将所有像素视为独立特征,无法利用局部空间结构。例如,识别 “汽车轮胎” 需要邻近像素的组合信息,而 MLP 需通过大量参数单独学习每个像素的关联,效率极低。
2. 深层 MLP 的参数规模呈指数级增长,容易过拟合
接下来学习CNN架构,CNN架构的参数规模相对较小,且训练速度更快,而且CNN架构可以解决图像识别问题,而MLP不能。
@浙大疏锦行
