深度学习笔记017卷积层

看到一句话,其实卷积层就是一种滤波器,放大它感兴趣的,缩小它不感兴趣的,很有道理。

 

二维卷积层的数学表达:

 

这里这个W其实就是kernel,是在这里通过这种方式学习出来的参数,表现出来的就是一个矩阵。b是偏差,通过广播机制作用给Y。

 

 

 二维交叉和二维卷积,就差一个翻转的关系:

 

 

 为了简单,我们把负号删掉了。所以在神经网络里虽然我们说在做卷积,其实是在做交叉相关。

 

图像处理领域一般都用二维的卷积层,但是一维和三维也在应用中很重要。

一维卷积:

  文本、语言、时序序列

二维卷积:

  视频、医学图像、气象地图

 

卷积层就是将输入和核矩阵进行交叉相关,再加上偏移之后,进行输出。

核矩阵和偏移是可学习的量。

核矩阵的大小是超参数。

 

Q&A:

1、Kernel大小主流用3x3,最多5x5。感受野不是越大越好,最终我们虽然会看到整张图,类似为什么是深度学习而不是广度学习一样,我们用大核少做几次和用小核多做几次,工作量一样,但是视野小一些会更棒。

 

卷积层控制输出大小的超参数:填充和步幅

填充:可以控制输出形状的减小量

步幅:可以成倍减小输出形状

  填充:在输入的四周添加额外的行或列

    通常利用填充,使得输出保持与输入一样的大小

    

  步幅:是指滑行的行/列的步长,高度和宽度的步幅可以不同

    步幅计算:

    

 

 

Q&A:

1、一般来说,填充会使得输出和输入不变,因为这样子算起来比较方便,否则需要一直想着输入输出变化的关系;

2、通常来讲,步幅常常=1,除非计算量明显太大了;

3、卷积的边长一般取奇数,因为取奇数时填充会方便一些,上下左右对称一些。但是效果上来说,奇偶差不多了。

4、机器学习本质上就是信息筛选,信息压缩,我们的信息一直都是丢失的,只要在操作,就是在丢失信息。只不过在压缩的时候,我们放大了我们感兴趣的特征。

5、一个特定的卷积层就是去匹配一种特定的纹理。

 

代码如下:

 1 import torch
 2 from torch import nn
 3 from d2l import torch as d2l
 4 
 5 
 6 # 定义一个计算二维相关的运算
 7 def corr2d(X,K):
 8     h,w=K.shape
 9     Y=torch.zeros((X.shape[0]-h+1,X.shape[1]-w+1))
10     for i in range(Y.shape[0]):
11         for j in range(Y.shape[1]):
12             Y[i,j]=(X[i:i+h,j:j+w]*K).sum()
13     return Y
14 
15 
16 X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
17 K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
18 print(corr2d(X, K))
19 
20 
21 # 实现二维卷积层
22 class Conv2D(nn.Module):
23     def __init__(self,kernel_size):
24         super().__init__()
25         self.weight=nn.Parameter(torch.rand(kernel_size))
26         self.bias=nn.Parameter(torch.zeros(1))
27 
28     def forward(self,x):
29         return corr2d(x,self.weight)+self.bias
30 
31 
32 # 简易应用:检测图像不同颜色的边缘
33 X=torch.ones((6,8)) #z做了一个有两条竖线边缘的矩阵
34 X[:,2:6]=0
35 print(X)
36 K=torch.tensor([[1.0,-1.0]])
37 Y=corr2d(X,K)
38 print(corr2d(X,K))
39 
40 # # 类比做一个检测竖直边缘的算子
41 # X=torch.ones((10,8)) #z做了一个有两条竖线边缘的矩阵
42 # X[3:7,:]=0
43 # print(X)
44 # K=torch.tensor([[1.0],[-1.0]])
45 # print(corr2d(X,K))
46 
47 # 学习由X生成的Y的卷积核
48 conv2d=nn.Conv2d(1,1,kernel_size=(1,2),bias=False)
49 X=X.reshape((1,1,6,8))  #将二维图片转换为四维,第一个是通道,第二个是样本维度(样本数),第三四个是长宽
50 Y=Y.reshape(1,1,6,7)
51 
52 for i in range(10):
53     Y_hat=conv2d(X)
54     l=(Y_hat-Y)**2
55     conv2d.zero_grad()
56     l.sum().backward()
57     conv2d.weight.data[:]-=3e-2*conv2d.weight.grad
58     if(i+1)%2==0:
59         print(f'batch {i+1}, loss {l.sum():.3f}')
60 
61 print(conv2d.weight.data.reshape((1,2)))# 不reshape就会输出四维
62 
63 
64 # 2维变为4维,用于下面的函数
65 XX=torch.zeros((2,3))
66 print(XX)
67 XX=XX.reshape((1,1)+XX.shape)
68 print(XX)
69 
70 # 填充和步幅
71 def comp_conv2d(conv2d,X):
72     X=X.reshape((1,1)+X.shape)  #2维变为4维
73     Y=conv2d(X)
74     return Y.reshape(Y.shape[2:])
75 
76 conv2d=nn.Conv2d(1,1,kernel_size=3,padding=1) # 填充为1,上下左右各填充一行
77 X=torch.rand(size=(8,8))
78 print(comp_conv2d(conv2d,X).shape)
79 
80 conv2d=nn.Conv2d(1,1,kernel_size=(5,3),padding=(2,1)) # 前面为上下,后面为左右
81 print(comp_conv2d(conv2d,X).shape)
82 
83 conv2d=nn.Conv2d(1,1,kernel_size=3,padding=1,stride=2) # 步幅为2
84 X=torch.rand(size=(8,8))
85 print(comp_conv2d(conv2d,X).shape)
86 
87 conv2d=nn.Conv2d(1,1,kernel_size=(3,5),padding=(0,1),stride=(3,5)) # 填充为1,上下左右各填充一行
88 X=torch.rand(size=(8,8))
89 print(comp_conv2d(conv2d,X).shape)

 

posted @ 2022-02-04 22:49  爱和九九  阅读(322)  评论(0编辑  收藏  举报