学习笔记-李沐动手学深度学习(七)(19-21,卷积层、填充padding、步幅stride、多输入多输出通道)

总结

19-卷积层

【补充】看评论区建议的卷积动画视频

数学中的卷积

【链接】https://www.bilibili.com/video/BV1VV411478E/?from=search&seid=1725700777641154181&vd_source=e81e116c4ffe5e79d4bc44738263eda4

【可判断是否为卷积的典型标志】两个函数中自变量相加是否可以消掉,如 下面的τ + x-τ = x

问在某一时刻 这个人的肚子中还有多少食物没消化:
f(t):进食的时间与进食的多少
g(t):某个吃进去的食物 剩余的比例
在这里插入图片描述
当不考虑用户消化食物时,下午两点时用户所剩食物就是f(t)的积分
在这里插入图片描述
在这里插入图片描述

推广到一般情况:
在这里插入图片描述

在这里插入图片描述

f(t)和g(t)中点的对应关系:
在这里插入图片描述
为什么叫卷积: g函数被翻转了一下
在这里插入图片描述
翻转后:
在这里插入图片描述

卷积神经网络

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

【举例】卷积处理图片后的效果

【卷积共有三层含义】
在这里插入图片描述

卷积核:过滤器,选择不同的卷积核可以提到不同的局部特征
【卷积核参数设置】
不想考虑某个位置时,卷积核某位置设为0;想重点考虑某位置时,将卷积核某位置数值设置比较高

1.求均值的卷积核
在这里插入图片描述

【符号】
*即卷积
Σ连加:因为 考虑的是像素点,是离散的,因此不用积分用 Σ累加
g函数相当于规定了 周围像素点如何对当前像素点产生的影响
在这里插入图片描述
下图看到,对应关系还是有点拧着的
在这里插入图片描述
在这里插入图片描述
g函数旋转180°后才是卷积核

在这里插入图片描述
卷积核可以扣在图像上进行对应相乘并最后相加(其实省略了旋转这个步骤,但本质上仍然是卷积运算)

在这里插入图片描述

在这里插入图片描述

【局部性】看全局时,两个图片像素点不同,但是分别看局部,特征是一样的
在这里插入图片描述

当只看局部时
在这里插入图片描述

【不同的卷积核提取后的效果】
在这里插入图片描述

卷积(操作子)(从全连接到卷积)

下图说明了 为什么卷积层是特殊的全连接层:
首先将原全连接层的权重w改写为 四维的(即含二维输入和二维输出)i、j、a、b,
1.【平移不变性】然后对v进行一下重新索引(为保证其平移不变性) 丢掉i、j维度 (即在其他不关注的维度都是一样的东西)后 为va,b
2.【局部性】然后 限制a、b在 负derta~derta的范围内(即只关注 某个位置i、j像素点 附近的东西)
在这里插入图片描述

【引言】MLP处理图片分类任务存在的问题

如一个12M(即1200万)的彩色图片 有RGB三通道,则共 36M像素(每个像素点有一个值),用单隐藏层训练,在模型共有36亿个元素,远远多余所有的猫狗的数量,这样还不如直接记住所有种类

在这里插入图片描述
在这里插入图片描述

在图片中找物体的两个原则

【两个原则】
1.平移不变性:图片识别分类器在识别物体时不会因为该物体像素在图片中出现位置的不同 而改变识别结果(待识别物体出现在图片中任何位置时,应该都能准确识别才行)

2.局部性:只需要看局部信息即可,不需要看全部信息

这两个原则也启发了后续的设计

下面从全连接层出发,应用卷积(即特殊的全连接层)

重新考察全连接层

【此处用矩阵的原因】之前用全连接层时,就将二维矩阵转换成了一维向量,但此时要考察一些空间信息,因此需要用矩阵来计算。

【为何reshape为4D tensor】输入和输出都变成了二维的,权重表示使用下标,要显示输入输出的高宽,所以权重就是四维的

参数解释:(搜一下卷积的动图,原来全连接层是一个权重,现在是一个矩阵的权重)
hi,j:输出(之前学习的全连接层时 是 hi
wi,j,k,l:权重(之前是二维,现在是四维)(之前得输入层和隐藏层是向量,所以w下标为两个。现在输入层和隐藏层变成矩阵,所以w下标是四个。)
xk,l:输入(之前学习的全连接层时是 xi
(弹幕)Wijkl里面的kl是对应X的kl也就是输入的矩阵的元素,ij代表卷积核里面和kl相乘的那个值,因为卷积核的值不会变但是会滑动所以sigma下标是kl,实际就是滑动卷积的意思

【w下标的变换得到v】然后对w进行重新索引(即 重新排列),得到v, 因此 也会使得x的下标有点变化
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

平移不变性

【从图像卷积角度理解, 用卷积核去扫input图像时,卷积核的内容是不变的】
【i、j是位置,i+a、j+b是 以ij位置为参照点进行平移后得到的位置】

至此存在的问题:输入x的平移会导致v的平移(如 x 的i、j分别平移为i+a、j+b,则 识别图像的权重 v也会随之变化),但我们的目标是 x的变化不应该引起v的变化

【权重就是特征提取器,不应该随位置而发生变化】i、j应该是 图片中不同的位置索引,将v改为va,b后(即丢掉v的i、j两个维度),就不依赖于 输入x的位置i、j了

虽然下图红框是二维卷积,但是严格在数学上来说是 二维交叉相关
在这里插入图片描述

局部性

【从图像卷积角度理解, 用卷积核去扫input图像时,每次只关注input图像中 卷积核扫描的那一部分,而不是每次关注全部input图像】
理论上,以i、j为中心,可以平移到任意位置,但实际上 我们不应该看离i、j太远的位置(即令太远的va,b=0,即不关注了),应该只看其附近的点
即:关注的位置 即 i、j变化的位置i+a、j+b 只关注 a和b在 [-derta,+derta]的范围内(即下图橙框)
在这里插入图片描述

【局部性-补充】评论区推荐视频的通俗理解:
看全局时,两个图片像素点不同,但是分别看局部,特征是一样的
在这里插入图片描述

当只看局部时
在这里插入图片描述

卷积层

核矩阵(即卷积核)W和偏移b都是可以学习的参数
核矩阵(卷积核)的大小是超参数,其控制局部性
在这里插入图片描述

概述

在这里插入图片描述

二维卷积

全程中 核是不变的(即平移不变形)
在这里插入图片描述

【二维卷积层】
用卷积核去扫描时,丢掉的内容就是 (kh - 1) x (kw - 1)
下图中 五角星 即为 上节定义的二维交叉相关操作子;
W和b都是可以学习的参数
在这里插入图片描述

【举例】
弹幕说:卷积核肯定是自己学,因为卷积核中每个元素都代表一个weight
在这里插入图片描述

交叉相关

交叉相关和卷积没有太多区别,唯一的区别是w角标中的a、b和-a、-b
(弹幕说:是不是说卷积时他的核需要逆时针旋转180°,相关不需要。
实际运算时反正参数推出来了,效果也达到了,所以我们就不去深究里面翻转前后代表的意义了)

实际应用中虽然说 使用的是卷积操作,但是实际上用的是交叉相关(因为 严格来说卷积 要按照下图中这么写,即 w角标为-a、-b,但 我们 从使用者的角度 并不严格)
在这里插入图片描述

一维和三维交叉相关

主要关注的还是二维图像

在这里插入图片描述

代码

互相关运算

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

def corr2d(X, K):   # X 为输入,K为核矩阵
    """计算二维互相关信息"""
    h, w = K.shape  # 核矩阵的行数和列数
    Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1)) # 初始化输出Y的形状。X.shape[0]为输入高    
    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)
二维卷积层

互相关运算,就是类似于点积,对应位置(卷积核覆盖的区域)元素相乘再相加,
在这里插入图片描述

【应用】检测图像颜色边缘

对于某一个图像,如果 某个像素与其相邻像素相同,则 与 [1,-1]核运算后 为0,则不是边缘; 如果某处是边缘(即 由0变为1或1变为0),则 与[1,-1]核运算后 不为0(要么是1,要么是-1)

在这里插入图片描述

# 实现二维卷积层
class Conv2D(nn.Module):
    def __init__(self, kernel_size):
        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 = torch.ones((6,8))
X[:,2:6] = 0  # 把中间四列设置为0
print(X)  # 0 与 1 之间进行过渡,表示边缘

K = torch.tensor([[1.0,-1.0]])  # 如果左右原值相等,那么这两原值乘1和-1相加为0,则不是边缘
Y = corr2d(X, K)
print(Y)
print(corr2d(X.t(), K)) # X.t() 为X的转置,而K卷积核只能检测垂直边缘

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

给定输入X和输出Y,学习得到卷积核K

在这里插入图片描述

# 学习由X生成Y的卷积核(此处以检测垂直边缘为例)(最简单的简化版)
# 第一个参数1:输入通道为1,;第二个参数1:输出通道为1;要学习的核是  1x2的
# 单个矩阵,输入通道为1,黑白图片通道为1,彩色图片通道为3。这里输入通道为1,输出通道为1.   
conv2d = nn.Conv2d(1, 1, kernel_size=(1,2), bias=False) 
# 1,1,6,8:batch_size、channel、height、width
X = X.reshape((1,1,6,8)) # 通道维:通道数channel,RGB图3通道,灰度图1通道。批量维就是样本维,就是样本数batch_size
Y = Y.reshape((1,1,6,7))  # 输出的shape(因为 核是1x2的,所以最后会少一列即  6x8变成了6x7)
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 # 3e-2是学习率。沐神裸写的梯度下降
    if(i+1) % 2 == 0:
        print(f'batch {i+1},loss {l.sum():.3f}')

