目录:
task1:https://blog.csdn.net/zahidzqj/article/details/104293563
task2:https://blog.csdn.net/zahidzqj/article/details/104309590
task3:https://blog.csdn.net/zahidzqj/article/details/104319328
task4:https://blog.csdn.net/zahidzqj/article/details/104324196
task5:本章节
task6:https://blog.csdn.net/zahidzqj/article/details/104451810
task8:https://blog.csdn.net/zahidzqj/article/details/104452274
task9:https://blog.csdn.net/zahidzqj/article/details/104452480
task10:https://blog.csdn.net/zahidzqj/article/details/104478668
1 卷积神经网络基础
卷积运算是卷积神经网络最基本的组成部分,使用边缘检测作为入门样例。核就是filter。
卷积的工作方式:对应相乘求和得到一个新的矩阵 得到的是非零填充 stride=1
二维互相关(cross-correlation)运算:输入是一个二维输入数组和一个二维核(kernel)数组,输出也是一个二维数组,其中核数组通常称为卷积核或过滤器(filter)。卷积核的尺寸通常小于输入数组,卷积核在输入数组上滑动,在每个位置上,卷积核与该位置处的输入子数组按元素相乘并求和,得到输出数组中相应位置的元素。图1展示了一个互相关运算的例子,阴影部分分别是输入的第一个计算区域、核数组以及对应的输出。
定义二维互相关运算函数:
import torch
import torch.nn as nn
def corr2d(X, K):
H, W = X.shape
h, w = K.shape
Y = torch.zeros(H - h + 1, W - w + 1)
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i: i + h, j: j + w] * K).sum()
return Y
调用:
X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
K = torch.tensor([[0, 1], [2, 3]])
Y = corr2d(X, K)
print(Y)
>>tensor([[19., 25.],
[37., 43.]])
二维卷积层
二维卷积层将输入和卷积核做互相关运算,并加上一个标量偏置来得到输出。卷积层的模型参数包括卷积核和标量偏置。
class Conv2D(nn.Module):
def __init__(self, kernel_size):
super(Conv2D, self).__init__()
self.weight = nn.Parameter(torch.randn(kernel_size))
self.bias = nn.Parameter(torch.randn(1))
def forward(self, x):
return corr2d(x, self.weight) + self.bias
下面我们看一个例子,我们构造一张6×86×8的图像,中间4列为黑(0),其余为白(1),希望检测到颜色边缘。我们的标签是一个6×76×7的二维数组,第2列是1(从1到0的边缘),第6列是-1(从0到1的边缘)。
X = torch.ones(6, 8)
Y = torch.zeros(6, 7)
X[:, 2: 6] = 0
Y[:, 1] = 1
Y[:, 5] = -1
我们希望学习一个1×21×2卷积层,通过卷积层来检测颜色边缘。
conv2d = Conv2D(kernel_size=(1, 2))
step = 30
lr = 0.01
for i in range(step):
Y_hat = conv2d(X)
l = ((Y_hat - Y) ** 2).sum()
l.backward()
# 梯度下降
conv2d.weight.data -= lr * conv2d.weight.grad
conv2d.bias.data -= lr * conv2d.bias.grad
# 梯度清零
conv2d.weight.grad.zero_()
conv2d.bias.grad.zero_()
if (i + 1) % 5 == 0:
print('Step %d, loss %.3f' % (i + 1, l.item()))
print(conv2d.weight.data)
print(conv2d.bias.data)
互相关运算与卷积运算卷积层得名于卷积运算,但卷积层中用到的并非卷积运算而是互相关运算。我们将核数组上下翻转、左右翻转,再与输入数组做互相关运算,这一过程就是卷积运算。由于卷积层的核数组是可学习的,所以使用互相关运算与使用卷积运算并无本质区别。
特征图feature map:二维卷积层输出的二维数组可以看作是输入在空间维度(宽和高)上某一级的表征。
感受野receptive field:。影响元素xx的前向计算的所有可能输入区域(可能大于输入的实际尺寸)
填充(padding):是指在输入高和宽的两侧填充元素(通常是0元素)
步幅(stride):卷积核在输入数组上滑动,每次滑动的行数与列数
卷积输出边长的计算公式是:
output_h =(originalSize_h+padding*2-kernelSize_h)/stride +1
卷积核参数计算
可以写为:(Cin*(kernelSize_w*kernelSize_h)+1)Cout
注意:卷积向下取整,池化向上取整
在卷积神经网络中,每一个卷积层中使用的过滤器中的参数都是一样的。这是卷积神经网络一个非常重要的性质。从直观上理解,共享过滤器的参数可以使得图像上的内容不受位置的影响。以MNIST手写体数字识别为例,无论数字“1”出现在左上角还是右下角,图片的种类都是不变的。因为在左上角和右下角使用的过滤器参数相同,所以通过卷积层之后无论数字在图像上的哪个位置,得到的结果都一样。
共享每一个卷积层中过滤器中的参数可以巨幅减少神经网络上的参数。
池化:池化层可以非常有效地缩小矩阵的尺寸,从而减少最后全连接层中的参数。使用池化层既可以加快计算速度也有防止过拟合问题的作用。和卷积层类似,池化层前向传播的过程也是通过移动一个类似过滤器的结构完成的。不过池化层过滤器中的计算不是节点的加权和,而是采用更加简单的最大值或者平均值运算。最大池化层(max pooling)和平均池化层(average pooling), mean-pooling,即对邻域内特征点只求平均,对背景保留更好; max-pooling,即对邻域内特征点取最大,对纹理提取更好;唯一的区别在于卷积层使用的过滤器是横跨整个深度的,而池化层使用的过滤器只影响一个深度上的节点。所以池化层的过滤器除了在长和宽两个维度移动之外,它还需要在深度这个维度移动。
注意:池化层参与反向传播,但是没有模型参数,且不改变深度。
X = torch.arange(32, dtype=torch.float32).view(1, 2, 4, 4)
pool2d = nn.MaxPool2d(kernel_size=3, padding=1, stride=(2, 1))#nn.AvgPool2d
Y = pool2d(X)
2 leNet
第一层,卷积层
这一层的输入就是原始的图像像素,LeNet-5模型接受的输入层大小为32×32×1。第一个卷积层过滤器的尺寸为5×5,深度为6,不使用全0填充,步长为1。因为没有使用全0填充,所以这一层的输出的尺寸为32-5+1=28,深度为6。这一个卷积层总共有5×5×1×6+6=156个参数,其中6个为偏置项参数。因为下一层的节点矩阵有28×28×6=4704个节点,每个节点和5×5=25个当前层节点相连,所以本层卷积层总共有4704×(25+1)=122304个连接。
第二层,池化层
这一层的输入为第一层的输出,是一个28×28×6的节点矩阵。本层采用的过滤器大小为2×2,长和宽的步长均为2,所以本层的输出矩阵大小为14×14×6。原始的LeNet-5模型中使用的过滤器和本文中介绍的有些细微差别,这里不做具体介绍。
第三层,卷积层
本层的输入矩阵大小为14×14×6,使用的过滤器大小为5×5,深度为16。本层不使用全0填充,步长为1。本层的输出矩阵大小为10×10×16。按照标准的卷积层,本层应该有5×5×6×16+16=2416个参数,10×10×16×(25+1)=41600个连接。
第四层,池化层
本层的输入矩阵大小为10×10×16,采用的过滤器大小为2×2,步长为2。本层的输出矩阵大小为5×5×16。
第五层,全连接层
本层的输入矩阵大小为5×5×16,在LeNet-5模型的论文中将这一层称为卷积层,但是因为过滤器的大小就是5×5,所以和全连接层没有区别,在之后的TensorFlow程序实现中也会将这一层看成全连接层。如果将5×5×16矩阵中的节点拉成一个向量,那么这一层和在第四章中介绍的全连接层输入就一样了。本层的输出节点个数为120,总共有5×5×16×120+120=48120个参数。
第六层,全连接层
本层的输入节点个数为120个,输出节点个数为84个,总共参数为120×84+84=10164个。
第七层,全连接层
第七层本层的输入节点个数为84个,输出节点个数为10个,总共参数为84×10+10=850个。
net = torch.nn.Sequential( #Lelet
Reshape(),
nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2), #b*1*28*28 =>b*6*28*28
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2), #b*6*28*28 =>b*6*14*14
nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5), #b*6*14*14 =>b*16*10*10
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2), #b*16*10*10 => b*16*5*5
Flatten(), #b*16*5*5 => b*400
nn.Linear(in_features=16*5*5, out_features=120),
nn.Sigmoid(),
nn.Linear(120, 84),
nn.Sigmoid(),
nn.Linear(84, 10)
)
3卷积神经网络进阶
LeNet: 在大的真实数据集上的表现并不尽如⼈意。
1.神经网络计算复杂。
2.还没有⼤量深⼊研究参数初始化和⾮凸优化算法等诸多领域。
AlexNet:首次证明了学习到的特征可以超越⼿⼯设计的特征,从而⼀举打破计算机视觉研究的前状。
特征:
VGG:通过重复使⽤简单的基础块来构建深度模型。
Block:数个相同的填充为1、窗口形状为3×33×3的卷积层,接上一个步幅为2、窗口形状为2×22×2的最大池化层。
NiN:LeNet、AlexNet和VGG:先以由卷积层构成的模块充分抽取 空间特征,再以由全连接层构成的模块来输出分类结果。
NiN:串联多个由卷积层和“全连接”层构成的小⽹络来构建⼀个深层⽹络。
⽤了输出通道数等于标签类别数的NiN块,然后使⽤全局平均池化层对每个通道中所有元素求平均并直接⽤于分类。
NiN重复使⽤由卷积层和代替全连接层的1×1卷积层构成的NiN块来构建深层⽹络。
NiN去除了容易造成过拟合的全连接输出层,而是将其替换成输出通道数等于标签类别数 的NiN块和全局平均池化层。
NiN的以上设计思想影响了后⾯⼀系列卷积神经⽹络的设计。
GoogLeNet: