【动手学习pytorch笔记】9.卷积神经网络基础(卷积层,填充和步长,多输入输出通道,池化层)

2023-11-06

卷积层

二维互相关运算

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))
    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):
        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

把中间的变成0,看起来像图片边界

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.]])

一个1*2的卷积核

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.]])

把X转置一下再试试

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.]])

可见这个卷积核智能判定垂直边界

手动写一个卷积过程

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
    if(i + 1) % 2 == 0:
        print(f'batch{i + 1}, loss {l.sum():.3f}')

nn.Conv2d(输入通道数,输出通道数,卷积核大小,偏移量)

X.reshape成一个四维变量(通道数,批量大小数,6, 8)

Y也一样

迭代10次学习卷积核参数

conv2d.weight.grad梯度

batch2, loss 5.869
batch4, loss 1.119
batch6, loss 0.243
batch8, loss 0.063
batch10, loss 0.020

看看学习到的参数

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

输出

tensor([[ 0.9751, -1.0009]])

可以看到10代之后和标准的[1.0, -1.0]很接近了

填充和步长

无步长

输出大小 = 输入 - 卷积核 + 填充 + 1

有步长

输出大小 = (输入 - 卷积核 + 填充 - 步长)/步长

import torch
from torch import nn

def comp_conv2d(conv2d, X):
    X = X.reshape((1, 1) + X.shape)
    Y = conv2d(X)
    
    return Y.reshape(Y.shape[2:])

conv2d = nn.Conv2d(1, 1, kernel_size = 3, padding = 1)
X = torch .rand(size = (8, 8))
comp_conv2d(conv2d, X).shape

X.reshape((1, 1) + X.shape)是加上通道数和小批次数[1 , 1]

Y.shape[2:]再把前两个维度通道数和小批次数[1 , 1]去掉

输出

torch.Size([8, 8])

8 - 3 + 2 + 1 = 8

例1

conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape

输出

torch.Size([8, 8])

8 - 5 + 4 + 1 = 8

8 - 3 + 2 + 1 = 8

例2

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride = 2)
comp_conv2d(conv2d, X).shape

输出

torch.Size([4, 4])

(8 - 3 + 2 + 2) / 2 = 4.5 向下取整

例3

conv2d = nn.Conv2d(1, 1, kernel_size=(3, 4), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape

输出

torch.Size([2, 2])

(8 - 3 + 3) / 3向下取整 = 2

(8 - 4 + 2 + 4) / 4向下取整 = 2

多输入输出通道

多输入

在这里插入图片描述

import torch
from d2l import torch as d2l

def corr2d_multi_in(X, K):
    return sum(d2l.corr2d(x, k) for x, k in zip(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)

X(2 * 3 * 3)

K(2 * 2 * 2)

tensor([[ 56.,  72.],
        [104., 120.]])

多输出

在这里插入图片描述

有Co组卷积核,Co个通道输出

def corr2d_multi_in_out(X, K):
    # 迭代“K”的第0个维度,每次都对输入“X”执行互相关运算。
    # 最后将所有结果都叠加在一起
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

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

         [[1., 2.],
          [3., 4.]]],


        [[[1., 2.],
          [3., 4.]],

         [[2., 3.],
          [4., 5.]]],
   

        [[[2., 3.],
          [4., 5.]],

         [[3., 4.],
          [5., 6.]]]])
corr2d_multi_in_out(X, K)
tensor([[[ 56.,  72.],
         [104., 120.]],

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

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

1 * 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))
    K = K.reshape((c_o, c_i))
    # 全连接层中的矩阵乘法
    Y = torch.matmul(K, X)
    return Y.reshape((c_o, h, w))

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

相当于全连接层

池化层

缓解卷积层对位置的敏感性,同样有窗口大小,填充,步长,但不用学习参数,且对每个通道单独作用,输入通道是几输出就是几。

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

def pool2d(X, pool_size, mode='max'):
    p_h, p_w = pool_size
    Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            if mode == 'max':
                Y[i, j] = X[i: i + p_h, j: j + p_w].max()
            elif mode == 'avg':
                Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
    return Y

和卷积层的互相关运算差不多

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

输出

tensor([[4., 5.],
        [7., 8.]])
pool2d(X, (2, 2), 'avg')

输出

tensor([[2., 3.],
        [5., 6.]])

填充和步幅

X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X

看看X

tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]])
pool2d = nn.MaxPool2d(3)
pool2d(X)

默认情况下,深度学习框架中的步幅与汇聚窗口的大小相同。 因此,如果我们使用形状为(3, 3)的汇聚窗口,那么默认情况下,我们得到的步幅形状为(3, 3)。

pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

也可手动调整

tensor([[[[ 5.,  7.],
          [13., 15.]]]])
pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
pool2d(X)
tensor([[[[ 5.,  7.],
          [13., 15.]]]])

多通道输入

X = torch.cat((X, X + 1), 1)
X

这里用cat不是stack是因为stack会新增加一个轴在新轴上拼接,但上面 X 已经 reshape((1, 1, 4, 4))所以用cat在现有的通道数所在轴进行拼接

tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]],

         [[ 1.,  2.,  3.,  4.],
          [ 5.,  6.,  7.,  8.],
          [ 9., 10., 11., 12.],
          [13., 14., 15., 16.]]]])
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

输出

tensor([[[[ 5.,  7.],
          [13., 15.]],

         [[ 6.,  8.],
          [14., 16.]]]])

可以看到通道数输入的时候是2,输出的时候还是2

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【动手学习pytorch笔记】9.卷积神经网络基础(卷积层,填充和步长,多输入输出通道,池化层) 的相关文章

随机推荐

  • elasticsearch启动报错

    系统 操作centos7 虚拟机 bin elasticsearch 启动报错 es1 es1 software elasticsearch 6 3 1 bin elasticsearch Exception in thread main
  • 误差函数erf

    1 erf误差函数介绍 erf 是误差函数 它是高斯概率密度函数的积分 性质 2 erf误差函数在matlab中实现 erf函数在matlab里面可以直接作为内置函数使用 erf 0 与下面式子等价 syms s f f exp s 2 e
  • AcWing 3375. 成绩排序

    题目 题目链接3375 成绩排序 思路 思路要求稳定排序或者特判的快排 写法一 写两个sort中的比较函数的参数cmp 写法二 直接在结构体中进行比较 写法三 归并排序 代码1 include
  • Win11 Vmware 16 Pro 启动报错 ‘0xc000007b‘

    一段时间没有使用Vmware 打开突然报错 0xc000007b 可能是因为安装了其他软件导致C 库被改变 原因 C 库改变 解决方法 windows打开控制面板 然后打开程序 卸载程序 图中左下角 然后找到图中两个C 程序 分别右键 卸载
  • YoloV8改进策略:将FasterNet与YoloV8深度融合,打造更快更强的检测网络

    文章目录 数据集 官方模型的成绩 改进一 改进二 改进三 总结 数据集 本来想选COCO数据集 但是我觉得训练相同的epoch是一种不公平的对比 因为预训练本来就是COCO数据集上得来的 这样对官方的模型有利 而我改动了模型的结构 导致了没
  • 【重点突破】—— 百度地图在React单页面应用中的使用

    重点突破 百度地图在React单页面应用中的使用 前言 百度地图是网页中使用地图的常用第三方工具 这里结合React项目中学到的应用场景总结一些使用要点 一 在网页中嵌入百度地图 搜百度地图开放平台 注册百度开发者账号 控制台 查看应用 创
  • QT的使用(初期笔记)

    signal 发送的信号 signals 自定义信号 返回值是void 只需声明 不需实现 可以有参数 可以重载 按钮 1 inherited 继承 from QAbstractButton 1 clicked bool checked f
  • idea2021版本新建web项目(详细教程)

    打开idea右上角的文件 新建项目 选中java模块 下一步 取名 下一步 打开后是个空白 到这一步 右键选中untitled打开添加框架支持 选中web应用程序 一定要勾选创建web xml 然后点击确定 接下来 找到右上角的添加配置 点
  • matplotlib绘图横坐标或纵坐标文本显示不全

    import matplotlib pyplot as plt x 1 2 3 4 y 1 4 9 6 labels Frogs Hogs Bogs Slogs plt plot x y You can specify a rotation
  • unity使用Tcp/UDP协议网络通信实现(Socket简单应用)

    一 TCP协议 服务器端 1 打开vs 创建一个c 的控制台应用程序 代码如下 记得把ip换成自己电脑ip using System using System Collections Generic using System Linq us
  • INS/GNSS组合导航(七)角速度坐标系变换与欧拉角转换

    注意 角速度与角速度率有严格区别 反映在以下两点 正交的三个角速度 角速度矢量 与欧拉角速率之间的关系如下 欧拉角速率并不是纯粹的正交矢量 而是一个与旋转顺序相关而且非正交的三个矢量 积分欧拉角速率得到的是欧拉角的大小 又称卡丹角 积分角速
  • 股票预测_机器学习预测股票

    2 机器学习技术综述 集成多种人工智能系统的机器学习技术尝试通过对历史数据的学习提取数据模式 这一过程被称为训练或学习 其目的在于实现后续基于新数据的预测 Xiao Xiao Lu and Wang 2013 pp 99 100 使用机器学
  • 【Java】类和对象

    前言 面向对象编程的特性 封装 继承 多态 在Java中 最基本的封装单元是类 一个类的定义为具有相似特征对象的一种抽象 根据类的继承 父类只定义各子类所需的属性和方法 多态是类中同一名称的行为 可以有多种不同的功能 文章目录 前言 一 类
  • Mybatis Generator 配置详解

    许多人在Java项目中都会到使用Mybatis Generator这个工具包 这里把这个工具的配置完整列一下 gt
  • spss常态检验_利用SPSS检验数据是否符合正态分布

    利用SPSS检验数据是否符合正态分布 正态分布也叫常态分布 在我们后面说的很多东西都需要数据呈正态分布 下面的图就是正态分布曲线 中间隆起 对称向两边下降 下面我们来看一组数据 并检验 期初平均分 数据是否呈正态分布 此数据已在SPSS里输
  • Sentinel-持久化

    直接使用dashboard和sentinel配置各种规则时 默认是存在了内存中 如果服务器重启那么数据就会丢失 从而Sentinel提供了5中持久化的方式 将各种配置数据进行持久化 若服务器重启就重新加载持久化的数据 防止数据丢失 1 持久
  • 使用adb查看安装包的apk路径与清除安装包数据与缓存操作实例

    adb shell pm path
  • 【Stata】CGSS数据清理:Codebook速成法

    对数据使用者来说 了解一个调查数据基本情况的常见途径就是查看该数据的codebook 对数据所有者 提供方来说 制作一份详细的codebook是其数据管理工作中不可或缺的一环 2016年上半年CGSS项目组把CGSS2003年到CGSS20
  • 解决Ubuntu安装后无法联网的问题-网卡驱动为安装成功

    转载自 http blog csdn net ifmvo article details 54023628 t0 起因 屁话 最近由于公司电脑不够用 所以暂时使用自己的笔记本做开发 i5 4G win7这配置看个视频 听个音乐还好 可我是做
  • 【动手学习pytorch笔记】9.卷积神经网络基础(卷积层,填充和步长,多输入输出通道,池化层)

    卷积层 二维互相关运算 import torch from torch import nn from d2l import torch as d2l def corr2d X K 计算二维互相关运算 h w K shape Y torch