# 所学的卷积核的权重张量
print(conv2d.weight.data.reshape((1,2)))

在这里插入图片描述
在这里插入图片描述

QA

在这里插入图片描述

17.没区别。
100个神经元的单隐藏层MLP 即有 一个输出维度为100的全连接层

只是为了说明 为什么卷积是特殊的全连接层

19.图片输入时就是一个二维的(就是个矩阵)
之前使用softmax回归时,把图片reshape成了一个一维向量

20.没听过

21.感受野即kernel的大小

这个问题类似于之前全连接层提到过的 一个很浅的很宽的全连接层的效果没有 一个 深一点且窄一点的全连接层效果好
同理对于卷积层,使用层数少且每层核大 的 效果不如 层数多且每层的核小一点 的效果好

一般用3x3或5x5

这个就是inception的设计思路

在这里插入图片描述

23.信号与处理中 就是那么定义的,深度学习只是拿来用用,并没纠结细节

24.不管在图片的哪个位置,核是不变的

25.只是为了讲课定义的

26.数字信号处理中 可以看看

在这里插入图片描述

27.抖动厉害的原因:(抖动没事,只要 呈下降趋势即可,但是一直抖不下降是有问题的)
(1)数据多样性很大,每次随机采样的数据 区别很大, 这样是没事的( 可以做平滑,好看一点)
(2)学习率很大。可以降低学习率lr (或者batch_size大一点)

不是这个意思。

全连接层最大的问题是 权重矩阵W的高(好像就是 矩阵的行数)取决于 输入的宽 。那么此时当给定的输入是 1200万像素的图片,那么 输入维度就是1200万,那么权重矩阵参数量太大 就炸掉了。
而 卷积不存在这种问题,因为卷积核大小是固定的,无论输入的大小是多大(而且实际上也不会直接丢进去一个 1200万像素的输入)

弹幕说:mlp放不下的原因是因为权重参数的矩阵过大

20-卷积层中的填充和步幅

填充和步幅

卷积核大小kernel_size、填充padding、步幅stride都是 超参数

在这里插入图片描述
博客:
① 奇数卷积核更容易做padding。我们假设卷积核大小为k * k,为了让卷积后的图像大小与原图一样大,根据公式可得到padding=(k-1)/2,这里的k只有在取奇数的时候,padding才能是整数,否则padding不好进行图片填充。

② k为偶数时,p为浮点数,所做的操作为一个为向上取整,填充,一个为向下取整,填充。

填充padding

【总结】通常情况下,padding的高宽是对称的,且取为核大小-1,即ph=kh-1、pw=kw-1(这个是指课件理论中的 含上下或左右的 某个方向一共填充的大小,如果 在代码中 要写为 padding=ph/2)。从而使得输出形状=输入形状
【注意ph、pw与代码中的padding】此处填充ph和pw是指 从高度方向、宽度方向 共填充了多少,如 ph=2 上下共填充了2行,相当于 代码中的padding=1。即 对于 卷积核大小为3x3的、padding=1(代码中写padding=1,课件理论中ph、pw=2,二者是二倍的关系) 进行卷积操作后,输入和输出形状相同;对于 5x5的卷积核大小、padding=2(代码中写padding=2,课件理论中ph、pw=4),输入和输出形状相同

nh和nw为输入数据的高、宽

【引言-填充】当不使用padding时,经过多层卷积后 形状会变得很小

下图中:每一层都会减4,第七层大小就变成4X4了
在这里插入图片描述
【正文-填充】

在这里插入图片描述
在这里插入图片描述
【有填充时的输出形状计算】
【注意ph、pw与代码中的padding】此处填充ph和pw是指 从高度方向、宽度方向 共填充了多少,如 ph=2 上下共填充了2行,相当于 代码中的padding=1。即 对于 卷积核大小为3x3的、padding=1 进行卷积操作后,输入和输出形状相同;对于 5x5的卷积核大小、padding=2,输入和输出形状相同

p为padding,当 按下图中通常方式取ph和pw(即ph=kh-1、pw=kw-1)时,无论核的大小如何,输出和输入的形状相同
一般来说很少用核长宽为偶数的卷积核
下图中的类似[ ] 的是向上、下取整
在这里插入图片描述

步幅stride

【引言-步幅】
在这里插入图片描述

【正文-步幅】每次移动核时,可以 一次向右和向下 移动几格
下图中第一个图的两个蓝色区域是 分别从 起点(即左上角)向右移动一次(2步幅)、向下移动一次(3步幅)。
当继续移动 剩余区域不够时,就不移动了
在这里插入图片描述
【有步幅时的输出形状计算】
根据公式,如果 stride=2,那么 输出尺寸的高宽相当于减半
在这里插入图片描述
类似中括号的是 floor向下取整
在这里插入图片描述

代码

【通常情况下都是对称的】输入的数据形状是 高宽相同的,padding是对称的,stride也是对称的

【注意ph、pw与代码中的padding】此处填充ph和pw是指 从高度方向、宽度方向 共填充了多少,如 ph=2 上下共填充了2行,相当于 代码中的padding=1。即 对于 卷积核大小为3x3的、padding=1 进行卷积操作后,输入和输出形状相同

# 在所有侧边填充1个像素
import torch
from torch import nn

def comp_conv2d(conv2d, X): # conv2d 作为传参传进去,在内部使用
    # 在维度前面加入一个批量大小数batch_size和通道数channel(因为暂时没考虑批量大小数和通道数)
    X = X.reshape((1,1)+X.shape) 
    Y = conv2d(X)  # 卷积处理是一个四维的矩阵
    return Y.reshape(Y.shape[2:]) # 将前面两个维度拿掉

# 【填充】在所有侧边分别填充1个像素
conv2d = nn.Conv2d(1,1,kernel_size=3,padding=1) # padding=1 为左右都填充一行,相当于之前讲的ph、pw=2
X = torch.rand(size=(8,8))
print(comp_conv2d(conv2d,X).shape)  # torch.Size([8, 8])  即没改变输入的形状
# 【填充】填充不同的高度和宽度(核的形状为5x3, 填充时上下分别填充2行、左右分别填充1列)
conv2d = nn.Conv2d(1,1,kernel_size=(5,3),padding=(2,1))
print(comp_conv2d(conv2d,X).shape)  # torch.Size([8, 8])  即没改变输入的形状

# 【填充+步幅】将高度和宽度的步幅设置为2
conv2d = nn.Conv2d(1,1,kernel_size=3,padding=1,stride=2)
print(comp_conv2d(conv2d,X).shape)   # torch.Size([4, 4])。
# 因为步幅sh、sw为2,可以被输入的高、宽整除,因此输出为(nh/sh) x (nw/sw)

# 【填充+步幅】一个稍微复杂的例子
conv2d = nn.Conv2d(1,1,kernel_size=(3,5),padding=(0,1),stride=(3,4))
print(comp_conv2d(conv2d,X).shape)  # torch.Size([2, 2])  。 套公式计算

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

QA

在这里插入图片描述

  1. ppt错了,55层

重要程度:核大小> 填充通常取默认的、步幅取值取决于你要把你的模型大小控制在什么程度
卷积核大小kernel_size:
填充padding:通常ph和pw取值为 卷积核大小-1 ,从而实现 卷积核不改变输入形状大小(注意 如果是代码中 padding=1 相当于课件中的ph、pw=2)
步幅stride:通常padding=1(因为如果每层都减半,经过几个卷积层后 图片就很小 几乎没了 这样就 做不了深的神经网络了,因此减半是个别情况)。 不为1时 是因为计算量太大了,此时通常步幅取2。步幅越大,计算量越小;步幅越小,模型所需层数就很大(因为一般是 想将一个很大的输入图片 变成一个很小的)

3.是的。因为padding(课件理论中)=kernel-1,而padding是分在图片上下的,kernel为基数,padding就可以对半分。
注意 课件理论中的 ph、pw 除以2才为代码中的 padding

当然,也可以取偶数

4.看第二个问题
减半是很少的情况,大多数情况是不变的

padding、stride、通道数,这些是神经网络架构设计的一部分,当用不同的神经网络时 一般都会告诉你这些参数如何设定

在这里插入图片描述

6.一般来说很少会自己纯手写神经网络, 如用ResNet(kaiming大神的残差神经网络)就够了,其也分很多系列。除非你的输入是非常不一样的情况,如 是20x1000,很扁的这种,可能需要自己设计神经网络,否则一般用经典的即可 或 在经典的基础上做调整。

即便自己设计神经网络,也是参照经典神经网络的基础上

7.回看代码

8.回看代码

9.不存在这种情况

在这里插入图片描述

虽然单独看3x3很小,但是 如果神经网络很深时, 较深的层中的每个元素 能看到 足够大的图片信息

高层会看到低层所看到信息总和
对于后面比较深的卷积层中的 1x1、3x3这种,其实 每个元素对应的是 较浅层中很大的图片范围的,看到的信息并不小
在这里插入图片描述

11.NAS(Neural Network Architecture Search),也是自动机器学习的一部分
弹幕说:autodl和automl,计算成本太高,不是一般人研究的起的

(1)方式一:设计很多神经网络结构,从中选择效果最好的

12.从信息论的角度来说,特征信息肯定会丢失的
ML本质是一个极端的压缩算法:给你一个图片,最后得到一个类别、有语义信息的数值。 即把 比较原始的计算机能理解的像素信息、文字字符串的信息压缩到人能理解的 语义空间中

在这里插入图片描述

13.有,但是成本极大(沐神的一个实验跑了100w美金)

14.同13

15.是可以人为控制的

16.从理论上来说,大概是:三个3x3卷积核的效果是可以用2个5x5卷积核来替代的;10层3x3卷积的效果可以等效成5或6层 的5x5的卷积,
但是,3x3卷积更快,(涉及计算复杂度、成本方面的问题、更“贵”)

在这里插入图片描述

17.可以这样用。但是一般来说,简单高效易懂的更容易被人记住,即类似 都用比较简单的核。
太复杂的 可以不容易被人理解

18.后面会讲,不同的卷积层 可以看不同的纹理特征

DL不是有钱人的游戏。
如果不用DL:
1、用人,机器成本可能会低点,可能效果差,就需要更多的调参,即人力成本。
2、其次数据成本很大,数据很贵

DL使用GPU的算力来替代 人力成本和数据成本, 虽然计算算力变高。
NAS现在是有钱人的游戏,但是任何科技都是从很贵到很便宜的过程(如当年的磁盘计算机也很贵)

21-卷积层里的多输入和多输出

输出通道是当前卷积层的超参数, 输入通道是 上一个卷积层的 超参数(即上一个卷积层的输出通道)

在这里插入图片描述

多输入输出通道

引言

之前Fashion mnist是单通道(只有一个灰)

在这里插入图片描述
在这里插入图片描述

正文-多个输入通道

【多个输入通道】
如下图,通道0的数据和通道0的卷积核做点积运算,同理通道1,最后将两个通道的结果相加
在这里插入图片描述

现在假定输入数据X是三维的tensor,即三个通道,则卷积核也变成了三维的(与输入数据维度相同);每个通道都有一个 偏移(即长为ci的向量),此处只是没写
i:input
输出是单通道的,因为不管输入有多少个通道,都是最后按通道相加
在这里插入图片描述

正文-多个输出通道

【多个输出通道】 多个输入通道和多个输出通道其实是没有相关性的,可以分别设置
【个人理解,暂时没问题】输出通道数=卷积核个数,即下图中co

对于每个输出的通道,都有一个自己的三维卷积核,
co:output channel

弹幕说:这里等于就是利用多个卷积核,分别对输入进行上一页PPT的卷积操作,最后将结果分通道叠在一起。ci个通道,每个通道co种卷积核,共有ci*co种卷积核。

老师说:对每一个输入(下图中第一个红框),把它对应的一个输出通道的核拿出来(第二个红框),就会得到一个对应的输出通道(第三个红框),对每一个输出通道一一这样运算,最后将结果concat起来,得到输出Y

Yi,:,:输出里面的第i个通道
在这里插入图片描述
【多个输入和多个输出通道的意义】
多输出通道:每个输出通道可以取识别一种模式(如不同的卷积核 可以提取不同 角度的特征,如 边缘、锐化、颜色、纹理等),通过学习不同的卷积核权重 来匹配不同的模式,如下图中有6个输出通道

多输入通道:假设将上一层 得到的六个输出通道的结果 丢给下一层,将每个通道的到的结果组合起来(如 加权相加),得到组合的模式识别。这是对于相邻的两层,从整体的深度网络来看,浅层、下面的层识别 具体细节特征如 边缘特征、纹理等,
深层次的层可以将之前浅层得到的 分别的特征(模式)进行组合(如 将 胡须、眼睛等 组合起来 得到一个猫头,最深层、最高层 可能得到一整只猫)
在这里插入图片描述

1x1卷积层

【1x1卷积层可以认为是卷积层,也可以等价认为是一个全连接层】
卷积核的高宽均为1,每次只看一个像素(即不看 周围空间的特征,即其不识别空间信息,不看当前这个像素与周围其他像素的关系)
本质上等价于一个 形状为nhnw x ci、权重为co x ci x 1 x 1的全连接层

输出为0的通道,输出为1的通道

弹幕说:
1.其实就是对input里的3个矩阵做全连接,这里是做了两次不同权重的全连接
2. 3个输入通道经过一个核得到一个输出通道,这里有两个核,所以得到两个输出通道
3. 对的,这里理解为两组核或者两套核比较好一些,一组核包括三个核
在这里插入图片描述
在这里插入图片描述

最通用情况下的二维卷积层

【偏差B的理解(弹幕说)】
每一个卷积核都对应一个单独的偏差
pytorch的官方文档,bias是和卷积核个数相同
其实就是Co组核,每组核有Ci个偏差
这里+B是用了广播机制(不确定)

【计算复杂度的理解】
可以这么理解,输出层共有CoMhMw个元素,每个元素都是size大小为CiKhKw的卷积核计算得到的
在这里插入图片描述

代码

多输入通道互相关计算

【zip的作用】
弹幕:
zip(X, K)函数可以将X和K的每个通道配对,返回一个可迭代对象,其中每个元素是一个(x, k)的元组,表示一个输入通道和一个卷积核。
zip函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

在这里插入图片描述

在这里插入图片描述

多输出通道的互相关计算

torch.stack():沿着一个新维度对输入张量序列进行连接,序列中所有的张量都应该为相同形状
下图中即在dim=0这个维度上 进行堆叠

三个卷积核,每个卷积核有两个通道,每个通道是2*2的矩阵
在这里插入图片描述

# 多输入通道互相关运算
import torch
from d2l import torch as d2l
from torch import nn

# 多通道输入时的互相关运算
def corr2d_multi_in(X,K):  # 此处假设X和K都是3D的
    return sum(d2l.corr2d(x,k) for x,k in zip(X,K)) # X,K为3通道矩阵,for使得对最外面通道进行遍历
# zip(X, K)函数可以将X和K的每个通道配对,返回一个可迭代对象,其中每个元素是一个(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]]])
print(corr2d_multi_in(X,K))

# 多输出通道运算
def corr2d_multi_in_out(X,K):  # X为3通道矩阵;K为4通道矩阵,最外面维为输出通道      
    # 弹幕说:就是从4D的K中拿出一个3D的k进行上一步操作
    # 大K中每个小k是一个3D的Tensor。0表示stack堆叠函数里面在0这个维度堆叠。           
    return torch.stack([corr2d_multi_in(X,k) for k in K],0) 


print(K.shape)
print((K+1).shape)
print((K+2).shape)
print("K:",K)
print(K+1)
K = torch.stack((K, K+1, K+2),0) # 原来的K是3D的,现在使用stack创建一个 三输出通道的新K
print(K.shape)   # torch.Size([3, 2, 2, 2])  : 输出通道为3,输入通道为2,h、w分别为2
print("新的K:",K)
print(corr2d_multi_in_out(X,K))

在这里插入图片描述

1x1卷积

验证一下 1x1的卷积 等价于 一个全连接
在这里插入图片描述

# 【定义一个用全连接实现 1x1的 多输入多输出通道 的互相关操作】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)) # 拉平操作(把高宽拉成一个向量),每一行表示一个通道的特征。此时X是一个矩阵
    K = K.reshape((c_o,c_i))  #  原K完整是  co x ci x 1 x 1,去掉1x1后 ,K也是一个矩阵
    Y = torch.matmul(K,X) 
    return Y.reshape((c_o, h, w))

X = torch.normal(0,1,(3,3,3))   # norm函数生成0到1之间的(3,3,3)矩阵 
K = torch.normal(0,1,(2,3,1,1)) # 输出通道是2,输入通道是3,核是1X1

Y1 = corr2d_multi_in_out_1x1(X,K)
Y2 = corr2d_multi_in_out(X,K)
assert float(torch.abs(Y1-Y2).sum()) < 1e-6
print(float(torch.abs(Y1-Y2).sum()))

在这里插入图片描述

QA

在这里插入图片描述

20.输入通道基本是固定的, 因为输入是给定的。输出通道理论上可以设为任意值(虽然实际上肯定不能随便设)

【直观理解】一般来说,输入和输出的数据 高宽不变时, 输出通道也会设为和输入通道一致。
但是如果输出的数据 高宽都减半了,那么 输出通道数 会 设为 输入通道数的二倍(即 把空间信息压缩了, 并把提取出的信息在更多的通道上存储起来)

21.不会影响模型的精度、模型的性能(当然 很多0会影响计算性能,计算变慢了)

22.每个通道上的卷积核是不一样的;(一般来说)不同通道的卷积核大小是一样的,这样方便计算、计算上的效率更高(当然理论上也可以让不同通道的卷积核大小不同)

23.偏移的影响并不是很大(况且后续还有BN的存在),而且几乎不会对计算性能产生影响

24.核的参数是学习出来的

在这里插入图片描述

不是的。有深度图信息后要使用三维卷积,此时输入数据变为 4D的(即 输入通道 x 深度 x 宽 x 高),核变为5D的,输出为4D的

26.对于多输入通道,一个输入通道有一个卷积核 得到一个计算结果, 多个输入通道计算结果会累加。
多输出通道数 取决于co,与 多输入通道数的独立的,

三维卷积核是五维的, 含 输入通道、输出通道、高、宽、深度信息

