实验内容与完成情况:
- 环境安装步骤
- 配置安装PyTorch软件。采用pip安装的Python+CPU版,在终端输入:pip3 install torch torchvision torchaudio
(已安装,装的时候没有截图)
- 根据代码提示装包
- 实验代码
-
import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt # 数据变换:将图片转换为Tensor并进行归一化处理 transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]) # 加载训练和测试数据集 trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True) # 训练集的DataLoader testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False) # 测试集的DataLoader # 定义简单的卷积神经网络(CNN)模型 class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() # 定义卷积层、池化层、全连接层等 self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1) # 第一层卷积 self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1) # 第二层卷积 self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0) # 最大池化层 self.fc1 = nn.Linear(64 * 7 * 7, 128) # 第一个全连接层 self.fc2 = nn.Linear(128, 10) # 第二个全连接层(输出10个类) self.relu = nn.ReLU() # 激活函数 def forward(self, x): # 定义前向传播过程 x = self.pool(self.relu(self.conv1(x))) # 第一层卷积 -> ReLU -> 池化 x = self.pool(self.relu(self.conv2(x))) # 第二层卷积 -> ReLU -> 池化 x = x.view(-1, 64 * 7 * 7) # 展平处理 x = self.relu(self.fc1(x)) # 第一个全连接层 -> ReLU x = self.fc2(x) # 第二个全连接层 return x # 实例化模型、定义损失函数和优化器 net = SimpleCNN() criterion = nn.CrossEntropyLoss() # 损失函数:交叉熵损失 optimizer = optim.Adam(net.parameters(), lr=0.001) # 优化器:Adam,学习率为0.001 # 训练过程 num_epochs = 5 # 训练轮数 for epoch in range(num_epochs): running_loss = 0.0 for i, (inputs, labels) in enumerate(trainloader, 0): optimizer.zero_grad() # 清零梯度缓存 outputs = net(inputs) # 前向传播 loss = criterion(outputs, labels) # 计算损失 loss.backward() # 反向传播 optimizer.step() # 更新参数 running_loss += loss.item() if i % 100 == 99: # 每100批次打印一次损失 print(f'Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}], Loss: {running_loss / 100:.4f}') running_loss = 0.0 print("Finished Training") # 测试过程:计算测试集上的准确率 correct = 0 total = 0 with torch.no_grad(): # 不计算梯度 for inputs, labels in testloader: outputs = net(inputs) # 前向传播 _, predicted = torch.max(outputs.data, 1) # 获取最大概率的类别 total += labels.size(0) # 累加总样本数 correct += (predicted == labels).sum().item() # 累加正确预测的数量 print(f'Accuracy on the 10000 test images: {100 * correct / total:.2f}%') # 可视化部分:显示前4张测试图像及其预测标签 dataiter = iter(testloader) images, labels = next(dataiter) # 打印前4张图像 for i in range(4): plt.subplot(1, 4, i+1) plt.imshow(images[i].numpy().squeeze(), cmap='gray') # 显示灰度图像 plt.title(f'Predicted: {predicted[i].item()}') # 显示预测结果 plt.axis('off') plt.show()
运行截图
-
- 不同超参数(如学习率、批次大小)对模型训练的影
- 超参数的选择需要根据任务和资源进行调整,以优化训练效率和模型性能。
学习率影响模型训练的速度和稳定性。较大学习率可能导致训练不稳定,较小则会收敛慢。动态调整学习率或使用优化器如Adam可以帮助平衡这一点。
批次大小决定每次训练使用的数据量。小批次增加噪声,有助于逃避局部最优,但训练波动较大;大批次计算精度高,但训练可能更慢,且容易过拟合。
优化器影响梯度更新方式。SGD适合大规模数据集,但可能较慢;而Adam则更适合大多数任务,能够自动调整学习率,提高训练效率。
正则化防止过拟合,常用方法有L2正则化和Dropout。它们通过限制权重大小或随机丢弃神经元来提升模型泛化能力。
训练轮数决定训练迭代次数。训练轮数不足会导致欠拟合,过多则可能导致过拟合。通过交叉验证和早停策略,可以选择合适的轮数。