目录
1.概述
2.单通道卷积
3.多通道卷积
4.卷积层常见的参数
5.代码实现(卷积神经网络训练MNIST数据集)
推荐课程:10.卷积神经网络(基础篇)_哔哩哔哩_bilibili
1.概述
全连接神经网络:完全由线性层串行连接起来的网络。在全连接神经网络中,我们会把图像像素映射为一个较长的张量,这样会丧失图像像素之间原始的空间结构。
卷积神经网络:会保留图像像素之间原始的空间结构的神经网络。
convolution卷积:会保留图像像素之间原始的空间结构。
subsampling下采样:缩小图像,提取特征值。
卷积神经网络分为feature extraction特征提取和classification分类两部分。
卷积层每次需要拿出一块像素块进行操作:
Input Channel输入通道数、Output Channel输出通道数、卷积核的大小(长和宽)
2.单通道卷积
可以把卷积核以及卷积核扫描到图像的区域当作两个矩阵,卷积核依次与扫描到的区域做数乘。
单通道卷积运算的过程:
1.将对应位置的元素相乘
2.将得到的所有乘积做一个求和
3.放到输出矩阵的对应位置
3.多通道卷积
有多少个输入通道,卷积核就要有多少个通道数,数乘后,将所有得到的输出矩阵(张量)相加,得到最终的输出矩阵(张量)。
三个卷积核通道构成一个卷积核。
在RGB模型上的表现:
如果有n个输入通道m个输出通道:
1.卷积核的通道数和输入通道数一致
2.卷积核的总个数和输出通道数一致,输出张量的维度和输出通道数一致
3.注意:输出张量的长和宽与卷积核的长和宽不一定相同
(牢记这三条卷积规则)
最后将输出的张量摞叠起来。
一个卷积核的大小 = n*卷积核的宽度*卷积核的高度
卷积核总的大小 = m*n*卷积核的宽度*卷积核的高度
卷积网络的权重为(输出通道数m, 输入通道数n, 卷积核的宽度, 卷积核的高度 )
import torch
# 输入、输出通道数
in_channels, out_channels = 5, 10
# 图像的宽高
width, height = 100, 100
# 卷积核大小
kernel_size = 3
# batch大小
batch_size = 1
# 设置输入张量
input = torch.randn(batch_size,
in_channels,
width,
height)
# 卷积层
# 设置卷积核,kernel_size则默认卷积核为3*3
conv_layer = torch.nn.Conv2d(in_channels,
out_channels,
kernel_size=kernel_size)
# 返回输出
output = conv_layer(input)
print(input.shape)
print(output.shape)
print(conv_layer.weight.shape)
4.卷积层常见的参数
padding(填充):在某些情况下,我们希望输出的张量变得更大一些,由于输出张量的大小与卷积核在输入图像上的扫描面积有关,因此我们只需在输入图像外围填充0即可。
stride(步长):卷积核在输入图像上的扫描间隔。可以有效降低输出张量的大小。Max pooling默认stride = 2。stride = 2意味着输出张量长和宽各减小一半。
注:输出矩阵的长/宽 = 输入矩阵的长/宽 - 卷积核长/宽 + 1
5.代码实现(卷积神经网络训练MNIST数据集)
Conv2d Layer为卷积层。Pooling Layer为最大池层,输出张量缩小一半。ReLU Layer为激活层。
参考之前的标黄的卷积规则,思考(1,28,28)—Conv2d(in = 1,out = 10,size = 5)—>(10,24,24)。
import torch
# 用于图像映射到矩阵中
from matplotlib import pyplot as plt
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
batch_size = 64
#…1.准备数据………………………………………………………………………………………………………………………………………#
# 把像素值0-255转化为图像张量0-1
transform = transforms.Compose([
# transforms.ToTensor()转化张量,Normalize映射到[0,1]之间
transforms.ToTensor(),
# (均值,标准差)
transforms.Normalize((0.1307, ), (0.381, ))
])
# 训练集
train_dataset = datasets.MNIST(root="../dataset/mnist",
train=True,
download=False,
transform=transform)
train_loader = DataLoader(train_dataset,
batch_size=batch_size,
shuffle=True)
test_dataset = datasets.MNIST(root="../dataset/mnist",
train=False,
download=False,
transform=transform)
test_loader = DataLoader(test_dataset,
batch_size=batch_size,
shuffle=False)
#…2.设计模型………………………………………………………………………………………………………………………………………#
# 继承torch.nn.Module,定义自己的计算模块,neural network
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
# 卷积层(输入通道数,输出通道数,卷积核大小(长/宽))
self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
# 最大池层,池化,卷积核大小(长/宽)减小一半
self.pooling = torch.nn.MaxPool2d(2)
# 从320维降到10维
self.fc = torch.nn.Linear(320, 10)
def forward(self, x):
# flatten data from (n,1,28,28) to (n, 784)
batch_size = x.size(0)
# 激活
x = F.relu(self.pooling(self.conv1(x)))
x = F.relu(self.pooling(self.conv2(x)))
# 调整张量维度为320
x = x.view(batch_size, -1) # -1 此处自动算出的是320
# 降维
x = self.fc(x)
return x
#……3.构造损失函数和优化器………………………………………………………………………………………………………#
model = Net()
# 实例化损失函数,返回损失值
criterion = torch.nn.CrossEntropyLoss()
# 优化器,momentum冲量
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
#……4.训练和测试……………………………………………………………………………………………………………………………#
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
# 1.准备数据
inputs, labels = data
optimizer.zero_grad()
# 2.正向传播
outputs = model(inputs)
loss = criterion(outputs, labels)
# 3.反向传播
loss.backward()
# 4.更新权重w
optimizer.step()
# 损失求和
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0.0
def test():
correct = 0
total = 0
# with torch.no_grad():内部代码不会再计算梯度
with torch.no_grad():
for data in test_loader:
images, labels = data
# 内部权重已更新完毕,测试时直接使用即可
outputs = model(images)
# dim沿着第一个纬度(行)找最大值,返回(最大值,最大值下标)
_, predicted = torch.max(outputs.data, dim=1)
total += labels.size(0)
# 预测值与标签对比,正确则加1
correct += (predicted == labels).sum().item()
# 输出精确率
print('Accuracy on test set: %d %%' % (100 * correct / total))
return correct / total
if __name__ == '__main__':
epoch_list = []
acc_list = []
for epoch in range(10):
train(epoch)
acc = test()
epoch_list.append(epoch)
acc_list.append(acc)
#…………5.绘图……………………………………………………………………#
plt.plot(epoch_list, acc_list)
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.show()
训练结果: