文章目录
- 🧡🧡实验内容🧡🧡
- 🧡🧡代码🧡🧡
- 🧡🧡分析结果🧡🧡
- 🧡🧡实验总结🧡🧡
🧡🧡实验内容🧡🧡
编写卷积神经网络分类,实现对 MNIST 数据集分类的操作。
🧡🧡代码🧡🧡
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.optim as optim
from torch import nn, optim
from time import time# 准备数据集
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,))
])
train_dataset = datasets.MNIST(root='../dataset/mnist/',train=True,download=True,transform=transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)# @title CNN net
class CNN_net(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1, 16, kernel_size=5) # 卷积1self.pooling1 = nn.MaxPool2d(2) # 最大池化self.relu1 = nn.ReLU() # 激活self.conv2 = nn.Conv2d(16, 32, kernel_size=5)self.pooling2 = nn.MaxPool2d(2)self.relu2 = nn.ReLU()self.fc = nn.Linear(512, 10) # 全连接def forward(self, x):batch_size = x.size(0)x = self.conv1(x)x = self.pooling1(x)x = self.relu1(x)x = self.conv2(x)x = self.pooling2(x)x = self.relu2(x)x = x.view(batch_size, -1)x = self.fc(x)return xmodel = CNN_net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)def train(epoch):time0 = time() # 记录下当前时间loss_list = []for e in range(epoch):running_loss = 0.0for images, labels in train_loader:outputs = model(images) # 前向传播获取预测值loss = criterion(outputs, labels) # 计算损失loss.backward() # 进行反向传播optimizer.step() # 更新权重optimizer.zero_grad() # 清空梯度running_loss += loss.item() # 累加损失# 一轮循环结束后打印本轮的损失函数print("Epoch {} - Training loss: {}".format(e, running_loss / len(train_loader)))loss_list.append(running_loss / len(train_loader))# 打印总的训练时间print("\nTraining Time (in minutes) =", (time() - time0) / 60)# 绘制损失函数随训练轮数的变化图plt.plot(range(1, epoch + 1), loss_list)plt.xlabel('Epochs')plt.ylabel('Loss')plt.title('Training Loss')plt.show()train(5)
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as pltdef test():model.eval() # 将模型设置为评估模式correct = 0total = 0all_predicted = []all_labels = []with torch.no_grad():for images, labels in test_loader:outputs = model(images)_, predicted = torch.max(outputs.data, dim=1)total += labels.size(0)correct += (predicted == labels).sum().item()all_predicted.extend(predicted.tolist())all_labels.extend(labels.tolist())print('Model Accuracy =:%.4f' % (correct / total))# 绘制混淆矩阵cm = confusion_matrix(all_labels, all_predicted)plt.figure(figsize=(8, 6))sns.heatmap(cm, annot=True, fmt=".0f", cmap="Blues")plt.xlabel("Predicted Labels")plt.ylabel("True Labels")plt.title("Confusion Matrix")plt.show()test()
🧡🧡分析结果🧡🧡
数据预处理:
- 加载数据集:
加载torch库中自带的minst数据集- 转换数据:
先转为tensor变量(相当于直接除255归一化到值域为(0,1))
然后根据std=0.5,mean=0.5,再将值域标准化到(-1,1)。做这个实验时,上网了解发现minst最合适的的std和mean分别为0.1307, 0.3081,但为了与上个BP网络实验作为对照,本次实验依然采用std和mear均为0.5,并且它们的值对结果的影响没有很大。
设置基本参数:
构建CNN神经网络:
- 5 x 5的卷积核,输入通道为1,输出通道为16:此时图像矩经过卷积核后尺寸变成24 x 24。
- 2 x 2 的最大池化层:此时图像大小缩短一半,变成 12 x 12,通道数不变;
- 再次经过 5 x 5 的卷积核,输入通道为16,输出通道为32:此时图像尺寸经过卷积核后变成8 *8。
- 再次经过 2 x 2 的最大池化层:此时图像大小缩短一半,变成4 x 4,通道数不变;
- 最后将图像整型变换成向量,输入到全连接层中:输入一共有4 x 4 x 32 = 512 个元素,输出为10.
模型训练:
可见,虽然只经过5个epoch,但是花的时间为3.3min,跟BP神经网络训练15个epoch时间差不多。
模型评估:
准确率达98.26%,比BP神经网络97.65%要高
分析卷积层、池化层的层数、卷积核大小对分类准确率的影响
更改卷积层层数为2、池化层层数为2、卷积核大小为4:
def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1, 16, kernel_size=4) # 第一层卷积self.pooling1 = nn.MaxPool2d(2) # 第一层池化self.relu1 = nn.ReLU() # 激活self.conv2 = nn.Conv2d(16, 32, kernelsize=4) # 第二层卷积self.pooling2 = nn.MaxPool2d(2) # 第二层池化self.relu2 = nn.ReLU() # 激活self.fc = nn.Linear(512, 10) # 全连接
更改卷积层层数为2、池化层层数为2、卷积核大小为3:
def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1, 16, kernel_size=3) # 第一层卷积self.pooling1 = nn.MaxPool2d(2) # 第一层池化self.relu1 = nn.ReLU() # 激活self.conv2 = nn.Conv2d(16, 32, kernel_size=3) # 第二层卷积self.pooling2 = nn.MaxPool2d(2) # 第二层池化self.relu2 = nn.ReLU() # 激活self.fc = nn.Linear(512, 10) # 全连接
更改卷积层层数为3、池化层层数为3、卷积核大小为3:
def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1, 16, kernel_size=3) # 第一层卷积self.pooling1 = nn.MaxPool2d(2) # 第一层池化self.relu1 = nn.ReLU() # 激活self.conv2 = nn.Conv2d(16, 32, kernel_size=3) # 第二层卷积self.pooling2 = nn.MaxPool2d(2) # 第二层池化self.relu2 = nn.ReLU() # 激活self.conv3 = nn.Conv2d(32, 64, kernel_size=3) # 第三层卷积self.pooling3 = nn.MaxPool2d(2) # 第三层池化self.relu3 = nn.ReLU() # 激活self.fc = nn.Linear(64, 10) # 全连接
更改卷积层层数为4、池化层层数为4、卷积核大小为3:
def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1) # 第一层卷积self.pooling1 = nn.MaxPool2d(2) # 第一层池化self.relu1 = nn.ReLU() # 激活self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1) # 第二层卷积self.pooling2 = nn.MaxPool2d(2) # 第二层池化self.relu2 = nn.ReLU() # 激活self.conv3 = nn.Conv2d(32, 64, kernel_size=3, padding=1) # 第三层卷积self.pooling3 = nn.MaxPool2d(2) # 第三层池化self.relu3 = nn.ReLU() # 激活self.conv4 = nn.Conv2d(64, 128, kernel_size=3, padding=1) # 第四层卷积self.pooling4 = nn.MaxPool2d(2) # 第四层池化self.relu4 = nn.ReLU() # 激活self.fc = nn.Linear(128, 10) # 全连接
总结以上结果如下表(epoch=5):
由此可知:
- 卷积层数目:
当卷积层数目增加时,模型的复杂度也随之增加,有助于提取更加抽象和复杂的特征,从而提高分类准确率。观察实验结果,最为明显的是时间会显著增加,其次准确率在3层时较2层时降低,而在4层时又显著增加,考虑因为因为epoch过小,训练不充分;其次在4层时防止卷积后特征维度变少,增加了padding保留了最边边的数据特征,因此总体来说卷积层数增加,对准确率有较好的影响。- 池化层数目:
池化层的作用是逐渐降低特征图的空间维度,从而减少模型的参数数量,并且具有一定的平移不变性。在一定程度上,池化层可以帮助防止过拟合,但过多的池化层可能会导致信息丢失。池化层的数目往往和卷积层数目相关,在本实验中,其对准确率的影响同卷积层数目对准确率的影响。- 卷积核大小:
较大的卷积核大小可以捕获更大范围的特征,而较小的卷积核大小可以捕获更局部的特征。从实验结果看,相同卷积层和池化层数目下,卷积核更大的准确率会高一些,运行时间也有所增加。
🧡🧡实验总结🧡🧡
CNN卷积网络与BP神经网络的比较:
- 应用场景:
CNN: 卷积神经网络主要用于图像处理和计算机视觉任务。由于卷积层和池化层的设计,CNN能够有效提取图像中的局部特征,并具备平移不变性和局部连接的特点。
BP: 反向传播算法是一种用于训练神经网络的优化方法,可应用于各种机器学习任务,包括图像分类、语音识别、自然语言处理等。- 网络结构:
CNN: 卷积神经网络采用卷积层、池化层和全连接层等结构,通过卷积操作和权重共享有效减少了参数数量,并能够处理高维数据(如图像)。
BP: 反向传播算法通常用于训练多层前馈神经网络,其中每个神经元与下一层的所有神经元相连接。- 特点:
CNN: 卷积神经网络在处理图像等二维数据时具有较好的性能,能够自动学习图像中的特征,并具备一定的平移不变性和局部连接性。
BP: 反向传播算法是一种通用的神经网络训练方法,可以适用于多种任务,并且能够通过反向传播更新网络的权重,从而实现模型的优化和学习。
在对于分类minst手写数据集的实验中,CNN准确率更胜一筹,从而也看出CNN相较于BP神经网络在图像处理方面有较大的优势。但相比之下,CNN网络结构更加复杂,从而运行时间花费更多(如两次实验中,epoch=15的BP神经网络与epoch=5的CNN网络花费时间均为3到4minutes,可见CNN网络花费时间约为BP神经网络的3倍)