27.信号处理区分高低频,图像里面好像不太注重这个。 数据丢进去 网络自己学习

28.卷积核的高宽均为1,每次只看一个像素(即不看 周围空间的特征,即其不识别空间信息,不看当前这个像素与周围其他像素的关系)

29.是的。这个就是mobile net(音译,移动端用的卷积神经网络,计算复杂度很低)

在这里插入图片描述

30.卷积有位置信息,而且对位置很敏感。
输出数据中第i行第j列的元素 就是对应 输入数据中第i行第j列元素附近那一块的信息。
因此 卷积输出的那些信息、位置信息 是 输出的元素在矩阵中的位置决定的,后续会讲基于 池化层 使得不对位置那么敏感。

31.通道之间是不共享参数的,我们希望每个通道能学习到不同的东西、模式。
弹幕说:同一卷积层共享参数,通道之间的不共享
卷积层参数共享指的是整个图像用同一个卷积核来扫描,和全连接网络相比共享了参数。

可以把 计算复杂度中的 mh和mw用 含nh nw去替换,因为 mh mw就是通过nh nw计算出来的。
只是用mh、mw表示 会简单一点,且可以直观看出 计算复杂度与 输出数据中高宽的关系
在这里插入图片描述

在这里插入图片描述

33.同32

34.我们无法控制每个卷积核究竟能提取到什么信息,核参数都是学习出来的。
当然 一般需要多次卷积 即深度卷积神经网络。

35.需要save和load
老师一般用 vim + VSCode
弹幕说:Vscode安装jupyterlab插件,简直不要太爽

在这里插入图片描述

36.正确。

37.feature map就是卷积的输出

38.输入通道不是动态变化的。

39.奇数在padding时方便一点。

40.rgbd可以用3D卷积,也可以用2D卷积(每个深度做一个2D卷积,然后用RNN或直接concat起来)

本次课程不会讲3D卷积,其在视频中用的多,其效果稍微比2D卷积好一点点、但是计算复杂度高很多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/415120.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity零基础到进阶 | Unity中的 RectTransformUtility 方法整理汇总

Unity零基础到进阶 ☀️| RectTransformUtility 方法整理汇总一、RectTransformUtility 官方文档1.1 RectTransformUtility.CalculateRelativeRectTransformBounds&#xff08;重&#xff09;1.2 RectTransformUtility.FlipLayoutAxes1.3 RectTransformUtility.FlipLayoutOnAxi…

Unity中URP实现水体(水的焦散)

文章目录 前言一、原理1、 通过深度图&#xff0c;得到 对应像素 在 世界空间下的Z值2、得到模型顶点在 观察空间 下的坐标3、由以上两点得到 深度图像素 对应的 xyz 值4、最后&#xff0c;转化到 模型本地空间下&#xff0c;用其对焦散纹理采样 二、实现1、获取深度图2、在顶点…

[WebUI Forge]ForgeUI的安装与使用 | 相比较于Auto1111 webui 6G显存速度提升60-75%

ForgeUI的github主页地址:https://github.com/lllyasviel/stable-diffusion-webui-forge Stable Diffusion WebUI Forge 是一个基于Stable Diffusion WebUI(基于Gradio)的平台,可简化开发、优化资源管理并加快推理速度。 “Forge”这个名字的灵感来自于“Minecraft Forge”…

《Vite 基础知识》Vitepress 技术文档站点搭建与配置

前言 简介 VitePress 是一个静态站点生成器 (SSG)&#xff0c;专为构建快速、以内容为中心的站点而设计。 简而言之&#xff0c;可构建你自己的 技术文档站点&#xff1b; 环境要求 Node.js 18 及以上版本。我使用 v20.11.0 创建 第一步&#xff1a; 全局安装 npm i vitep…

图搜索基础-深度优先搜索

图搜索基础-深度优先搜索 参考原理引入流程解析手推例子 代码实现运行结果结果分析 参考 理论参考&#xff1a;深蓝学院 实现参考&#xff1a;github项目 原理 引入 对于这样一个图&#xff0c;我们试图找到S到G的通路&#xff1a; 计算机程序不会像人眼一样&#xff0c;一…

鸿蒙应用程序包安装和卸载流程

开发者 开发者可以通过调试命令进行应用的安装和卸载&#xff0c;可参考多HAP的调试流程。 图1 应用程序包安装和卸载流程&#xff08;开发者&#xff09; 多HAP的开发调试与发布部署流程 多HAP的开发调试与发布部署流程如下图所示。 图1 多HAP的开发调试与发布部署流程 …

线性DP-前缀和

哪种连续子字符串更长 思路 我们遍历输入字符串s中的每个字符。对于每个字符&#xff0c;我们检查它是1还是0&#xff0c;并相应地更新currentLength1和currentLength0。当我们遇到一个1时&#xff0c;我们增加currentLength1的值&#xff0c;并将currentLength0重置为0&#…

