P19 卷积层

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


def corr2d(X,K):
  #计算二维互相关运算
  h,w = K.shape #kernel核矩阵 K.shape里有h和w,表示行数和列数/高和宽
  Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
  #输出Y的高度:X.shape[0] - h + 1 输入的高h - kernel的高h + 1
  #输出Y的宽度:X.shape[1] - w + 1 输入的宽度 - kernel的宽度w + 1
  #用2个for loop对Y的i和j作计算
  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()
      #从i开始,到h行; 从j列开始,往后到w列, 和kernel矩阵作点积, 最后求和
  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) #使用上面的函数
print(corr2d(X,K))

'''
和书上计算的一样
tensor([[19., 25.],
        [37., 43.]])
'''

# 实现二维卷积层
class Conv2D(nn.Module):
  def _init_(self,kernel_size): #kernel size 是3*3的矩阵
    super().__init__()
    self.weight = nn.Parameter(torch.rand(kernel_size))
    self.bias = nn.Parameter(torch.zeros(1)) #bias是0,一个标量

  def forward(self,x):
    return corr2d(x,self.weight) + self.bias
  #x和weight做互相关运算 + bias


#卷积层的简单运用:检测图像中不同颜色的边缘
X= torch.ones((6,8)) #图像输入6*8
X[:, 2:6] = 0 #把图片中间一块变成0
print(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.]])
从1-0的时候,图片会有从黑到白的过程
'''

K = torch.tensor([[1.0,-1.0]]) #自定义一个核

#输出Y中的1达标从白色到黑色的边缘,-1代表从黑色到白色的边缘
Y = corr2d(X,K)
print(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只能检测垂直边缘,不垂直就不能检测了
print(corr2d(X.t(),K)) #对X做转置

'''
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的卷积核
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))

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
  #learning rate = 3e - 2 * weight
  if (i+1) % 2 == 0:
    print(f'batch{i+1}, loss{l.sum():.3f}')
      #每2个batch之后print参数

'''
batch2, loss13.181
batch4, loss2.263
batch6, loss0.401
batch8, loss0.076
batch10, loss0.016
'''

print(conv2d.weight.data.reshape((1, 2)))

'''
tensor([[ 0.9732, -0.9893]])
'''

总结:

对全连接层使用1.平移不变 2.局部性 原则, 就会得到卷积层

卷积运算是交叉相关

二维:一般图像是二维

一维:文本、语言、时序序列

三维:视频、医学图像、气象地图

练习:

  1. 构建一个具有对角线边缘的图像X

    1. 如果将本节中举例的卷积核K应用于X,会发生什么情况?

    2. 如果转置X会发生什么?

    3. 如果转置K会发生什么?

  2. 在我们创建的Conv2D自动求导时,有什么错误消息?

  3. 如何通过改变输入张量和卷积核张量,将互相关运算表示为矩阵乘法?

  4. 手工设计一些卷积核:

    1. 二阶导数的核的形式是什么?

    2. 积分的核的形式是什么?

    3. 得到d次导数的最小核的大小是多少?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值