资讯详情

动手学深度学习---从全连接层到卷积层篇

卷积神经网络

1.从全连接层到卷积层

前言:MLP适合,行对应样本,列出对应特征。感知数据会变得不实用

(数据量太大,需要很多GPU和耐心)

采用(convolutional neural networks,CNN)时机器学习创造性的方法


。这是图像分类的一个很好的特点,因为我们希望图像中的目标能够成功识别,无论是平移、旋转、缩放,甚至是不同的光条件和视角。

因此,上述描述对应于各种不变性:

  • 平移不变性:Translation Invariance
  • 旋转/视角不变性:Ratation/Viewpoint Invariance
  • 尺度不变性:Size Invariance
  • 光照不变性:Illumination Invariance

①平移不变性

例如,对于图像分类任务,无论图像中的目标移动到图像的哪个位置,结果(标签)都应该相同,即卷积神经网络中的平移不变性。

②局部性

神经网络的,而,这就是局部原则。,预测整个图像级别。


我在这里的数学运算有问题,后续补充


2.图像卷积

前言:在最后一节中,我们分析了卷积层的数学原理。现在让我们来看看它的实际应用

########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################

严格来说,卷积只是一个称谓,他所表达的运算其实是

########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################

#

所谓cross-correlation 实际是输入tensor与核tensor输出张量是通过相关操作产生的。让我们通过图解来解释cross-correlation

暂时忽略channel(第三维)查看如何处理二维图像数据和隐藏表示()

在这里插入图片描述

在二维的 cross-correlation中间,卷积窗。当卷积窗口到达新位置时,隐藏表示的单一标量像素值。例如,相关操作如下:

注意, ,如果不满足,继续滑动直到满足位置 )

接下来,我们在这里corr2d上述卷积操作在函数中使用代码:

import torch from torch import nn from d2l import torch as d2l  def corr2d(X,K):     """计算二维相关操作"""     h,w=K.shape   #得到卷积核(kernel)行长,宽长     #创建一个与隐藏相同形状的0tensor     Y=torch.zeros((X.shape[0]-K.shape[0] 1,X.shape[1]-K.shape[1] 1))          for i in range(Y.shape[0]):      for j inrange(Y.shape[1]):
            #按元素重新一个个填充
            Y[i,j]=(X[i:i+h,j:j+w]*K).sum() #得到进行互相关运算后的隐藏表示,步长为1
    return Y
        	
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
corr2d(X, K)
result:

tensor([[19., 25.],
        [37., 43.]])

所以,卷积层中的两个被训练的参数是。 就像我们之前随机初始化全连接层一样,在训练基于卷积层的模型时,我们也

基于上面定义的corr2d函数实现二维卷积层。

class Conv2D(nn.module):
    def __init__(self,kernel_size):#kernel_size为卷积核的shape
        super().__init__()
        
        #weight为Conv2D的属性,self.weight是Paramter类的实例
        self.weight=nn.Parameter(torch.rand(kernel_size))#初始化卷积核权重
        self.bias=nn.Parameter(torch.zeros(1))
        
    def forword(self,X):
        return corr2d(X,self.weight)+self.bias #广播机制

高度和宽度分别为h和w的卷积核可以被称为h×w卷积或h×w卷积核。 我们也将带有h×w卷积核的卷积层称为h×w卷积层。

首先,我们构造一个6×8像素的黑白图像。中间四列为黑色(0),其余像素为白色(1)。

X=torch.ones((6,8))
X[:,2:6]=0
X
result:
tensor([[1., 1., 0., 0., 0., 0., 1., 1.],
        [1., 1., 0., 0., 0., 0., 1., 1.],
        [1., 1., 0., 0., 0., 0., 1., 1.],
        [1., 1., 0., 0., 0., 0., 1., 1.],
        [1., 1., 0., 0., 0., 0., 1., 1.],
        [1., 1., 0., 0., 0., 0., 1., 1.]])

接下来,我们

当进行互相关运算时,如果水平相邻的两元素相同,则输出为零,否则输出为非零。

K = torch.tensor([[1.0, -1.0]])

现在,我们对参数X(输入)和K(卷积核)执行互相关运算。

Y = corr2d(X, K)
Y
result:
tensor([[ 0.,  1.,  0.,  0.,  0., -1.,  0.],
        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],
        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],
        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],
        [ 0.,  1.,  0.,  0.,  0., -1.,  0.],
        [ 0.,  1.,  0.,  0.,  0., -1.,  0.]])

现在我们,再进行如上的互相关运算。 其输出如下,之前检测到的垂直边缘消失了。 不出所料,

corr2d(X.t(), K)
result:
tensor([[0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.]])

当有更复杂的情况时,我们不可能手动设计滤波器,那么我们是否可以学习由X生成Y的卷积核呢?

下面,我们首先构造一个卷积层(等),并。接下来我,在每个epoch中,我们比较Y与卷积层的输出的平方误差,然后据此计算gradient来更新卷积核。

# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
#最前面的1,1为in_channels,out_channels
# 这个二维卷积层使用四维输入和输出格式(输出通道、输入通道、高度、宽度),
# 其中批量大小和通道数都为1
conv2d=nn.Conv2d(1,1,kernel_size=(1,2),bias=False) 
X=X.reshape((1,1,6,8))
Y=Y.reshape((1,1,6,7))
lr=3e-2 #学习率

for i in range(10):#训练的基本不走
    y_hat=conv2d(X)
    l=(Y-y_hat)**2
    con2d.zero_grad()
    l,sum().backward()#损失函数求导,得到loss关于卷积核的导数
    #迭代卷积核,即卷积核(权重)更新
    conv2d.weight.data[:]-=lr*conv2d.weight.grad
    
    if (i+1)%2==0:
         print(f'epoch { 
          i+1}, loss { 
          l.sum():.3f}')

???因为前一小节未充分理解,所以难以阐述两者关系

在卷积神经网络中,对于某一层的任意元素x,其

例: 让我们用为例来: 给定2×2卷积核,元素值19的感受野是部分的四个元素。 假设之前输出为Y,其大小为2×2,现在我们在其后附加一个卷积层,该卷积层以Y为输入,输出单个元素z。 在这种情况下,,而。 因此,


3.填充(paddle)和步幅 (stride)

那还有什么因素影响输出的shape呢?

当应用了连续的卷积后,我们得到的输出远小于输入的shape,,而padding是解决此问题最有效的方法。

在输入图像的边界填充元素(),填充操作如下图所示:

通常,如果我们填充Ph行,则顶部与底部各填充 1/2 Ph行,填充 Pw列同理

填充后,输出公式如下:

通常,

卷积神经网络的卷积核(kernel)的高度和宽度通常为

好处:

  1. 保持空间维度同时,可以同时在上下,左右填充相同数量的行()
  2. 提供书写便利

代码示例:

​ 我们创建一个 高度和宽度为3的二维卷积层,并在所有侧边填充1个像素。给定高度和宽度为8的输入,则输出的高度和宽度也是8。 ,所以输出shape不变

import torch 
from torch import nn




def comp_conv2d(conv2d,X):
    # 为了方便起见,我们定义了一个计算卷积层的函数。
	# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
    #此处为元组相加,X.shape=(8,8)
    #(1,1)+(8,8)=(1,1,8,8)
    # 这里的(1,1)表示批量大小和通道数都是1
    X=X.reshape((1,1)+X.shape)
    
	Y=conv2d(X)#得到经过卷积的Y
    return Y.reshape(Y.shape[2:])#将Y重新整合为2维矩阵并返回Y(因为这里的通道数,批量数为1,所以不影响)

# 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列
conv2d=nn.Conv2d(1,1,kernel_size=3,padding=1)
#conv2d的输入shape为(1,1,8,8),输出shape同样为(1,1,8,8)
X=torch.rand(size=(8,8))
cop_conv2d(conv2d,X).shape
result:
torch.Size([8, 8]) #表明输出的高宽为[8,8]

,使输出和输入具有相同的高度和宽度。 在如下示例中,我们使用高度为5,宽度为3的卷积核,高度和宽度两边的填充分别为2和1。

#padding为(2,1),即高度和宽度两边的填充行数列数分别为2和1,即4,2
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))

comp_conv2d(conv2d, X).shape
result:
torch.Size([8, 8])

计算互相关时,卷积窗口默认从左上角开始,向下、向右滑动。 卷积层默认每次滑动一个元素。

卷积窗口也可以跳过中间位置,每次滑动多个元素。每次滑动元素的数量称为 步幅(stride)。

下图为指定步幅的输出形状公式:

下面为输出形状简化:

①如果设置 ph=kh-1 和 pw=kw-1.则输出形状简化为 [(nh+sh−1)/sh]×[(nw+sw−1)/sw]。

②更进一步,如果 输入的高度和宽度可以被垂直和水平步幅整除,则输出形状为状将为(nh/sh)×(nw/sw) (因为, (sw-1)<1,则视为0)

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
result:
torch.Size([4, 4])

接下来,看一个稍微复杂的例子

conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape
result:
torch.Size([2, 2])

输入高度和宽度两侧的填充数量分别为。当时,填充是。同理,步幅为**(sh,sw)sh=sw=ss**。。在实践中,我们很少使用不一致的步幅或填充,也就是说,我们通常有ph=pw和sh=sw

小结: stride 和padding可用于有效调整数据的维度 (w,h)


前言:在前面我们的例子中,进行互相关运算的始终是二维的数据与卷积核。而大多数图片数据通常为 3维tensor(具有 R G B 3通道),shape为(3 X h X w),我们将这个大小为3的轴称为 通道(channel) 维度

本节我们将深入研究具有多输入 和多输出的kernel

当输入包含多个channel时,需要构造 相同channel 数的 kernel,便与进行互相关运算。

多输入通道数据**(3维tensor)** 与 多输入通道 kernel 是如何进行互相关运算的?

