目录
[二、 卷积](#二、 卷积)
[1. 卷积神经网络与传统神经网络的不同](#1. 卷积神经网络与传统神经网络的不同)
[2. 那么到底卷积做了什么事情呢??什么是卷积??](#2. 那么到底卷积做了什么事情呢??什么是卷积??)
[3. 卷积特征值的计算方法](#3. 卷积特征值的计算方法)
[4. 得到特征图的表示](#4. 得到特征图的表示)
[5. 卷积层涉及的参数](#5. 卷积层涉及的参数)
[6. 特征图尺寸的计算](#6. 特征图尺寸的计算)
[7. 参数共享](#7. 参数共享)
[11. 残差神经网络(Resnet)](#11. 残差神经网络(Resnet))
[3. 构建网络](#3. 构建网络)
[4. 训练网络](#4. 训练网络)
一、卷积神经网络应用领域
CV领域发展
应用:目标检测,分类检索,超分辨率重构,医学任务,无人驾驶,人脸识别...
传统神经网络在特征提取上的问题:
-
权重参数举证大
-
过拟合风险大
二、 卷积
1. 卷积神经网络与传统神经网络的不同
大家可以参考神经网络(深度学习,计算机视觉,得分函数,损失函数,前向传播,反向传播,激活函数)https://blog.csdn.net/JamesSwifte/article/details/136848838?spm=1001.2014.3001.5501来学习神经网络的有关知识。
大家想一下,神经网络的输入是一个向量,即使数据原本是矩阵,也是将其拉成一长条。
上图可以看出有4个特征输入,经过两个隐藏层,到达输出层。
那么卷积神经网络输入不在是向量,不是一条,而是张量,是矩阵。
从上图可以看出输入的张量,中间经过卷积层后面加上全连接网络也就是神经网络。
2. 那么到底卷积做了什么事情呢??什么是卷积??
大家联系神经网络提取特征的过程,经过隐藏层,将输入特征值增大,减小,特征数量增多,减少,最后学习到了特征,虽然人是看不出,读不懂这样的特征。那么卷积的作用也是提取特征,而且克服了神经网络的参数过多,容易过拟合的问题。
想象一下,一张图片有主次之分,有背景,有人物,把一张图片分成一块一块的(张量),每一块都有它的代表特征,怎么得到这个特征呢???
引入卷积核(类似于神经网络中的权重参数矩阵)
卷积核在定义了大小后,初始化类似与神经网络中的权重参数矩阵,然后在迭代优化中(反向传播)更新,达到最佳的一组。
3. 卷积特征值的计算方法
数据与卷积核是怎么来做运算呢?答案是做内积,各自位置上的值相乘然后再相加。
上图的列子里:
而且有3个颜色通道,每个颜色通道进行计算,最后相加。
4. 得到特征图的表示
大家看上图的列子,用了一个5*5*3的卷积核得到了一个,特征图。一个特征图效果可能不好,那么想要得到多个特征图怎么做呢?答案是用多个5*5*3的卷积核。而且每个卷积核都不同,这样可以多尺度,多粒度进行特征提取。
而且为了提高提取特征的精确率,采用多次卷积的方式。
5. 卷积层涉及的参数
-
滑动窗口步长 很显然步长小:粒度细,特征丰富 步长大:粒度粗,特征少
-
卷积核尺寸 一般3X3
-
边缘填充 我们发现一个问题:当步长太长,边缘的点被利用的次数明显比在里面的点的次数少,那么是边缘的点就不重要了吗?不是,经过边缘填充,将边缘点变为中间点,多利用几次,一定程度上弥补了边界信息缺失的问题(一般加0)加一圈。
-
卷积核的个数 增大特征丰富度,有几个核就可以得到几个通道的特征图
6. 特征图尺寸的计算
在卷积后怎么计算卷积后的结果呢?即wight,hight,channel呢?
卷积结果计算公式:
其中表示输入的宽度,长度;表示输出特征图的宽度,长度;表示卷积核长和宽的大小;表示滑动窗口的步长;表示边界填充(加几圈)。
7. 参数共享
采用卷积神经网络可以大大降低参数的数量。例如:一张32*32*1的灰度图,用神经网络由输入层1024个特征到第一隐藏层784个特征,中间的权重参数一个需要1024*784=8028816个。而采用卷积神经网络需要一个7*7的卷积核,所需的参数49个。
那么如果对于每一区域的卷积核参数要不一样吗?如果不一样,那么参数就会像神经网络一样非常庞大。所以对每一个区域选择相同的卷积核。这就是参数共享。这是卷积神经网路非常重要的一个特点。
8.池化层的作用
池化层的作用:并不是所有的特征都重要,选择一些留下来。这个操作不涉及矩阵的计算。
池化方法:最大池化(选择该区域内最大值),最小池化(选择该区域内最小值),平均池化(该区域内平均值)
经过实验人员的验证最大池化效果最好,一般选择最大池化方式。
9.整体网络架构
卷积的作用就是提取特征,所以和神经网络的隐藏层一样卷积层可以很多,但是唯一不同的是在卷积后,要加入全连接层,即神经网络的隐藏层后,再输出。而且卷积,非线性变换(relu),池化一般配套使用。
10.经典网络架构
做了解
11. 残差神经网络(Resnet)
深层网络遇到的问题:当卷积核的个数,网络的深度到达一定值后,网络的结果没有出现提升,反而越来越差。这是深度学习的末日,意思是深度学习就到此为止了吗?
分析一下问题:当深度越深效果反而不好,是因为下一层特征提取是在上一层提取的特征上进行的,不能保证效果越来越好的。
解决方案:有学的好的学的不好的,要保留学的好的,同时不能让学的不好的影响整体效果。
残差神经网络:
12.感受野
在卷积神经网络中,感受野(Receptive Field)是指特征图上的某个点能看到的输入图像的区域,即特征图上的点是由输入图像中感受野大小区域的计算得到的。神经元感受野的值越大表示其能接触到的原始图像范围就越大,也意味着它可能蕴含更为全局,语义层次更高的特征;相反,值越小则表示其所包含的特征越趋向局部和细节。因此感受野的值可以用来大致判断每一层的抽象层次。
卷积层(conv)和池化层(pooling)都会影响感受野,而激活函数层通常对于感受野没有影响,当前层的步长并不影响当前层的感受野,感受野和填补(padding)没有关系。
公式求取的感受野通常很大,而实际的有效感受野(Effective Receptive Field)往往小于理论感受野,因为输入层中边缘点的使用次数明显比中间点要少,因此作出的贡献不同,所以经过多层的卷积堆叠后,输入层对于特征图点做出的贡献分布呈高斯分布形状。
三、卷积神经网络实战
构建卷积神经网络
卷积网络中的输入层与传统的神经网络有区别,需要重新设计,训练模块基本一致
1.导入包
python
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import datasets,transforms
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
2.读取数据
分别构建训练集和测试集(验证集)
DataLoader来迭代取数据
python
#定义超参数
input_size = 28 # 图像的总尺寸28*28
num_classes = 10 #标签的种类数
num_epochs = 3 #训练的总循环数
batch_size = 64 # 一个批次的大小,64张图片
python
#训练集
train_dataset = datasets.MNIST(root='./data',
train = True,
transform=transforms.ToTensor(),
download = True)
#测试集
test_dataset = datasets.MNIST(root='./data',
train = False,
transform=transforms.ToTensor(),
)
#构建batch数据
train_loader = torch.utils.data.DataLoader(
dataset = train_dataset,
batch_size = batch_size,
shuffle = True
)
test_loader = torch.utils.data.DataLoader(
dataset = test_dataset,
batch_size = batch_size,
shuffle = True
)
3. 构建网络
python
class CNN(nn.Module):
def __init__(self):
super(CNN,self).__init__()
self.conv1 = nn.Sequential( # 输入大小 (1,28,28)
nn.Conv2d(
in_channels = 1, #灰度图 一个颜色通道
out_channels = 16, #要得到几个特征图
kernel_size = 5, #卷积核大小
stride = 1, #步长
padding = 2, #如果希望卷积后的大小跟原来一样,设置padding=(kernel_size-1)/2 if stride = 1
),
nn.ReLU(), #激活函数
nn.MaxPool2d(kernel_size=2), #进行池化层操作(2x2 区域),输出结果为:(16,14,14)
)
self.conv2 = nn.Sequential(
nn.Conv2d(16,32,5,1,2),
nn.ReLU(), #激活函数
nn.MaxPool2d(2), #进行池化层操作(2x2 区域),输出结果为:(32,7,7)
)
self.out = nn.Linear(32*7*7,10) #全连接层得到结果
def forward(self,x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0),-1) #flatten操作,结果为:(batch_size,32*7*7)
output = self.out(x)
return output
4. 训练网络
python
#定义一个准确率作为评估标准
def accuracy(predictions,labels):
pred = torch.max(predictions.data,1)[1]
rights = pred.eq(labels.data.view_as(pred)).sum()
return rights, len(labels)
#实例化
net = CNN()
#损失函数
criterion = nn.CrossEntropyLoss()
#优化器
optimizer = optim.SGD(net.parameters(),lr=0.01) # 定义优化器,普通的随机梯度下降算法
loss_num = []
#开始循环训练
for epoch in range(num_epochs):
#当前epoch的结果保存下来
train_rights = []
for batch_idx,(data,target) in enumerate(train_loader):
net.train()
output = net(data)
loss = criterion(output,target)
loss_num.append(loss)
optimizer.zero_grad()
loss.backward()
optimizer.step()
right = accuracy(output,target)
train_rights.append(right)
if batch_idx % 100 == 0 :
net.eval()
val_rights = []
for (data,target) in test_loader:
output = net(data)
right = accuracy(output,target)
val_rights.append(right)
#准确率计算
train_r = (sum([tup[0] for tup in train_rights]),sum([tup[1] for tup in train_rights]))
val_r = (sum([tup[0] for tup in val_rights]),sum([tup[1] for tup in val_rights]))
print('当前epoch: {} [{}/{} ({:.0f}%)] \t损失: {:.6f}\t训练集正确率: {:.2f}%\t测试集准确率: {:.2f}%'.format(
epoch,batch_idx*batch_size,len(train_loader.dataset),
100 * batch_idx / len(train_loader),
loss.data,
100 * train_r[0]/ train_r[1],
100 * val_r[0] / val_r[1]
)
)
5.查看损失结果
python
plt.figure(figsize=(10,4))
with torch.no_grad():
plt.plot(loss_num[:])
plt.xlabel('iterion')
plt.ylabel('loss')
plt.show()