文章目录
(一) 问题描述(二) 设计简要描述(三) 程序清单(四) 结果分析(五) 调试报告(六) 实验小结(七) 参考资料(一) 问题描述
构建卷积神经网络实现MNIST手写数字分类。
(二) 设计简要描述
机器学习的三个基本步骤——
程序设计思路——(此图放大可看清)
(三) 程序清单
import torchimport torchvisionfrom torch.utils.data import DataLoaderimport matplotlib.pyplot as pltimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimn_epochs = 3 # 定义了学习算法在整个训练数据集中的工作次数batch_size_train = 64 # 1 <批量大小<训练集的大小 严格来说这个算小批量梯度下降,而不是SGDbatch_size_test = 1000learning_rate = 0.01momentum = 0.5 # Momentum可以加速 SGD, 并且抑制震荡'''可以使得梯度方向不变的维度上速度变快,梯度方向有所改变的维度上的更新速度变慢'''log_interval = 10random_seed = 1torch.manual_seed(random_seed)train_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./data/', train=True, download=True,transform=pose([torchvision.transforms.ToTensor(), # 用于将图片转换成Tensor格式的数据,并且进行了标准化处理torchvision.transforms.Normalize( # Normalize()用均值和标准偏差对张量图像进行归一化(0.1307,), (0.3081,)) # Normalize()转换使用的值0.1307和0.3081是MNIST数据集的全局平均值和标准偏差])),batch_size=batch_size_train, shuffle=True)test_loader = torch.utils.data.DataLoader(torchvision.datasets.MNIST('./data/', train=False, download=True,transform=pose([torchvision.transforms.ToTensor(),torchvision.transforms.Normalize((0.1307,), (0.3081,))])),batch_size=batch_size_test, shuffle=True)# 看看一批数据的形状'''examples = enumerate(test_loader)batch_idx, (example_data, example_targets) = next(examples)print(example_targets)print(example_data.shape)'''# 查看MNIST数据集中的图片'''fig = plt.figure()for i in range(6):plt.subplot(2, 3, i + 1)plt.tight_layout()plt.imshow(example_data[i][0], cmap='gray', interpolation='none')plt.title("Ground Truth: {}".format(example_targets[i]))plt.xticks([])plt.yticks([])plt.show()'''class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 10, kernel_size=5) # 三个参数的意思分别是:输入信号的通道,卷积产生的通道,卷积核的尺寸self.conv2 = nn.Conv2d(10, 20, kernel_size=5)self.conv2_drop = nn.Dropout2d() # 随机将输入张量中整个通道设置为0self.fc1 = nn.Linear(320, 50) # 全连接层采用线性函数self.fc2 = nn.Linear(50, 10) # 第一个参数是输入样本的大小,第二个是输出def forward(self, x): # forward()传递定义了使用给定的层和函数计算输出的方式x = F.relu(F.max_pool2d(self.conv1(x), 2)) # relu:Rectified Linear Unit,修正线性单元,是一种非线性激活函数x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))x = x.view(-1, 320)x = F.relu(self.fc1(x))x = F.dropout(x, training=self.training)x = self.fc2(x)return F.log_softmax(x) # softmax:输出是每个分类被取到的概率# 初始化网络和优化器network = Net()optimizer = optim.SGD(network.parameters(), lr=learning_rate, # SGD:Stochastic Gradient Descentmomentum=momentum)train_losses = []train_counter = []test_losses = []test_counter = [i * len(train_loader.dataset) for i in range(n_epochs + 1)]del test_counter[0]def train(epoch):network.train()for batch_idx, (data, target) in enumerate(train_loader):optimizer.zero_grad()output = network(data)loss = F.nll_loss(output, target)loss.backward()optimizer.step()if batch_idx % log_interval == 0:print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, batch_idx * len(data), len(train_loader.dataset),100. * batch_idx / len(train_loader), loss.item()))train_losses.append(loss.item())train_counter.append((batch_idx * 64) + ((epoch - 1) * len(train_loader.dataset)))torch.save(network.state_dict(), './model.pth')torch.save(optimizer.state_dict(), './optimizer.pth')def test():network.eval()test_loss = 0correct = 0with torch.no_grad():for data, target in test_loader:output = network(data)test_loss += F.nll_loss(output, target, size_average=False).item()pred = output.data.max(1, keepdim=True)[1]correct += pred.eq(target.data.view_as(pred)).sum()test_loss /= len(test_loader.dataset)test_losses.append(test_loss)print('\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(test_loss, correct, len(test_loader.dataset),100. * correct / len(test_loader.dataset)))for epoch in range(1, n_epochs + 1):train(epoch)test()fig = plt.figure()plt.plot(train_counter, train_losses, color='blue')plt.scatter(test_counter, test_losses, color='red')plt.legend(['Train Loss', 'Test Loss'], loc='upper right')plt.xlabel('number of training examples seen')plt.ylabel('negative log likelihood loss')plt.show()
(四) 结果分析
一批训练数据是一个形状张量
意味着有1000个例子的28x28像素的灰度(即没有rgb通道)
训练结果与测试结果
蓝色为训练集上损失值
红色为一轮训练后测试集上的损失值
一共训练了三轮
模型精度
第一轮训练后测试集上的精度
第二轮训练后测试集上的精度
第三轮训练后测试集上的精度
(五) 调试报告
在PyTorch中,构建网络的一个好方法是为我们希望构建的网络创建一个新类,再在类中导入一些子模块,以获得更具可读性的代码。报错:ValueError: x and y must be the same size定位:plt.scatter(test_counter, test_losses, color=‘red’)
分析:打印出test_counter和test_losses,发现test_counter多一个元素0
解决:在test_counter = [i * len(train_loader.dataset) for i in range(n_epochs + 1)]下面加一行
del test_counter[0]增加Dropout layers
其作用是随机将输入张量中部分元素设置为0。对于每次前向调用,被置0的元素都是随机的。
作用是可以提高特征图之间的独立程度,防止过拟合。
(六) 实验小结
本次实验使用了PyTorch框架,在实验指导书和官方文档的帮助下训练了一个精度还算不错的卷积神经网络模型,由两个卷积层一个dropout层两个池化层两个全连接层构成。弄清了epoch和batch的区别,epoch是对于整个训练集而言要训练多少次,取值范围是1到正无穷,batch是训练的最小单元,假设总样本量为total,batch_size的取值在1~total之间,一个epoch会进行total/batch_size回训练。(七) 参考资料
CSDN博客:/sxf1061700625/article/details/105870851
PyTorch官方文档:https://pytorch-cn.readthedocs.io/zh/latest/
如果觉得《PyTorch基础与简单应用:构建卷积神经网络实现MNIST手写数字分类》对你有帮助,请点赞、收藏,并留下你的观点哦!