首先 我们在每个输入通道 进行 进行互相关运算,最后将 每个输入通道上的结果进行求和 得到 。这就是 之间进行二维互相关运算的结果

下图,我们进行 运算演示:

为加深理解,我们进行代码复现。

在此之前,我们回顾一下

#zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个tuple,然后返回由这些tuple构成的list。如果各个迭代器的元素个数不一致,则返回的list长度与最短的list长度相同。同时,使用zip(*)号,可以将tuple解压为list

a='1111'
b='22222'
print(zip(a,b))
print(list(zip(a,b))
za,zb=zip(*zip(a,b))
print('za is {za},zb is {zb}'.format(za=za,zb=zb))
result:
    <zip object at 0x000001F9CFEC6E80>
    [('1','2'),('1','2'),('1','2'),('1','2')]#该结果证明了zip构成了元素为tuple的list
    za is ('1','1','1','1'), zb is('2','2','2','2')
    

多输入通道互相关运算 简而言之就是

import torch
from d2l import torch as d2l

def corr2d_multi_in(X,K):
    # 先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起
    #此处X,K为三维tensor x,y 为具有高宽的2维tensor(x,y)为list中的tuple
    #sum 使得每个输入通道上的结果进行对应元素相加
    return sum(d2l.corr2d(x,k) for x,k in zip(X,K))

我们可以构造与 中的值相对应的输入张量X和核张量K,以验证互相关运算的输出。

X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
               [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])

corr2d_multi_in(X, K)
result:
tensor([[ 56.,  72.],
        [104., 120.]])

到目前为止,我们的,即输出为单通道的。用 。为获得多个channel的三维tensor ,我们在 ,相当于 卷积核的shape 为 (四维)。

在互相关运算中,每个输出通道先获取所有输入通道,再以对应该输出通道的 进行 多输入通道的计算,最后将

def corr2d_multi_in_out(X,K):
    #此时K为四维tensor,第0维为输出通道
    return torch.stack([corr2d_multi_in(X,k) for k in K],0)
#解析:
#在每个输出通道上取出三维tensor-kernel然后进行 多输入通道计算,即在每个输入通道进行2维kernel与2维输入tensor进行互相关运算,最后用torch.stack(……,0)在第0维上进行2维tensor连接,得到新的多输入通道tensor(三维)

通过将核张量KK+1K中每个元素加1)和K+2连接起来,构造了一个具有3个输出通道的卷积核。

K = torch.stack((K, K + 1, K + 2), 0)
K.shape
result:
torch.Size([3, 2, 2, 2])

下面,我们对输入张量X与卷积核张量K执行互相关运算。现在的输出包含3个通道,第一个通道的结果与先前输入张量X和多输入单输出通道的结果一致。

corr2d_multi_in_out(X, K)
result:
tensor([[[ 56.,  72.],
         [104., 120.]],

        [[ 76., 100.],
         [148., 172.]],

        [[ 96., 128.],
         [192., 224.]]])

前言:1 x 1 卷积层失去了卷积的特性:有效提取相邻像素间的相关特征。而1 X 1 卷积 的唯一计算发生在channel上

下图所示,1X1 卷积核 与多输入多输出通道的互相关计算的,最后

如下图所示:

下面,我们使用全连接实现 1X 1 卷积。()

def corr2d_multi_in_out_1x1(X,K):
    c_i,h,w=X.shape
    c_o=K.shape[0]
    X=X.reshape((c_i,h*w)) #整合为2维tensor
    K=K.reshape((c_o,c_i)) #整合为2维tensor
    #下面是用的是全连接层的矩阵乘法
    Y=torch.matmul(K,X) #全连接层的计算相当于 1X1的多输入输出通道的卷积层运算 1x1卷积核实质上不存在
    return Y.reshape((c_o,h,w)) 

当执行1×1卷积运算时,上述函数相当于先前实现的互相关函数corr2d_multi_in_out。让我们用一些样本数据来验证这一点。

X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))

Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6

5.汇聚层

前言:

①处理图像时,我们希望逐渐(即 w,h) 同时

②我们学习任务通常与全局图像问题有关(),所以。通过逐步聚合信息,生成越发粗糙的映射,最终实现学习全局表示的目标,同时将卷积涂层的又是保留在中间层。

③当检测较底层特征时,我们希望**这些特征保持某种程度上的平移不变性。**若因为像素的短距离移动导致新图像的输出大不相同,则模型的稳定性过于差劲。所以我们采取汇聚层( pooling)

​ 优点:1. 可以

​ 2.可以


与 卷积窗口类似,pooling同样存在。汇聚窗口的移动与kernel 一样,但**操作区别是:**汇聚窗口计算每个窗口中tensor最大的元素值或者平均值,将该值作为新元素。

操作如下图所示:

可以看出,即使输入数据在高度或宽度上移动一个元素,卷积层仍能识别到模式

标签: 1414zb4m连接器1619zb4m连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台