【23-24 秋学期】NNDL 作业7 基于CNN的XO识别

一、用自己的语言解释以下概念


(一)、局部感知、权值共享

(1)局部感知

定义:在进行卷积计算的时候,将图片划分为一个个的区域进行计算/考虑;

由于越是接近的像素点之间的关联性越强, 反之则越弱. 所以我们选择先进行局部感知, 然后在更高层(FC层)将这些局部信息综合起来得到全局信息的方式.【来自深度学习之卷积神经网络(Convolutional Neural Networks, CNN) - 知乎 (zhihu.com)】

感知的大小只有滑动窗口那么大。如下图所示:

可以看到,每次卷积核都是针对某一局部的数据窗口进行卷积,这就是所谓的CNN中的局部感知机制。

(2)权值共享

定义:在卷积神经网络中,同一个卷积核在整个输入数据的不同位置共享相同的权重参数。这意味着无论卷积核移动到哪个位置,它所使用的权重参数都是一样的。

以上文参考卷积神经网络(CNN)的相关概念 - 掘金 (juejin.cn)

如下图所示,移动的蓝框是局部感知,在计算第一个output时,W0不改变,这就是权值共享

【图来自https://cs231n.github.io/convolutional-networks/】

(二)、池化(子采样、降采样、汇聚)。会带来那些好处和坏处?

(1)池化对应定义

池化,也称子采样、降采样或汇聚,它的工作是取区域平均或最大,其目的是为了减少特征图,减少特征的数量,从而降低模型的计算量和参数量。

其中池化运算有以下几种:

  • 最大池化(Max Pooling)。取4个点的最大值。这是最常用的池化方法。
  • 均值池化(Mean Pooling)。取4个点的均值。
  • 高斯池化。借鉴高斯模糊的方法。不常用。
  • 可训练池化。训练函数 ff ,接受4个点为输入,出入1个点。不常用。

图来自【CS231n Convolutional Neural Networks for Visual Recognition】 

 上图是一个2*2且步长为2的最大池化。

文来自【卷积神经网络(CNN)的相关概念 - 掘金 (juejin.cn)】

(2)好处、坏处

上图可以看到池化操作具有特征不变性,可以保留主要特征,实现降维。

好处:

1)降维:池化减小图片的尺寸,主要用来降维。

2)减少计算量:通过池化操作,可以大幅降低后续层的计算复杂度,从而提高模型的训练速度。

3)保留主要特征:池化操作通常会采用最大池化或平均池化等方式,保留主要特征,降低了特征的冗余性。

4)减少过拟合:通过减少特征图的尺寸,池化层有助于减少模型对于训练数据中噪声和微小变化的敏感度,从而有助于防止过拟合。

图文来自【图像识别(七)| 池化层是什么?有什么作用? - 知乎 (zhihu.com)】

坏处:

池化层由于保留的是主要特征,会丧失一些细节信息,特别是在一些对细节敏感的任务中,可能需要谨慎使用或者考虑使用合适的池化方式。【文来自CNN中池化层的作用?-CSDN博客】

(三)、全卷积网络

定义全卷积网络(FCN)是从抽象的特征中恢复出每个像素所属的类别。即从图像级别的分类进一步延伸到像素级别的分类。

文来自【机器学习基础系列笔记7—全卷积网络FCN&U-Net结构 - 知乎 (zhihu.com)】

相比于CNNFCN相较于CNN来说,其将CNN最后几个用于输出概率的全连接层都改成了卷积层,这样网络的输出将是热力图而非类别;同时,为解决卷积和池化导致图像尺寸的变小,使用上采样方式对图像尺寸进行恢复。

它的基本思想是:1.不含全连接层(fc)的全卷积网络。可适应任意尺寸输入。 2.增大数据尺寸的反卷积(deconv)层。能够输出精细的结果。 3.结合不同深度层结果的跳级(skip)结构。同时确保鲁棒性和精确性。

文来自【卷积神经网络( CNN)与全卷积神经网络(FCN) (xjx100.cn)】

FCN网络结构:全卷积部分和反卷积部分。其中全卷积部分为一些经典的CNN网络(如VGG,ResNet等),用于提取特征;反卷积部分则是通过上采样得到原尺寸的语义分割图像。FCN的输入可以为任意尺寸的彩色图像,输出与输入尺寸相同,通道数为n(目标类别数)+1(背景)。

图文来自FCN(全卷积神经网络)详解-菜鸟笔记 (coonote.com) 

(四)、低级特征、中级特征、高级特征

网络中靠前的部分提取的是初级特征:例如边缘特征,是直接从原数据集中提取到的

网络中段提取的是中级特征,中级特征一定程度上是初级特征的再组合体现,比如纹理特征等。

而网络后端提取的是高级特征,高级特征可以看作中级特征的再组合,也更加抽象

文来自【分层特征提取Hierarchical Feature Extraction (baidu.com)】

还是这个图:

形象来说,首先尽可能找到与这个头像相关的各种边,这些边就是底层的特征(Low-level features),也就是低级特征;然后对这些底层特征进行组合,就可以看到鼻子、眼睛、耳朵等,它们是中间层特征(Mid-level features),也就是中级特征;最后,对鼻子、眼睛等进行组合,就可以组成各种各样的头像,也就是高层特征(High-level features)。这个时候,它就可以识别出各种人的头像了。

图文来自【白话版,聊聊“深度学习” (qq.com)】

在搜集了其他的博客后【来自【22-23 春学期】人工智能基础--AI作业8-卷积2-CSDN博客】里边对于这几个特征是这么说的:

低级特征通常指一些较为基础的、直接从原始数据中提取的特征,如颜色、纹理、边缘等,它们通常对于物体的分类或识别任务并不十分有效,但是可以作为中级特征的基础。

中级特征则是指基于低级特征构建的一些更高层次的特征,如形状、轮廓、纹理组合等,这些特征能够更好地描述物体的形态和结构,因此对于分类或识别任务的效果会更好。

高级特征则是指基于中级特征构建的更加抽象和复杂的特征,如物体的部件、结构、语义等,这些特征能够更好地描述物体的高层次语义信息,因此对于更加复杂的任务(如目标检测、语义分割等)的效果会更好。

(五)、多通道。N输入,M输出是如何实现的?

1)多输入、单输出

如图所示,输入通道有两个,那么需要两个卷积核,进行卷积运算,然后累加,得到一个输出。

当输入通道有多个时,因为对各个通道的结果做了累加,所以不论输入通道数是多少,输出通道数总是为 1。

那么如何得到多个输出呢? 

2)多输入、多输出

如上图所示,如果想要得到M个输出,那么只要准备M组卷积核,其中每一组卷积核的多少与有几个输入有关。 来自【精选】【从零开始学习深度学习】23. CNN中的多通道输入及多通道输出计算方式及1X1卷积层介绍_多通道cnn-CSDN博客

(六)、1×1的卷积核有什么作用

1)增加网络深度(增加非线性映射次数)

当1*1的卷积核但是是m层和n层的话,1×1卷积核可以起到一个跨通道聚合的作用。

2)升维/降维

1*1不会改变输出的尺寸,改变的是通道数。

1*1的卷积核将原本的数据量进行增加或者减少。这里看其他文章或者博客中都称之为升维、降维。但我觉得维度并没有改变,改变的只是 height × width × channels 中的 channels 这一个维度的大小而已。

上图文来自【1*1卷积核的作用-CSDN博客】

 图来自【深度笔记|1x1卷积核的作用 - 知乎 (zhihu.com)】

3)跨通道的信息交互

4)减少卷积核参数(简化模型)

降维,其实也是减少了参数,因为特征图少了,参数也自然跟着就减少,相当于在特征图的通道数上进行卷积,压缩特征图,二次提取特征,使得新特征图的特征表达更佳。

上边这四个作用是相互联系的,归根到底,1*1的卷积核实现了输出的降维或者升维,才会出现其他作用。

二、使用CNN进行XO识别


(一)、复现参考资料中的代码

(1)数据集

(2)模型构建

如上图所示,构建模型:

class Net(nn.Module):def __init__(self):super(Net, self).__init__()#定义卷积层self.conv1 = nn.Conv2d(1, 9, 3)#最大池化层self.maxpool = 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.maxpool(self.relu(self.conv1(x)))#第二次x = self.maxpool(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

 (3)训练模型

把数据分成了10个批次,然后进行循环,循环中嵌套的循环是计算平均损失函数:

model = Net()criterion = torch.nn.CrossEntropyLoss()  # 损失函数: 交叉熵损失函数
optimizer = optim.SGD(model.parameters(), lr=0.1)  # 优化函数:随机梯度下降epochs = 10
for epoch in range(epochs):running_loss = 0.0#计算平均损失值【累加,每10次一输出一清零】for i, data in enumerate(data_loader):images, label = dataout = model(images)loss = criterion(out, label)#计算损失optimizer.zero_grad()#清空之前的梯度loss.backward()optimizer.step()running_loss += loss.item()if (i + 1) % 10 == 0:print('[%d  %5d]   loss: %.3f' % (epoch + 1, i + 1, running_loss / 100))running_loss = 0.0print('finished train')# 保存模型
torch.save(model, 'model_name.pth')  # 保存的是模型, 不止是w和b权重值

 然后保存模型。

得到的输出为:
 

[1     10]   loss: 0.069
[1     20]   loss: 0.069
[2     10]   loss: 0.068
[2     20]   loss: 0.066
[3     10]   loss: 0.058
[3     20]   loss: 0.037
[4     10]   loss: 0.023
[4     20]   loss: 0.008
[5     10]   loss: 0.004
[5     20]   loss: 0.004
[6     10]   loss: 0.003
[6     20]   loss: 0.002
[7     10]   loss: 0.001
[7     20]   loss: 0.001
[8     10]   loss: 0.001
[8     20]   loss: 0.000
[9     10]   loss: 0.001
[9     20]   loss: 0.000
[10     10]   loss: 0.001
[10     20]   loss: 0.000
finished train

(4)测试模型

读取一张图片进行测试:

# 读取模型
model_load = torch.load('model_name.pth')
# 读取一张图片 images[0],测试
print("labels[0] truth:\t", labels[0])
x = images[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()

如下图所示,预测正确:

(5)计算准确率 

 “预测正确的数目除以总的数目”,得到准确率:

# 读取模型
model_load = torch.load('model_name.pth')correct = 0
total = 0
with torch.no_grad():  # 进行评测的时候网络不更新梯度for data in data_loader_test:  # 读取测试集images, labels = dataoutputs = model_load(images)_, predicted = torch.max(outputs.data, 1)  # 取出 最大值的索引 作为 分类结果total += labels.size(0)  # labels 的长度correct += (predicted == labels).sum().item()  # 预测正确的数目
print('Accuracy of the network on the  test images: %f %%' % (100. * correct / total))

得到准确率:

(6)查看训练好模型的特征图

# 看看每层的 卷积核 长相,特征图 长相
# 获取网络结构的特征矩阵并可视化
import torch
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from torchvision import transforms, datasets
import torch.nn as nn
from torch.utils.data import DataLoader#  定义图像预处理过程(要与网络模型训练过程中的预处理过程一致)transforms = transforms.Compose([transforms.ToTensor(),  # 把图片进行归一化,并把数据转换成Tensor类型transforms.Grayscale(1)  # 把图片 转为灰度图
])
path = r'training_data_sm'
data_train = datasets.ImageFolder(path, transform=transforms)
data_loader = DataLoader(data_train, batch_size=64, shuffle=True)
for i, data in enumerate(data_loader):images, labels = dataprint(images.shape)print(labels.shape)breakclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 9, 3)  # in_channel , out_channel , kennel_size , strideself.maxpool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(9, 5, 3)  # in_channel , out_channel , kennel_size , strideself.relu = nn.ReLU()self.fc1 = nn.Linear(27 * 27 * 5, 1200)  # full connect 1self.fc2 = nn.Linear(1200, 64)  # full connect 2self.fc3 = nn.Linear(64, 2)  # full connect 3def forward(self, x):outputs = []x = self.conv1(x)outputs.append(x)x = self.relu(x)outputs.append(x)x = self.maxpool(x)outputs.append(x)x = self.conv2(x)x = self.relu(x)x = self.maxpool(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 outputs# create model
model1 = Net()# load model weights加载预训练权重
# model_weight_path ="./AlexNet.pth"
model_weight_path = "model_name1.pth"
model1.load_state_dict(torch.load(model_weight_path))# 打印出模型的结构
print(model1)x = images[0]# forward正向传播过程
out_put = model1(x)for feature_map in out_put:# [N, C, H, W] -> [C, H, W]    维度变换im = np.squeeze(feature_map.detach().numpy())# [C, H, W] -> [H, W, C]im = np.transpose(im, [1, 2, 0])print(im.shape)# show 9 feature mapsplt.figure()for i in range(9):ax = plt.subplot(3, 3, i + 1)  # 参数意义:3:图片绘制行数,5:绘制图片列数,i+1:图的索引# [H, W, C]# 特征矩阵每一个channel对应的是一个二维的特征矩阵,就像灰度图像一样,channel=1# plt.imshow(im[:, :, i])plt.imshow(im[:, :, i], cmap='gray')plt.show()

输出:

实例化情况

torch.Size([64, 1, 116, 116])
torch.Size([64])
Net((conv1): Conv2d(1, 9, kernel_size=(3, 3), stride=(1, 1))(maxpool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv2): Conv2d(9, 5, kernel_size=(3, 3), stride=(1, 1))(relu): ReLU()(fc1): Linear(in_features=3645, out_features=1200, bias=True)(fc2): Linear(in_features=1200, out_features=64, bias=True)(fc3): Linear(in_features=64, out_features=2, bias=True)
)

 

(7)查看卷积核

# 看看每层的 卷积核 长相,特征图 长相
# 获取网络结构的特征矩阵并可视化
import torch
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from torchvision import transforms, datasets
import torch.nn as nn
from torch.utils.data import DataLoaderplt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号 #有中文出现的情况,需要u'内容
#  定义图像预处理过程(要与网络模型训练过程中的预处理过程一致)
transforms = transforms.Compose([transforms.ToTensor(),  # 把图片进行归一化,并把数据转换成Tensor类型transforms.Grayscale(1)  # 把图片 转为灰度图
])
path = r'training_data_sm'
data_train = datasets.ImageFolder(path, transform=transforms)
data_loader = DataLoader(data_train, batch_size=64, shuffle=True)
for i, data in enumerate(data_loader):images, labels = data# print(images.shape)# print(labels.shape)breakclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 9, 3)  # in_channel , out_channel , kennel_size , strideself.maxpool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(9, 5, 3)  # in_channel , out_channel , kennel_size , strideself.relu = nn.ReLU()self.fc1 = nn.Linear(27 * 27 * 5, 1200)  # full connect 1self.fc2 = nn.Linear(1200, 64)  # full connect 2self.fc3 = nn.Linear(64, 2)  # full connect 3def forward(self, x):outputs = []x = self.maxpool(self.relu(self.conv1(x)))# outputs.append(x)x = self.maxpool(self.relu(self.conv2(x)))outputs.append(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 outputs# create model
model1 = Net()# load model weights加载预训练权重
model_weight_path = "model_name1.pth"
model1.load_state_dict(torch.load(model_weight_path))x = images[0]# forward正向传播过程
out_put = model1(x)weights_keys = model1.state_dict().keys()
for key in weights_keys:print("key :", key)# 卷积核通道排列顺序 [kernel_number, kernel_channel, kernel_height, kernel_width]if key == "conv1.weight":weight_t = model1.state_dict()[key].numpy()print("weight_t.shape", weight_t.shape)k = weight_t[:, 0, :, :]  # 获取第一个卷积核的信息参数# show 9 kernel ,1 channelplt.figure()for i in range(9):ax = plt.subplot(3, 3, i + 1)  # 参数意义:3:图片绘制行数,5:绘制图片列数,i+1:图的索引plt.imshow(k[i, :, :], cmap='gray')title_name = 'kernel' + str(i) + ',channel1'plt.title(title_name)plt.show()if key == "conv2.weight":weight_t = model1.state_dict()[key].numpy()print("weight_t.shape", weight_t.shape)k = weight_t[:, :, :, :]  # 获取第一个卷积核的信息参数print(k.shape)print(k)plt.figure()for c in range(9):channel = k[:, c, :, :]for i in range(5):ax = plt.subplot(2, 3, i + 1)  # 参数意义:3:图片绘制行数,5:绘制图片列数,i+1:图的索引plt.imshow(channel[i, :, :], cmap='gray')title_name = 'kernel' + str(i) + ',channel' + str(c)plt.title(title_name)plt.show()

 输出:

卷积核

 

 

 

(二)、重新设计网络结构

(1)至少增加一个卷积层,卷积层达到三层以上

由于我在加入一层卷积层后,计算特征图尺寸一一直不对,然后舍友茜借了我一段代码:

import torch
import torch.nn as nn# 定义卷积层和池化层
conv1 = nn.Conv2d(1, 9, 3)
maxpool = nn.MaxPool2d(2, 2)
conv2 = nn.Conv2d(9, 5, 3)
conv3 = nn.Conv2d(5, 3, 3)
# 假设输入图像尺寸为 64x64
W_in, H_in = 116, 116# 计算特征图尺寸
x = torch.rand(1, 1, W_in, H_in)  # 构造一个输入张量
x = maxpool(nn.ReLU()(conv1(x)))
x = maxpool(nn.ReLU()(conv2(x)))
x = maxpool(nn.ReLU()(conv3(x)))output_size = x.size()[2:]  # 获取特征图的尺寸
print("Output feature map size:", output_size)

 可以得到对应的尺寸:

Output feature map size: torch.Size([12, 12])

在后边就不放代码了,只有构建模型部分进行了一点点修改:

import torch
import torch.nn as nn# 定义卷积层和池化层
conv1 = nn.Conv2d(1, 9, 3)
maxpool = nn.MaxPool2d(2, 2)
conv2 = nn.Conv2d(9, 5, 3)
conv3 = nn.Conv2d(5, 3, 3)
# 假设输入图像尺寸为 64x64
W_in, H_in = 116, 116# 计算特征图尺寸
x = torch.rand(1, 1, W_in, H_in)  # 构造一个输入张量
x = maxpool(nn.ReLU()(conv1(x)))
x = maxpool(nn.ReLU()(conv2(x)))
x = maxpool(nn.ReLU()(conv3(x)))output_size = x.size()[2:]  # 获取特征图的尺寸
print("Output feature map size:", output_size)

然后训练模型得到的损失:

[1     10]   loss: 0.051
[1     20]   loss: 0.045
[1     30]   loss: 0.039
[2     10]   loss: 0.045
[2     20]   loss: 0.041
[2     30]   loss: 0.044
[3     10]   loss: 0.042
[3     20]   loss: 0.046
[3     30]   loss: 0.042
[4     10]   loss: 0.040
[4     20]   loss: 0.045
[4     30]   loss: 0.043
[5     10]   loss: 0.040
[5     20]   loss: 0.044
[5     30]   loss: 0.045
[6     10]   loss: 0.045
[6     20]   loss: 0.041
[6     30]   loss: 0.044
[7     10]   loss: 0.043
[7     20]   loss: 0.047
[7     30]   loss: 0.037
[8     10]   loss: 0.037
[8     20]   loss: 0.046
[8     30]   loss: 0.044
[9     10]   loss: 0.042
[9     20]   loss: 0.046
[9     30]   loss: 0.042
[10     10]   loss: 0.041
[10     20]   loss: 0.045
[10     30]   loss: 0.041
finished train

效果不太好。 

然后参考了一下美女学霸NNDL 作业7 相关语言解释+基于CNN的XO识别代码复现-CSDN博客的,多增加了10轮次,效果很好:

[1     10]   loss: 0.069
[1     20]   loss: 0.069
[2     10]   loss: 0.069
[2     20]   loss: 0.068
[3     10]   loss: 0.056
[3     20]   loss: 0.034
[4     10]   loss: 0.012
[4     20]   loss: 0.006
[5     10]   loss: 0.005
[5     20]   loss: 0.001
[6     10]   loss: 0.002
[6     20]   loss: 0.001
[7     10]   loss: 0.001
[7     20]   loss: 0.001
[8     10]   loss: 0.001
[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
[11     10]   loss: 0.000
[11     20]   loss: 0.000
[12     10]   loss: 0.000
[12     20]   loss: 0.000
[13     10]   loss: 0.000
[13     20]   loss: 0.000
[14     10]   loss: 0.000
[14     20]   loss: 0.000
[15     10]   loss: 0.000
[15     20]   loss: 0.000
[16     10]   loss: 0.000
[16     20]   loss: 0.000
[17     10]   loss: 0.000
[17     20]   loss: 0.000
[18     10]   loss: 0.000
[18     20]   loss: 0.000
[19     10]   loss: 0.000
[19     20]   loss: 0.000
[20     10]   loss: 0.000
[20     20]   loss: 0.000
finished train


(2)去掉池化层,对比“有无池化”的效果

得到的结果:

[1     10]   loss: 0.062
[1     20]   loss: 0.051
[1     30]   loss: 0.044
[2     10]   loss: 0.041
[2     20]   loss: 0.045
[2     30]   loss: 0.042
[3     10]   loss: 0.044
[3     20]   loss: 0.043
[3     30]   loss: 0.041
[4     10]   loss: 0.043
[4     20]   loss: 0.041
[4     30]   loss: 0.044
[5     10]   loss: 0.042
[5     20]   loss: 0.042
[5     30]   loss: 0.044
[6     10]   loss: 0.041
[6     20]   loss: 0.045
[6     30]   loss: 0.042
[7     10]   loss: 0.043
[7     20]   loss: 0.043
[7     30]   loss: 0.039
[8     10]   loss: 0.046
[8     20]   loss: 0.039
[8     30]   loss: 0.043
[9     10]   loss: 0.039
[9     20]   loss: 0.044
[9     30]   loss: 0.043
[10     10]   loss: 0.037
[10     20]   loss: 0.043
[10     30]   loss: 0.044
[11     10]   loss: 0.040
[11     20]   loss: 0.042
[11     30]   loss: 0.041
[12     10]   loss: 0.039
[12     20]   loss: 0.040
[12     30]   loss: 0.042
[13     10]   loss: 0.039
[13     20]   loss: 0.041
[13     30]   loss: 0.037
[14     10]   loss: 0.038
[14     20]   loss: 0.036
[14     30]   loss: 0.035
[15     10]   loss: 0.034
[15     20]   loss: 0.033
[15     30]   loss: 0.031
[16     10]   loss: 0.030
[16     20]   loss: 0.029
[16     30]   loss: 0.029
[17     10]   loss: 0.025
[17     20]   loss: 0.024
[17     30]   loss: 0.024
[18     10]   loss: 0.014
[18     20]   loss: 0.019
[18     30]   loss: 0.021
[19     10]   loss: 0.011
[19     20]   loss: 0.009
[19     30]   loss: 0.017
[20     10]   loss: 0.006
[20     20]   loss: 0.006
[20     30]   loss: 0.008
finished train

可以看到,20轮次有较好的效果。但是速度比较慢,还有池化层的效率更高。 

(3)修改“通道数”等超参数,观察变化

修改了通道数,改成11的:
 

[1     10]   loss: 0.070
[1     20]   loss: 0.069
[2     10]   loss: 0.069
[2     20]   loss: 0.067
[3     10]   loss: 0.050
[3     20]   loss: 0.038
[4     10]   loss: 0.022
[4     20]   loss: 0.010
[5     10]   loss: 0.004
[5     20]   loss: 0.003
[6     10]   loss: 0.002
[6     20]   loss: 0.002
[7     10]   loss: 0.001
[7     20]   loss: 0.002
[8     10]   loss: 0.001
[8     20]   loss: 0.001
[9     10]   loss: 0.001
[9     20]   loss: 0.000
[10     10]   loss: 0.001
[10     20]   loss: 0.000
finished train
Accuracy of the network on the  test images: 99.666667 %

 改为15,效果不好:

[1     10]   loss: 0.070
[1     20]   loss: 0.069
[2     10]   loss: 0.069
[2     20]   loss: 0.069
[3     10]   loss: 0.069
[3     20]   loss: 0.069
[4     10]   loss: 0.069
[4     20]   loss: 0.069
[5     10]   loss: 0.069
[5     20]   loss: 0.069
[6     10]   loss: 0.069
[6     20]   loss: 0.069
[7     10]   loss: 0.069
[7     20]   loss: 0.069
[8     10]   loss: 0.069
[8     20]   loss: 0.069
[9     10]   loss: 0.069
[9     20]   loss: 0.068
[10     10]   loss: 0.065
[10     20]   loss: 0.061
finished train
Accuracy of the network on the  test images: 80.000000 %

(4)可视化低级特征、中级特征、高级特征

注重一下可视化的过程

1.通过模型将输入数据`x`进行正向传播,得到输出的特征图`out_put`。

2.但是得到的特征图不能使用plt直接显示出来,需要对他们进行一些操作实现可视化【循环:`np.squeeze`函数将特征图的维度从`[N, C, H, W]`变换为`[C, H, W]`,其中`N`表示批次大小,`C`表示通道数,`H`和`W`表示特征图的高度和宽度;np.transpose`函数将特征图的维度从`[C, H, W]`变换为`[H, W, C]`;然后输出特征图形状】

3.创建图形窗口,循环使用`plt.imshow`函数绘制特征图的每个通道,其中`im[:, :, i]`表示特征图的第`i`个通道。

4.`plt.show`函数展示绘制好的特征图。

import torch  
from torchvision import transforms  
from torch.utils.data import DataLoader  
from torchvision import datasets, transforms  
import torch.nn as nn  # 数据预处理  
transforms = transforms.Compose([  transforms.ToTensor(),  # 把图片进行归一化,并把数据转换成Tensor类型  transforms.Grayscale(),  # 把图片转为灰度图  
])  path = r'train_data'  
data_train = datasets.ImageFolder(path, transform=transforms)  
data_loader = DataLoader(data_train, batch_size=64, shuffle=True)  for i, data in enumerate(data_loader):  images, labels = data  print(images.shape)  # 输出:(batch_size, 1, height, width) 或者 (batch_size, num_channels, height, width)取决于你的图像数据  print(labels.shape)  # 输出:(batch_size,)  break  class Net(nn.Module):  def __init__(self):  super(Net, self).__init__()  self.conv1 = nn.Conv2d(1, 9, 3)  # input: (batch_size, 1, height, width), output: (batch_size, 9, height-2, width-2)  self.maxpool = nn.MaxPool2d(2, 2)  # 2x2的最大池化层,输出:(batch_size, 9, height/2-1, width/2-1)  self.conv2 = nn.Conv2d(9, 5, 3)  # input: (batch_size, 9, height/2-1, width/2-1), output: (batch_size, 5, height/2-2, width/2-2)  self.conv3 = nn.Conv2d(5, 5, 3)  # input: (batch_size, 5, height/2-2, width/2-2), output: (batch_size, 5, height/2-3, width/2-3)  self.relu = nn.ReLU()  self.fc1 = nn.Linear(5 * 5 * 5, 480)  # input: (batch_size, 5*5*5), output: (batch_size, 480)  self.fc2 = nn.Linear(480, 320)  # input: (batch_size, 480), output: (batch_size, 320)  self.fc3 = nn.Linear(320, 2)  # input: (batch_size, 320), output: (batch_size, 2)  def forward(self, x):  x = self.maxpool(self.relu(self.conv1(x)))  # output: (batch_size, 9, height/2-1, width/2-1)  x = self.maxpool(self.relu(self.conv2(x)))  # output: (batch_size, 5, height/4-1, width/4-1) or (batch_size, 5*num_channels ..., height/4-1, width/4-1) depending on the num_channels of your input data  x = self.maxpool(self.relu(self.conv3(x)))  # output: (batch_size, 5, height/8-1, width/8-1) or (batch_size,# 打印出模型的结构
print(model1)x = images[0]# forward正向传播过程
out_put = model1(x)for feature_map in out_put:# [N, C, H, W] -> [C, H, W]    维度变换im = np.squeeze(feature_map.detach().numpy())# [C, H, W] -> [H, W, C]im = np.transpose(im, [1, 2, 0])print(im.shape)# show 9 feature mapsplt.figure()for i in range(5):ax = plt.subplot(3, 3, i + 1)  # 参数意义:3:图片绘制行数,5:绘制图片列数,i+1:图的索引# [H, W, C]# 特征矩阵每一个channel对应的是一个二维的特征矩阵,就像灰度图像一样,channel=1# plt.imshow(im[:, :, i])plt.imshow(im[:, :, i], cmap='gray')plt.show()

可以看到,在最开始的图像中还有明确的⚪,到后来就没了,变成了一个个像素组的,因为初级特征关注的是直接从原数据集中提取到的。而在后期,也就是高级特征阶段,关注的更加抽象。

这一部分是参考的【NNDL 作业7 相关语言解释+基于CNN的XO识别代码复现-CSDN博客】

 三、收获

1.首先是修改卷积层:在这一环节中,我多次尝试【10轮次时】,然后最后的准确率都在50%-60%左右,后来修改到20轮次,发现效果好了很多,可是在第7轮是就没有损失了,感觉很神奇。

2.关于提取这几个特征图,很难弄,在网上也没有搜到相关资料,一直卡着,后来看了美女学霸的【指路:NNDL 作业7 相关语言解释+基于CNN的XO识别代码复现-CSDN博客】,发现“out_put = model1(x)”这一步,也就是正向传播得到特征图,豁然开朗,后边我就懂了。

3.在最后可视化特征这部分,我用了三个卷积层+三个线性层【想让高级特征更明显点,但是好像不太行】

深层网络的感受野更大,大感受野下才存在一定的高阶语义。深层网络所积累的特征空间更大。

上边那句话我的理解是,神经网络越深,那么他的高级特征更抽象。

【来自(46 封私信 / 82 条消息) 为什么越深层的特征图具备更丰富的语义信息? - 知乎 (zhihu.com)】

我感觉我的高级特征图还不是很抽象,可能卷积层再多一点,网络再深一点效果会更明显。

XO识别参考:

【23-24 秋学期】NNDL 作业7 基于CNN的XO识别-CSDN博客

【2021-2022 春学期】人工智能-作业6:CNN实现XO识别_x = self.conv2(x)#请问经过conv2(x)之后,x的维度是多少-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/178118.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac下vue-cli从2.9.6升级到最新版本

由于mac之前安装了 vue 2.9.6 的版本,现在想升级到最新版本,用官方给的命令: npm uninstall vue-cli -g 发现不行。 1、究其原因:从vue-cli 3.0版本开始原来的npm install -g vue-cli 安装的都是旧版,最高到2.9.6。安…

SLAM中提到的相机位姿到底指什么?

不小心又绕进去了,所以掰一下。 以我个人最直观的理解,假设无旋转,相机在世界坐标系的(5,0,0)^T的位置上,所谓“位姿”,应该反映相机的位置,所以相机位姿应该如下: Eigen::Matrix4d T Eigen::M…

ubuntu 18.04安裝QT+PCL+VTK+Opencv

资源 qt5.14.1:qt5.14.1.run opencv4.5.5:opecv4.5.5压缩包 1.国内换中科大源,加快下载速度 cd /etc/apt/ sudo gedit sources.list 替换成如下内容 deb https://mirrors.ustc.edu.cn/ubuntu/ bionic main restricted universe multiverse deb-src https://mirro…

初试 jmeter做压力测试

一.前言 压力测试是每一个Web应用程序上线之前都需要做的一个测试,他可以帮助我们发现系统中的瓶颈问题,减少发布到生产环境后出问题的几率;预估系统的承载能力,使我们能根据其做出一些应对措施。所以压力测试是一个非常重要的步…

《QT从基础到进阶·二十八》QProcess使用,从一个exe程序启动另一个exe程序

QString exePath QCoreApplication::applicationDirPath(); //获取要启动的另一个exe路径 exePath exePath “/OffLineProcess.exe”; //路径exe名称 QProcess* Process new QProcess; //创建新的进程 Process->start(exePath)…

【Springboot】基于注解式开发Springboot-Vue3整合Mybatis-plus实现分页查询(二)——前端el-pagination实现

系列文章 【Springboot】基于注解式开发Springboot-Vue3整合Mybatis-plus实现分页查询—后端实现 文章目录 系列文章系统版本实现功能实现思路后端传入的数据格式前端el-table封装axois接口引入Element-plus的el-pagination分页组件Axois 获取后台数据 系统版本 后端&#xf…

如何创建标准操作规程(SOP)[+模板]

创建、分发和管理流程文档和逐步说明的能力是确定企业成功的关键因素。许多组织依赖标准操作规程(SOP)作为基本形式的文档,指导他们的工作流程操作。 然而,SOP不仅仅是操作路线图;它们就像高性能车辆中的先进GPS系统一…

易货:一种古老而有效的商业模式

在当今的商业世界中,我们常常听到关于电子商务、互联网和社交媒体等新技术的讨论。然而,尽管这些新技术为我们的日常生活带来了许多便利,但它们并没有完全取代传统的商业模式。其中,易货模式是一种古老而有效的商业模式&#xff0…

香港:考虑将虚拟资产列为投资移民资产

11 月 13日消息,香港政府在重新启动投资移民计划后,正考虑将持牌虚拟资产交易平台的比特币等虚拟资产列为可接受的投资项目。这一措施旨在折大投资移民的资产范围,以吸引更多高净值人士在香港落户。尽管有声音呼吁将房地产投资纳入资格范围&a…

屏蔽机房与普通机房有什么不同?

屏蔽机房与普通机房在设计和功能上存在一些明显的区别。下面是一些区别的主要方面: 电磁屏蔽:屏蔽机房采用了电磁屏蔽材料来减少电磁波的干扰。屏蔽机房能够有效地将外部的电磁干扰隔离开来,确保机房内设备的安全运行。 物理安全:…

C#多线程入门概念及技巧

C#多线程入门概念及技巧 一、什么是线程1.1线程的概念1.2为什么要多线程1.3线程池1.4线程安全1.4.1同步机制1.4.2原子操作 1.5线程安全示例1.5.1示例一1.5.2示例二 1.6C#一些自带的方法实现并行1.6.1 Parallel——For、ForEach、Invoke1.6.1 PLINQ——AsParallel、AsSequential…

AI机器学习实战 | 使用 Python 和 scikit-learn 库进行情感分析

专栏集锦,大佬们可以收藏以备不时之需 Spring Cloud实战专栏:https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏:https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏:https:/…