卷积神经网络
卷积神经网络是一种带有卷积结构的深度神经网络,卷积结构可以减少深层网络占用的内存量,其三个关键的操作,其一是局部感受野,其二是权值共享,其三是pooling层,有效的减少了网络的参数个数,缓解了模型的过拟合问题。
卷积神经网络相比一般神经网络在图像理解中的优点:
- 网络结构能够较好的适应图像的结构
- 同时进行特征提取和分类,使得特征提取有助于特征分类
- 权值共享可以减少网络的训练参数,使得神经网络结构变得简单,适应性更强
卷积神经网络结构包括:卷积层,池化层,全连接层。每一层有多个特征图,每个特征图通过一种卷积滤波器提取输入的一种特征,每个特征图有多个神经元。
卷积层(Convolutional Layer)
什么是卷积?
卷积是对两个实变函数的一种数学操作。 ü 在图像处理中,图像是以二维矩阵的形式输入到神经网络的, 因此我们需要二维卷积。
通过卷积运算我们可以提取出图像的特征,通过卷积运算可以使得原始信号的某些特征增强,并且降低噪声。
池化层(Pooling Layer)
- 池化层保留了主要特征的同时减少参数和计算量,防止过拟合,提高模型泛化能力。
- 它一般处于卷积层与卷积层之间,全连接层与全连接层之间。
Pooling的类型:
Max pooling: 最大值池化
Average pooling: 平均池化
全连接层(FC Layer)
- 两层之间所有神经元都有权重链接
- 通常全连接层在卷积神经网络尾部
- 全连接层参数量通常最大
AlexNet
训练技巧:dropout防止过拟合,提高泛化能力
训练阶段使用了Dropout技巧随机忽略一部分神经元,缓解了神经网络的过拟合现象,和防止对网络参数优化时陷入局部最优的问题,Dropout虽有单独的论文论述,但是AlexNet将其实用化,通过实践证实了它的效果。在AlexNet中主要是最后几个全连接层使用了Dropout。
该网络是利用Dropout在训练过程中将输入层和中间层的一些神经元随机置零,使得训练过程收敛的更慢,但得到的网络模型更加具有鲁棒性。
VGG
引入了块的概念,块的使用导致网络定义的非常简洁。使用块可以有效地设计复杂的网络。
GoogleNet
网络包含22个带参数的层,独立成块的层总共约有100个;参数量大概是AlexNet的1/12;没有FC层。GoogLeNet提出了一个Inception模块,其初衷是多卷积核增加特征多样性。
其中5X5的卷积层仍可分解为两个3X3的卷积层进行参数量的降低。
ResNet
残差的思想:去掉相同的主体部分,突出微小的变化,可以被用来训练非常深的网络。
构建简单的CNN对 mnist 数据集进行分类
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
import numpy
# 一个函数,用来计算模型中有多少参数
def get_n_params(model):
np=0
for p in list(model.parameters()):
np += p.nelement()
return np
# 使用GPU训练,可以在菜单 "代码执行工具" -> "更改运行时类型" 里进行设置
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
1. 加载数据 (MNIST).
#PyTorch里包含了 MNIST, CIFAR10 等常用数据集,调用 torchvision.datasets 即可把这些数据由远程下载到本地,下面给出MNIST的使用方法:
#torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False)
input_size = 28*28 # MNIST上的图像尺寸是 28x28
output_size = 10 # 类别为 0 到 9 的数字,因此为十类
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=True, download=True,
transform=transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))])),
batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))])),
batch_size=1000, shuffle=True)
显示数据集中的部分图像
plt.figure(figsize=(8, 5))
for i in range(20):
plt.subplot(4, 5, i + 1)
image, _ = train_loader.dataset.__getitem__(i)
plt.imshow(image.squeeze().numpy(),'gray')
plt.axis('off');
2. 创建网络
定义网络时,需要继承nn.Module,并实现它的forward方法,把网络中具有可学习参数的层放在构造函数init中。
只要在nn.Module的子类中定义了forward函数,backward函数就会自动被实现(利用autograd)。
class FC2Layer(nn.Module):
def __init__(self, input_size, n_hidden, output_size):
# nn.Module子类的函数必须在构造函数中执行父类的构造函数
# 下式等价于nn.Module.__init__(self)
super(FC2Layer, self).__init__()
s