一、概念解释
1.局部感知:相较于全连接神经网络,卷积神经网络中相邻两层神经元之间的神经元只是部分连接,只感知局部,而不像全连接神经网络那样获取所有神经元之间的信息。也就是说,卷积神经网络中只是感知了局部,而不是整幅图像。卷积神经网络中局部感知的实现是通过卷积核“互相关”操作实现的。
2.权值共享:在卷积神经网络中,对输入的图片进行卷积时,对于同一个特征的提取,卷积核的参数是共享的,即卷积核中的参数是相同的。
3.池化带来哪些好处和坏处?
好处:
1.减少计算复杂度:池化可以起到降维的作用,减少参数量。
2.防止过拟合:通过减少模型的参数量,限制模型对训练数据的过拟合。
3. 特征提取,从输入的数据中提取出重要特征。
坏处:
会造成细节的信息丢失,池化操作会丢弃一部分特征激活,这可能导致位置信息的丢失。
4.全卷积网络
FCN对图像进行像素级的分类。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征 向 量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。最后逐个像素计算softmax分类的损失, 相当于每一个像素对应一个训练样本。
简单的来说,FCN与CNN的区域在把于CNN最后的全连接层换成卷积层。
4.低级特征、中级特征、高级特征
低级特征、中级特征和高级特征是特征提取的三个层次,分别对应于神经网络的底层、 中间层和较深层次。
低级特征主要包含图像的底层信息,如颜色、纹理等。这些特征是图像中最基本的、最 直观的特征,通常用于描述图像的表面信息。
中级特征往往包括对象信息,以及形状和空间信息等。它们通常是在网络的中间层次进 行提取的特征,具有比低级特征更高层次的抽象和语义含义。中级特征可以将低级特征组合 起 来,形成更具有代表性和抽象性的特征表示。
高级特征往往包含对象内在的语义信息。这些特征是在神经网络的较深层次中提取的抽 象和语义丰富的特征表示。它们通过对中级特征的进一步组合和整合,能够对整体图像的语 义 信息和高层次结构进行建模。
这三个层次的特征分别对应于神经网络的不同层次,从低级到高级,从局部到整体,从 表面信息到语义信息,逐渐提升对图像的理解和抽象表示。
5.多通道。N输入,M输出是如何实现的?
对于N个输入通道,每个通道都有自己的输入数据,这些数据通过独立的卷积层进行特 征提取。然后,这些特征图会被拼接(concatenation)或者融合(fusion)起来,形成更具 有代表性的特征表示。这个过程可以在网络的不同层次中进行多次,以逐步提取和整合更 高级的特征信息。
6.1x1的卷积核有什么作用
降维;增加非线性(接一个非线性激活函数)。
二、使用CNN进行XO识别
1、已有的网络模型复现:
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import transforms, datasets
transforms = transforms.Compose([
transforms.ToTensor(), # 把图片进行归一化,并把数据转换成Tensor类型
transforms.Grayscale(1) # 把图片 转为灰度图
])
data_train = datasets.ImageFolder(r"D:\BaiduNetdiskDownload\training_data_sm\train_data", transforms)
data_test = datasets.ImageFolder(r"D:\BaiduNetdiskDownload\training_data_sm\test_data", transforms)
train_loader = DataLoader(data_train, batch_size=64, shuffle=True)
test_loader = DataLoader(data_test, batch_size=64, shuffle=True)
for i, data in enumerate(train_loader):
images, labels = data
print(images.shape)
print(labels.shape)
break
for i, data in enumerate(test_loader):
images, labels = data
print(images.shape)
print(labels.shape)
break
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(1, 9, 3)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(9, 5, 3)
self.relu = nn.ReLU()
self.fc1 = nn.Linear(27*27*5, 1200)
self.fc2 = nn.Linear(1200, 64)
self.fc3 = nn.Linear(64, 2)
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = self.pool(self.relu(self.conv2(x)))
x = x.view(-1,27*27*5)
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.fc3(x)
return x
model = CNN()
loss = nn.CrossEntropyLoss()
opti = torch.optim.SGD(model.parameters(), lr=0.1)
epochs = 10
for epoch in range(epochs):
total_loss = 0
for i, data in enumerate(train_loader):
images, labels = data
out = model(images)
one_loss = loss(out, labels)
opti.zero_grad()
one_loss.backward()
opti.step()
total_loss += one_loss
if (i + 1) % 10 == 0:
print('[%d %5d] loss: %.3f' % (epoch + 1, i + 1, total_loss / 100))
total_loss = 0.0
print('finished train')
# 保存模型
torch.save(model, 'model.pth')
import matplotlib.pyplot as plt
# 读取模型
model_load = torch.load('model.pth')
# 读取一张图片 images[0],测试
print("labels[0] truth:\t", labels[0])
x = images[0].unsqueeze(0)
predicted = torch.max(model_load(x), 1)
print("labels[0] predict:\t", predicted.indices)
img = images[0].data.squeeze().numpy()
plt.imshow(img, cmap='gray')
plt.show()
model_load = torch.load('model.pth')
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model_load(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the test images: %f %%' % (100. * correct / total))
训练过程:
[1 10] loss: 0.069
[1 20] loss: 0.068
[2 10] loss: 0.055
[2 20] loss: 0.038
[3 10] loss: 0.039
[3 20] loss: 0.015
[4 10] loss: 0.005
[4 20] loss: 0.004
[5 10] loss: 0.004
[5 20] loss: 0.002
[6 10] loss: 0.001
[6 20] loss: 0.003
[7 10] loss: 0.001
[7 20] loss: 0.001
[8 10] loss: 0.001
[8 20] loss: 0.001
[9 10] loss: 0.001
[9 20] loss: 0.001
[10 10] loss: 0.000
[10 20] loss: 0.000
finished train
Loss变化:
测试集上的准确率:
Accuracy of the network on the test images: 100.000000 %
2.更改网络模型:增加一个卷积层
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(1, 9, 3)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(9, 5, 3)
self.conv3=nn.Conv2d(5,2,3)
self.relu = nn.ReLU()
self.fc1 = nn.Linear(12*12*2, 1200)
self.fc2 = nn.Linear(1200, 64)
self.fc3 = nn.Linear(64, 2)
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = self.pool(self.relu(self.conv2(x)))
x=self.pool(self.relu(self.conv3(x)))
x = x.view(-1,12*12*2)
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.fc3(x)
return x
训练结果:
[1 10] loss: 0.069
[1 20] loss: 0.069
[2 10] loss: 0.068
[2 20] loss: 0.067
[3 10] loss: 0.050
[3 20] loss: 0.035
[4 10] loss: 0.007
[4 20] loss: 0.009
[5 10] loss: 0.004
[5 20] loss: 0.003
[6 10] loss: 0.001
[6 20] loss: 0.002
[7 10] loss: 0.001
[7 20] loss: 0.001
[8 10] loss: 0.000
[8 20] loss: 0.000
[9 10] loss: 0.000
[9 20] loss: 0.000
[10 10] loss: 0.000
[10 20] loss: 0.000
finished train
labels[0] truth: tensor(0)
labels[0] predict: tensor([0])
Accuracy of the network on the test images: 100.000000 %
Loss变化:
从以上两个损失值变化曲线来看,后者的损失值下降会更快一些,模型的收敛速度更快。
3.去掉池化层
准确率只有百分之五十了。
Loss:
去掉池化层之后,模型训练的速度变得非常慢,还导致损失值相对比较高。由此可见,汇聚层对加快模型收敛速度和降低参数量都有着非常重要的作用。
4、修改通道数等超参数
适当减少或者增加通道数,模型的损失值下降速度变化不大,准确率基本上都维持在了100%。学习率调大的话,很容易导致模型不收敛。
卷积后的特征图
激活之后的特征图
池化之后的特征图
部分卷积核:
根据实际测试,本实验中的模型不同层得到的特征区别并不大。
总结:
首先,这次实验让我对DataLoader这个函数有了更深的了解,知道这个批量加载的整个过程。批量加载完所有数据之后才是一轮。其次就是对卷积神经网络的整个流程更加熟悉,能熟练计算第一个全连接层的第一个参数量。
参考链接:
【2021-2022 春学期】人工智能-作业6:CNN实现XO识别