0
点赞
收藏
分享

微信扫一扫

PyTorch基础(part7)--CNN

学习笔记,仅供参考,有错必纠


文章目录

  • ​​理论​​
  • ​​卷积神经网络CNN​​
  • ​​局部感受野和权值共享​​
  • ​​卷积计算​​
  • ​​池化Pooling​​
  • ​​Padding​​
  • ​​LeNET-5​​
  • ​​代码​​
  • ​​初始设置​​
  • ​​导包​​
  • ​​载入数据​​
  • ​​模型​​

理论

卷积神经网络CNN

卷积神经网络是近年发展起来,并广泛应用于图像处理,NLP等领域的一种多层神经网络。

局部感受野和权值共享

CNN通过局部感受野和权值共享减少了神经网络需要训练的参数个数,从而解决了传统BP权值太多,计算量太大,需要大量样本进行训练的问题.

卷积计算

卷积核也叫滤波器,不同的卷积核 对 同样的图片做卷积之后会提取出不同的信息. 以下图的卷积核为例,我们可以对示例Image进行卷积操作.

PyTorch基础(part7)--CNN_pytorch
PyTorch基础(part7)--CNN_cnn_02

需要注意的是,卷积核里的参数不是人为设定的,而是算法优化得到的.

池化Pooling

Pooling常用的三种方式:

  • max-pooling
  • mean-pooling
  • stochastic pooling

Padding

  • SAME PADDING

给平面外部补0,卷积窗口采样后可能会得到一个跟原来大小相同的平面.
PyTorch基础(part7)--CNN_深度学习_03

  • VALID PADDING

不会超出平面外部,卷积窗口采样后得到一个比原来平面小的平面。

PyTorch基础(part7)--CNN_cnn_04

LeNET-5

LeNET-5是最早的卷积神经网络之一. 下图为LeNET-5的网络结构.

PyTorch基础(part7)--CNN_数据_05

我们可以看到通过对第3层进行卷积后,第4层得到了16幅图. 那么第4层的16幅图是如何计算的呢,操作如下图所示.
PyTorch基础(part7)--CNN_数据_06

代码

初始设置

# 支持多行输出
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all' #默认为'last'

导包

# 导入常用的包
import numpy as np
from torch import nn,optim
from torch.autograd import Variable
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import torch

载入数据

# 载入数据
train_dataset = datasets.MNIST(root = './data/', # 载入的数据存放的位置
train = True, # 载入训练集数据
transform = transforms.ToTensor(), # 将载入进来的数据变成Tensor
download = True) # 是否下载数据
test_dataset = datasets.MNIST(root = './data/', # 载入的数据存放的位置
train = False, # 载入测试集数据
transform = transforms.ToTensor(), # 将载入进来的数据变成Tensor
download = True) # 是否下载数据
# 批次大小
batch_size = 64

# 装载训练集
train_loader = DataLoader(dataset=train_dataset,
batch_size=batch_size,
shuffle=True)

# 装载训练集
test_loader = DataLoader(dataset=test_dataset,
batch_size=batch_size,
shuffle=True)

模型

这里我们使用具有多层网络结构的模型,并加入Dropout操作.

# 定义网络结构
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 定义卷积层和池化
# in_channels:int, 因为是黑白图片,所以输入通道设置为1,如果为彩色图像则这里为3
# out_channels:int, 这里的输出通道数也为生成的特征图的数量,这里我们设置为32
# kernel_size:int, 卷积核大小,我们设置为5
# stride=1, 步长我们设置为1
# padding=0, 我们设置padding为2,也就是在图片的外围补2圈0,这里我们要按照自己的需求自己计算
# 如果想要卷积后的大小和原始图像大小相同,则卷积核大小为3*3则填充1圈0,5*5填充2圈,7*7填充3圈.
# 因为卷积不是非线性操作,所以我们在卷积后增加非线性激活函数nn.ReLU()
# 在卷积后,我们增加一个2*2的池化操作
self.conv1 = nn.Sequential(nn.Conv2d(1, 32, 5, 1, 2), nn.ReLU(), nn.MaxPool2d(2, 2))
# 再定义一个卷积和池化
self.conv2 = nn.Sequential(nn.Conv2d(32, 64, 5, 1, 2), nn.ReLU(), nn.MaxPool2d(2, 2))
# 全连接
# 全连接的输入为64个大小为(7*7)的特征图
# 输出为1000
self.fc1 = nn.Sequential(nn.Linear(64*7*7, 1000), nn.Dropout(p = 0.4), nn.ReLU())
# 全连接
self.fc2 = nn.Sequential(nn.Linear(1000, 10),nn.Softmax(dim = 1))


def forward(self, x):
# ([64, 1, 28, 28])
# 卷积要求的数据格式就是4维的([图片数量, 图片通道数, 图片维度1, 图片维度2])
x = self.conv1(x)
x = self.conv2(x)
# 进入全连接层时,需要reshape
# ([64, 64, 7, 7]) -> ([64, 64*7*7])
x = x.view(x.size()[0], -1)
x = self.fc1(x)
x = self.fc2(x)
return x
LR = 0.0003
# 定义模型
model = Net()
# 定义代价函数为交叉熵代价函数
mse_loss = nn.CrossEntropyLoss()
# 定义优化器Adam
optimizer = optim.Adam(model.parameters(), LR)

在自定义训练和测试函数中,我们分别增加两个方法,​​model.train()​​​和​​model.eval()​​​ ,这​​model.train()​​​方法可以使训练集中的Dropout在训练模型时发挥作用,而​​model.eval()​​则可以使模型在测试过程中不工作.

def train():
model.train()
for i,data in enumerate(train_loader):
# 获得一个批次的数据和标签
inputs, labels = data
# 获得模型预测结果(64,10)
out = model(inputs)
# 计算loss,交叉熵代价函数out(batch,C), labels(batch)
loss = mse_loss(out, labels)
# 梯度清0
optimizer.zero_grad()
# 计算梯度
loss.backward()
# 修改权值
optimizer.step()

def test():
model.eval()

# 计算训练集准确率
correct = 0
for i,data in enumerate(train_loader):
# 获得一个批次的数据和标签
inputs, labels = data
# 获得模型预测结果(64,10)
out = model(inputs)
# 获得最大值,以及最大值所在的位置
_, predicted = torch.max(out, 1)
# 预测正确的数量
correct += (predicted == labels).sum()
print("Train acc:{0}".format(correct.item()/len(train_dataset)))

# 计算测试集准确率
correct = 0
for i,data in enumerate(test_loader):
# 获得一个批次的数据和标签
inputs, labels = data
# 获得模型预测结果(64,10)
out = model(inputs)
# 获得最大值,以及最大值所在的位置
_, predicted = torch.max(out, 1)
# 预测正确的数量
correct += (predicted == labels).sum()
print("Test acc:{0}".format(correct.item()/len(test_dataset)))
for epoch in range(5):
print('epoch:',epoch)
train()
test()
epoch: 0
Train acc:0.9728166666666667
Test acc:0.9755
epoch: 1
Train acc:0.9827666666666667
Test acc:0.983
epoch: 2
Train acc:0.9863
Test acc:0.9863
epoch: 3
Train acc:0.98665
Test acc:0.9842
epoch: 4
Train acc:0.99075
Test acc:0.9896

举报

相关推荐

0 条评论