当前位置:   article > 正文

李沐19_卷积层——自学笔记

李沐19_卷积层——自学笔记

从全连接到卷积

1.在图片中寻找原则:

1.平移不变性:(通俗理解)卷积核Vab是一个找猫猫的特征器,识别猫的特征器不会因为图片中猫藏的位置不同而发生变化,即同一张卷积核遍历整张图片。

2.局部性:(通俗理解)卷积核是一个试探模板,不想考虑某个位置的时候,就置0,想重点考虑某个位置的时候就设置值为大,即限制卷积核的宽高ab

2.重新考察全连接层

在全连接层W是权重矩阵,Wij是矩阵第i行第j列的一个值(标量),在第i行第j列引入“宽高”两个维度(k,l)就变成四维,推广后的Wij就是一个二维矩阵,有宽也有高。

i,j对应filter内参数的位置,k,l是输入矩阵输入特征的位置,第一个等号说明Wij要和所有的特征相乘。

3.总结

对全连接层使用平移不变性和局部性得到卷积层

卷积层

1.卷积层将输入和核矩阵进行交叉相关,加上偏移后得到输出

2.核矩阵和偏移都是可学习的参数

3.核矩阵的大小是超参数

代码实现

1.图像卷积

互相关运算

import torch
from torch import nn
from d2l import torch as d2l

def corr2d(X,K):
  '''计算二维互相关运算。'''
  h,w = K.shape  # 行、列
  Y = torch.zeros((X.shape[0]-h+1, X.shape[1]-w+1)) # 输出: 输入的高-核的高+1,输入的宽度-核的宽度+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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

验证上述二维互相关运算的输出

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)  # 哈马达积
  • 1
  • 2
  • 3
tensor([[19., 25.],
        [37., 43.]])
  • 1
  • 2

实现二维卷积层

class Conv2D(nn.Module):
  def __init__(self,kernel_size):
    super().__init__()
    self.weight = nn.Parameter(torch.rand(kernel_size))
    self.bias = nn.Parameter(torch.zeros(1))

  def forward(self,x):
    return corr2d(x, self.weight)+self.bias
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

卷积层的简单应用:检验图像中不同颜色的边缘

X = torch.ones((6,8))
X[:, 2:6] = 0
X
  • 1
  • 2
  • 3
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.]])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
K = torch.tensor([[1.0, -1.0]])
  • 1

输出Y中的1代表从白色到黑色的边缘,-1代表从黑色到白色的边缘

Y = corr2d(X, K)
Y
  • 1
  • 2
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.]])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

卷积核K只能检测垂直边缘

corr2d(X.t(), K) # X.t():转置
  • 1
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.]])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

学习由X生成Y的卷积核

conv2d = nn.Conv2d(1, 1, kernel_size=(1,2), bias=False) # 输入的通道是1,输出的通道是1,kernel_size核:2d的vector(学1*2的核),目前不需要bias
# 核设置了1*2,X是6*8,最后的结果会少1列(矩阵),所以Y是6*7
X = X.reshape((1,1,6,8))  # 批量大小、通道、高度、宽度
Y = Y.reshape((1,1,6,7))  # corr2d(X,K)

for i in range(10):
  Y_hat = conv2d(X)
  l = (Y_hat-Y)**2
  conv2d.zero_grad()
  l.sum().backward()
  conv2d.weight.data[:] -= 3e-2 * conv2d.weight.grad
  if (i+1)%2 == 0:
    print(f'batch{i+1}, loss{l.sum():.3f}')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
batch2, loss4.515
batch4, loss0.822
batch6, loss0.165
batch8, loss0.039
batch10, loss0.011
  • 1
  • 2
  • 3
  • 4
  • 5

所学的卷积核的权重张量

conv2d.weight.data.reshape((1,2))
  • 1
tensor([[ 0.9983, -0.9803]])
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/383793
推荐阅读
相关标签
  

闽ICP备14008679号