2023秋季飞书未来无限大会--随笔

这个时代的飞书 数字时代 工作协同平台 AI时代 帮助企业和个人用好AI 企业如何引用大模型能力&#xff1f; 智慧体— 接近人&#xff0c;有进步空间智能伙伴 用时代的科技打造爱不释手的好产品 移动互联网 – 改变信息分发方式 大模型 –自然的人机交互方式 业务协同 …

Swagger接口文档管理工具

Swagger 1、Swagger1.1 swagger介绍1.2 项目集成swagger流程1.3 项目集成swagger 2、knife4j2.1 knife4j介绍2.2 项目集成knife4j 1、Swagger 1.1 swagger介绍 官网&#xff1a;https://swagger.io/ Swagger 是一个规范和完整的Web API框架&#xff0c;用于生成、描述、调用和…

kali linux通过aircrack-ng命令破解wifi密码

相关阅读&#xff1a;如何破解攻击WiFi 百度安全验证https://baijiahao.baidu.com/s?id1764248756021219497&wfrspider&forpc上面2篇文章写得都很不错 一、前期准备工作 1、将无线网卡挂载到Kali上 ​ 将无线网卡插到电脑上&#xff0c;如果弹出检测到新的USB设备&…

break,continue

break&#xff1a;跳出并结束循环 continue:跳过本次循环&#xff0c;执行下一次循环 代码演示&#xff1a; package com.zhang.loop;public class BreakAndContinueDemo8 {public static void main(String[] args) {//掌握break和continue的作用//1. break&#xff1a;跳出循…

​LeetCode解法汇总2673. 使二叉树所有路径值相等的最小代价

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个整数 n 表示一棵 满二叉树 里面节…

Java设计模式 | 七大原则之迪米特法则

基本介绍 一个对象应该对其他对象保持最少的了解类与类关系越密切&#xff0c;耦合度越大迪米特法则&#xff08;Demeter Principle&#xff09;又叫最少知道法则&#xff0c;即一个类对自己依赖的类知道的越少越好。也就是说&#xff0c;对于被依赖的类不管多么复杂&#xff…

虚拟机 VMware 安装 Windows2000 (iso 光盘镜像)

上篇博客关于 kali 的安装&#xff0c;我们下载的直接是 vmx 文件 这次我们以 iso 文件为例&#xff0c;因此配置过程会有些许不同 先在本地新建一个文件夹用于存放我们一会儿下载的 iso 镜像文件 下载好后是一个后缀为 .iso 的文件 同样我们先打开 VMware 依次点击文件 -&g…

亚信安慧AntDB开启超融合数据库新纪元

&#xff08;一&#xff09; 前言 据统计&#xff0c;在信息化时代的今天&#xff0c;人们一天所接触到的信息量&#xff0c;是古人一辈子所能接收到的信息量的总和。当今社会中除了信息量“多”以外&#xff0c;人们对信息处理的“效率”和“速度”的要求也越来越高。譬如&…

lv21 QT对话框3

1 内置对话框 标准对话框样式 内置对话框基类 QColorDialog, QErrorMessage QFileDialog QFontDialog QInputDialog QMessageBox QProgressDialogQDialog Class帮助文档 示例&#xff1a;各按钮激发对话框实现基类提供的各效果 第一步&#xff1a;实现组件布局&…

C语言标准库函数qsort( )——数据排序

大家好&#xff01;我是保护小周ღ&#xff0c;本期为大家带来的是深度解剖C语言标准库函数 qsort()&#xff0c;qsort()函数他可以对任意类型的数据排序&#xff0c;博主会详细解释函数使用方法&#xff0c;以及使用快速排序的左右指针法模拟实现函数功能&#xff0c;这样的排…

本科毕业设计:计及并网依赖性的分布式能源系统优化研究。(C语言实现)(内包含NSGA II优化算法)(一)

目录 前言 1、分布式能源系统模型介绍 2、运行策略 前言 本篇文章介绍的是我的毕业设计&#xff0c;我将C语言将其实现。 1、分布式能源系统模型介绍 这是我将研究的分布式能源系统的框架&#xff0c;内部供能装置包括&#xff1a;太阳能光伏板&#xff1b;sofc燃料电池、太阳…

【数据结构】周末作业

1.new(struct list_head*)malloc(sizeof(struct list_head*)); if(newNULL) { printf("失败\n"); return; } new->nextprev->next; prev->nextnew; return; 2.struct list_head* pprev->next; prev->nextp->next; p->next->prevpr…

设计模式----装饰器模式

在软件开发过程中&#xff0c;有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下&#xff0c;可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。 装饰器模式 允许向一个现有的对象添加新的功能&#xff0c;同时又不改变他的…