动手学深度学习之卷积和卷积层

卷积神经网络

卷积

从全连接到卷积

  • 分类猫和狗的图片

    • 使用一个还不错的相机采集图片(12M像素)
    • RGB图片有36个元素
    • 使用100大小的单隐藏层MLP,模型有3.6B个元素
      • 远多于世界上所有的猫和狗的总和(900M狗,600M猫)
        在这里插入图片描述
  • 我们在图片中找Waldo在哪里,这时候我们有两个原则

    • 平移不变性。也就是说在图片任何地方,我们识别一个东西,这个识别器不需要改变
    • 局部性。我们要找一个东西我们只需要看局部的信息就可以了。

重新考察全连接层

  • 在前面全连接层我们识别一张图片的时候,我们是将图片展成一个一维的张量了。现在我们将输入和输出变形为矩阵(宽度,和高度),因为需要存放一些空间信息
  • 将权重变形为4-D张亮(h,w) 到 ( h ′ , w ′ ) (h', w') (h,w)。记为: h i , j = ∑ k , l w i , j , k , l x k , l = ∑ a , b v i , j , a , b x i + a , j + b h_{i,j} = \sum_{k,l}w_{i,j,k,l}x_{k,l}=\sum_{a,b}v_{i,j,a,b}x_{i+a,j+b} hi,j=k,lwi,j,k,lxk,l=a,bvi,j,a,bxi+a,j+b.这里h是我们的输出,x是我们的输入,w是我们的权重,
  • V是W的重新索引使得 v i , j , a , b = w i , j , i + a , j + b v_{i,j,a,b}=w_{i,j,i+a,j+b} vi,j,a,b=wi,j,i+a,j+b

原则一:平移不变性

  • x的平移导致h的平移 h i , j = ∑ a , b v i , j , a , b x i + a , j + b h_{i,j}=\sum_{a,b}v_{i,j,a,b}x_{i+a,j+b} hi,j=a,bvi,j,a,bxi+a,j+b
  • v不应该依赖于(i, j)
  • 解决方案: v i , j , a , b = v a , b v_{i,j,a,b}=v_{a,b} vi,j,a,b=va,b。则 h i , j = ∑ a , b v a , b x i + a , j + b h_{i,j}=\sum_{a,b}v_{a,b}x_{i+a,j+b} hi,j=a,bva,bxi+a,j+b
  • 这就是2维卷积,在数学上来说叫做2维的较叉相关

原则二:局部性

h i , j = ∑ a , b v a , b x i + a , j + b h_{i,j}=\sum_{a,b}v_{a,b}x_{i+a,j+b} hi,j=a,bva,bxi+a,j+b

  • 当评估 h i , j h_{i,j} hi,j时,我们不应该用远离 x i , j x_{i,j} xi,j的参数
  • 解决方案:当$\left | a \right |,\left | b\right | > \Delta , 使 得 ,使得 使v_{a,b}=0 , , h_{i,j}=\sum_{a=-\Delta }^{\Delta }\sum_{b=-\Delta }^{\Delta }v_{a,b}x_{i+a,j+b}$

总结

在这里插入图片描述

卷积层

二维交叉相关

  • 这里我们的输入是一个33的矩阵,这里的卷积核kernel是一个22的,所有这里的delta是1,这里的输出是由,kernel乘以输入的元素得到的,这里是元素的相乘,然后每次移动delta个位置
    在这里插入图片描述

二维卷积层

  • 二维卷积层,从神经网络的角度来说,就是输入是一个 n h × n w n_h\times n_w nh×nw,卷积核是 k h × k w k_h\times k_w kh×kw,偏差b是一个实数,输出是 Y = X ∗ W + b Y=X*W+b Y=XW+b,这里的Y中的+1是因为每一步大小为1
    在这里插入图片描述

  • 下面的图片我们可以看到不同的卷积核可以带来不同的效果,卷积核是我们学到的
    在这里插入图片描述

较叉相关vs卷积

在这里插入图片描述

一维和三维交叉相关

在这里插入图片描述

总结

在这里插入图片描述

图像卷积代码实现

# 互相关运算
import torch
from torch import nn
from d2l import torch as d2l

# 这里的输入是我们的输入x和卷积核K
def corr2d(X, K):
    """算二维互相关运算"""
    h, w = K.shape  # 这里就是拿出卷积核的行和列
    Y = torch.zeros(X.shape[0] -h + 1, X.shape[1] - w + 1)  # 根据上面理论我们可以得到我们输出的矩阵的大小,也就是输入矩阵的行减去卷积核的行+1,列同理
    # 下面的两个for循环的作用是给,输出矩阵的每个元素赋值,这里就是拿卷积核和对应的区的元素做乘法运算
    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.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)
tensor([[19., 25.],
        [37., 43.]])
# 实现二维卷积层
class Conv2D(nn.Module):
    def __init__(self, kernel_size):  # 这里kernel_size就是卷积核的大小是一个超参数,可以定义为3*3或2*2,都行
        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
# 卷积层的一个简单应用:检测图像中不同颜色的边缘
# 我们首先构造一个输入X,这是一个特殊的矩阵它的前两列是1,中间4列是0,最后2列是1,这样我们从0变到1或者从1变到0要么是1要么是-1
X = torch.ones((6, 8))
X[:, 2:6] = 0
X
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]])
Y = corr2d(X, K)
Y
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.]])
# 卷积核K只能检测垂直边缘
corr2d(X.t(), K)
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的卷积核

# 这里我们直接调用了pytorch中定义的一个二维的卷积层,第一个参数的意思是:输入的通道为1,第二个参数的意思是输出的通道为1,kernel_size指定核的大小
conv2d = nn.Conv2d(1, 1, kernel_size=(1, 2), bias=False)
X = X.reshape((1, 1, 6, 8))  # 这里reshape的原因是因为,第一个维度是通道维,第二个维度是批量大小维,后面的才是值
Y = Y.reshape((1, 1, 6, 7))

for i in range(10):
    Y_hat = conv2d(X)  # 这里是将X传入到网络,计算出输出
    l = (Y_hat - Y) ** 2  # 这里采用了一个均方误差
    conv2d.zero_grad()  # 将梯度置为0
    l.sum().backward()  # 反向传播求梯度
    conv2d.weight.data[:] -= 3e-2 * conv2d.weight.grad  # 这里手写了一个梯度下降,3e-1是学习率
    if (i + 1) % 2 == 0:
        print(f'batch {i+1}, loss {l.sum():.3f}')
batch 2, loss 11.542
batch 4, loss 2.754
batch 6, loss 0.797
batch 8, loss 0.271
batch 10, loss 0.102
# 学习到的卷积核的权重张量
conv2d.weight.data.reshape((1, 2))
tensor([[ 1.0170, -0.9533]])
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值