目录
一 视频学习
1.绪论
1.1 卷积神经网络的应用
1.2 传统神经网络vs卷积神经网络
2.基本组成结构
2.1 卷积
2.2 池化
2.3 全连接
3.卷积神经网络典型结构
3.1 AlexNet
3.2 ZFNet
3.3 VGG
3.4 GoogleNet
3.5 ResNet
二 代码学习
1.MNIST 数据集分类
2.CIFAR10 数据集分类
3.使用 VGG16 对 CIFAR10 分类
三 问题回答
分类、检索、检测、分割
人脸识别、人脸表情识别、图像生成、图像风格转化、自动驾驶
深度学习三部曲:
1.搭建神经网络结构
2.找到一个合适的损失函数(交叉熵损失(cross entropy loss) , 均方误差(MSE)......)
3.找到一个合适的优化函数,更新参数(反向传播(BP),随机梯度下降(SGD)....)
损失函数:
用来衡量吻合度。可以调整参数/权重W,使得映射的结果和实际类别吻合
常用损失函数如下所示
传统vs卷积
现有如下图所示全连接网络(某一个神经元和前面一层的所有输出都有连接),在训练过程中,会根据效果对网络神经元不断进行调整,其整体流程如下。
但是这样一个网络面对一张图片,一个神经元需要和图片上每一个像素点都有连接,需要学习的参数量太大了,参数太多很容易出现过拟合。
而卷积神经网络的一个神经元不再和整张图片都有链接,而是通过一个小的局部块和图片连接,并且在卷积核的一次滑动过程中,所有参数是共享的,这样让参数量大幅度降低
一维卷积
一维卷积经常用在信号处理中,用于计算信号的延迟累积
假设一个信号发生器在时刻t发出一个信号xt,其信息的衰减率为fk,即在k- 1个时间步长后,信息衰减为原来的fk倍。设f1=1,f2=1/2,f3= 1/4,在时刻t收到的信号yt为当前时刻产生的信息和以前时刻延迟信息的叠加。此处的[f1,f2,f3]被称为滤波器 (filter) 或卷积核(convolutional kernel)
卷积
在图像处理中,图像是以二维矩阵的形式输入到神经网络的,因此我们需要二维卷积。
大小不匹配怎么办?——padding,在输入的两边进行补零
深度:feature map的厚度,和filter个数是一致的
Pooling:缩放
Pooling的类型:
全连接层/FC layer
AlexNet成功的原因在于:
ReLU函数:
DropOut(随机失活)
训练时随机关闭部分神经元。测试时整合所有神经元
数据增强(data augmentation)
分层解析
主要的参数集中在全连接层
2013年ImageNet图像分类竞赛的冠军 ImageNet top 5 error: 16.4% -> 14.8%
VGG是一个更深网络
不止是在深度上加深,在结构上也做了改进,2014年ImageNet图像分类竞赛的冠军,ImageNet top 5 error: 11.7% -> 6.7%
网络总体结构:
Naive Inception
初衷:多卷积核增加特征多样性
在同一层用了三个不同的卷积核,对不同卷积核的输出在深度上进行串联,用padding让输出的前两维大小保持一致
channel的个数很大,随着模型的加深,chennel的个数一直不断增多,计算复杂度过高
Inception V2
解决思路:插入1*1卷积核进行降维
Inception V3
Inception V3 进一步对v2的参数数量进行降低。用小的卷积核替代大的卷积核,一次5*5卷积和两次3*3卷积对应的卷积核大小一样
GoogleNet
残差学习网络(deep residuallearning network),2015年ILSVRC竞赛冠军, top 5 错
误率从6.7% -> 3.57%。深度有152层
代码链接:https://colab.research.google.com/drive/1_CKuabjpLqCXywiteMc2M_R_bUOvKwQb?usp=sharing
加载数据集,从training.pt读取训练数据,从test.pt读取测试数据
显示数据集中的部分图像
创建网格,定义网络时,需要继承nn.Module,并实现它的forward方法,把网络中具有可学习参数的层放在构造函数init中。只要在nn.Module的子类中定义了forward函数,backward函数就会自动被实现(利用autograd)。
注意:给出的代码中用了两种定义网络的方式。分别是nn.Sequential和传统方法,利用Sequential可以简化写法,能用更简单的方式搭建同样的神经网络
定义训练和测试函数
在小型全连接网络上训练(Fully-connected network)vs 在卷积神经网络上训练
通过上面的测试结果可以发现,含有相同参数的 CNN 效果要明显优于简单的全连接网络,是因为 CNN 能够更好的挖掘图像中的信息,主要通过两个手段:
打乱图像中的像素顺序
在小型全连接网络上训练(Fully-connected network)vs 在卷积神经网络上训练
从打乱像素顺序的实验结果来看,全连接网络的性能基本上没有发生变化,但是卷积神经网络的性能明显下降。这是因为对于卷积神经网络会利用像素的局部关系,但是打乱顺序以后,这些像素间的关系将无法得到利用。
加载数据集。CIFAR10数据集包含十个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10 中的图像尺寸为3x32x32,也就是RGB的3层颜色通道,每层通道内的尺寸为32*32。
接下来定义网络,损失函数和优化器,并训练
网络在整个数据集上的表现并不出色
定义 dataloader,定义VGG网络,初始化网络,根据实际需要,修改分类层。然后对网络进行训练,
模型准确率有所提升
另外注意需要修改代码:
1、dataloader 里面 shuffle 取不同值有什么区别?
要不要打乱顺序,shuffle取值为True时打乱顺序(打乱顺序较好)
2、transform 里,取了不同值,这个有什么区别?
transforms.compose里面的参数实际上是个列表,而这个列表里面的元素就是想要执行的transform操作。
transform_train = transforms.Compose([
transforms.RandomCrop(32, padding=4), #在一个随机的位置进行裁剪(*)
transforms.RandomHorizontalFlip(), #以0.5的概率水平翻转给定的PIL图像(*)
transforms.ToTensor(), # 把灰度范围从0-255变换到0-1之间,
#用均值(前)和标准差归一化(后)张量图像 output = (input - mean) / std
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
3、epoch 和 batch 的区别?
当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一个 epoch。然而,当一个 epoch 对于计算机而言太庞大的时候,就需要把它分成多个小块(batch)。
在不能将数据一次性通过神经网络的时候,就需要将数据集分成几个 batch。另外注意,Batch size是一个 batch 中的样本总数,而number of batches也就是迭代次数
比如对于一个有 2000 个训练样本的数据集。将 2000 个样本分成大小为 500 的 batch,那么完成一个 epoch 需要 4 个 iteration。
4、1x1的卷积和 FC 有什么区别?主要起什么作用?
区别:全连接是把特征图拆开组成一个一维向量,再乘以一个权重向量,这两个向量中的元素一一对应,输出结果是一个值。1*1的卷积作用在一个局部区域,输出是图像长宽w*h的一个矩阵。
作用:1*1卷积在大多数情况下是用于升/降特征的维度(通道数),而不改变图片的宽和高。全连接做不到。全连接层的作用是可以将卷积得到的局部特征连接起来,综合考虑整个图像
5、residual leanring 为什么能够提升准确率?
残差网络可以通过增加网络深度来提升准确率,通过直接将输入信息绕道传到输出,保护信息的完整性,整个网络只需要学习输入和输出有差别的那一部分,这样就简化了学习目标以及难度。普通网络结构是一个连乘的形式,残差多了加和,缓解了梯度消失的问题。
6、代码练习二里,网络和1989年 Lecun 提出的 LeNet 有什么区别?
不同之处在于激活函数,LeNet采用Softmax,代码2采用ReLU
7、代码练习二里,卷积以后feature map 尺寸会变小,如何应用 Residual Learning?
需要使用1x1卷积调整通道维度,使其可以相加,表示如: 其中, Ws指的是1x1卷积操作
答案更正:利用padding
class Bottleneck(nn.Module):
def __init__(self, in_planes=256, planes=64):
super(Bottleneck, self).__init__()
self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1)
self.bn1 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(planes)
self.conv3 = nn.Conv2d(planes, in_planes, kernel_size=1)
self.bn3 = nn.BatchNorm2d(in_planes)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = F.relu(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
out = out + x
out = F.relu(out)
return out
8、有什么方法可以进一步提升准确率?
进行数据增强;增加数据量;适当增加epoch;调整网络结构。