动手学深度学习V2每日笔记(卷积层)

本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1L64y1m7Nh/p=2&spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=c7bfc6ce0ea0cbe43aa288ba2713e56d
文档教程 https://zh-v2.d2l.ai/

本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录,内容不会特别严谨仅供参考。

1.函数目录

1.1 python

python位置
元组加法操作2.2

1.2 torch

torch.nn位置
Conv2d2.3
stack2.3
cat2.3

2. 卷积神经网络

2.1 卷积层

卷积层将输入和核矩阵进行交叉相关运算,加上偏移后得到输出。核矩阵和偏移是可以学习的参数。核矩阵的大小是超参数。

  • 交叉相关VS卷积
  • 二维交叉相关
    y i , j = ∑ a = 1 h ∑ b = 1 w w a , b x i + a , j + b y_{i,j}=\sum_{a=1}^h\sum_{b=1}^ww_{a,b}x_{i+a,j+b} yi,j=a=1hb=1wwa,bxi+a,j+b
  • 二维卷积
    y i , j = ∑ a = 1 h ∑ b = 1 w w − a , − b x i + a , j + b y_{i,j}=\sum_{a=1}^h\sum_{b=1}^ww_{-a,-b}x_{i+a,j+b} yi,j=a=1hb=1wwa,bxi+a,j+b
  • 由于对称性,在实际使用中没有区别
  • 一维和三维交叉相关
  • 一维
    y i = ∑ a = 1 h w a , x i + a y_{i}=\sum_{a=1}^hw_{a,}x_{i+a} yi=a=1hwa,xi+a
  • 文本、语言、时序序列
  • 三维
    y i , j , k = ∑ a = 1 h ∑ b = 1 w ∑ c = 1 d w a , b , c x i + a , j + b , k + c y_{i,j,k}=\sum_{a=1}^h\sum_{b=1}^w\sum_{c=1}^dw_{a,b,c}x_{i+a,j+b,k+c} yi,j,k=a=1hb=1wc=1dwa,b,cxi+a,j+b,k+c
  • 视频、医学图像、气象图像

2.1.1 二维互相关运算

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.arange(9).reshape(3,3)
K = torch.arange(4).reshape(2,2)

print(corr2d(X, K))

2.1.2 卷积层

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

    def forward(self, x):
        return corr2d(x, self.weight) + self.bias

2.1.3 完整代码

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.arange(9).reshape(3,3)
K = torch.arange(4).reshape(2,2)

print(corr2d(X, K))
# 自定义卷积层
class Conv2D(nn.Module):
    def __init__(self, kernel_size):
        super().__init__()
        self.weight = nn.Parameter(torch.rand(size=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
print(x)

k = torch.tensor([[1.0, -1.0]])
Y = corr2d(x, k)
print(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
    if(i+1)%2 == 0:
        print(f'batch{i+1}, loss{l.sum():.3f}')

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

2.2 填充和步幅

2.2.1 填充padding

在输入周围添加额外的行、列
在这里插入图片描述

  • 填充 p h p_h ph行和 p w p_w pw列,输出的形状为
  • ( n h − k h + p h + 1 ) ∗ ( n w − k w + p w + 1 ) (n_h-k_h+p_h+1)*(n_w-k_w+p_w+1) (nhkh+ph+1)(nwkw+pw+1)

2.2.2 步幅stride

  • 步幅是指行/列的滑动步长
  • 例如;高度3宽度2的步长
    在这里插入图片描述
    填充和步幅是卷积层的超参数
    填充在输入周围添加额外的行/列,来控制输出的形状
    步幅是每次滑动核窗口时的行/列的步长,可以成倍的减少输出形状

2.3.3 元组加法运算

a = (1, 1)
b = (8, 8)
print(a+b)

在这里插入图片描述
列表也具有相同的操作

a = [1, 1]
b = [8, 8]
print(a+b)

在这里插入图片描述

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((8,8))
print(comp_conv2d(conv2d, X).shape)

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

2.3 多输入输出通道

2.3.1 多个输入通道

  • 彩色图片可能有RGB三个通道
  • 转换为灰度会丢失信息
    在这里插入图片描述
    每个通道都有一个卷积核,结果是所有通道卷积结果的和
    在这里插入图片描述
    多个输入通道
输入X核W输出Y
c i ∗ n h ∗ n w c_i*n_h*n_w cinhnw c i ∗ k h ∗ k w c_i*k_h*k_w cikhkw m h ∗ m w m_h*m_w mhmw

Y = ∑ i 0 c i X i , : , : ∗ W i , : , : Y = \sum_{i_0}^{c_i}X_{i,:,:}*W_{i,:,:} Y=i0ciXi,:,:Wi,:,:
无论有多少输入通道,到目前为止我们只用到单输出通道。

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

def corr2d_multi_in(X, K):
    return sum(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]]])
print(corr2d_multi_in(X, K))

2.3.2 多个输出通道

我们可以有多个三维卷积核,每个核生成一个输出通道。

输入X核W输出Y
c i ∗ n h ∗ n w c_i*n_h*n_w cinhnw c o ∗ c i ∗ k h ∗ k w c_o*c_i*k_h*k_w cocikhkw c o ∗ m h ∗ m w c_o*m_h*m_w comhmw

Y = ∑ i 0 c i X i , : , : ∗ W i , : , :   f o r   i = 1 , . . . , c o Y = \sum_{i_0}^{c_i}X_{i,:,:}*W_{i,:,:} \ for\ i=1,...,c_o Y=i0ciXi,:,:Wi,:,: for i=1,...,co

  • 每个输出通道都可以识别特定模式
    在这里插入图片描述
  • 输入通道核识别并组合输入中的模式
def corr2d_multi_in_out(X, K):
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

K = torch.stack((K, K+1, K+2), 0)
print(K.shape)
print(corr2d_multi_in_out(X,K))

2.3.3 1*1卷积层

k h = k w = 1 k_h=k_w=1 kh=kw=1是一个受欢迎的选择。它不识别空间模式,只是融合通道。
在这里插入图片描述
相当于输入形状为 n h n w ∗ c i n_hn_w*c_i nhnwci,权重为 c o ∗ c i {c_o*c_i} coci的全连接层。

2.3.4 nn.Conv2d()

nn.Conv2d 的作用是对输入的二维数据(如图像)进行卷积操作,输出经过卷积处理后的特征图。卷积操作可以帮助网络学习到数据的局部特征,如边缘、纹理等。

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
  • 参数说明
  • in_channels (int): 输入数据的通道数。例如,对于RGB图像,in_channels 应为 3。
  • out_channels (int): 卷积层输出的通道数(即卷积核的数量)。
  • kernel_size (int or tuple): 卷积核的大小。如果是整数,则表示卷积核是正方形的;如果是元组,则表示卷积核的高度和宽度。
  • stride (int or tuple, 可选): 卷积核的步幅。默认值为 1
  • padding (int, tuple or str, 可选): 输入数据的填充。默认值为 0
  • dilation (int or tuple, 可选): 卷积核元素之间的间距。默认值为 1
  • groups (int, 可选): 控制输入和输出通道的连接。默认值为 1
  • bias (bool, 可选): 如果设置为 True,将会给输出添加一个可学习的偏置。默认值为 True
  • padding_mode (str, 可选): 填充模式。可选值为 ‘zeros’, ‘reflect’, ‘replicate’ 或 ‘circular’。默认值为 ‘zeros’
    输出张量的形状可以通过以下公式计算:
  • input: ( N , C i n , H i n , W i n ) (N,C_{in},H_{in},W_{in}) (N,Cin,Hin,Win)
  • output: ( N , C o u t , H o u t , W o u t ) (N,C_{out},H_{out},W_{out}) (N,Cout,Hout,Wout)
    H o u t = H i n + 2 ∗ p a d d i n g [ 0 ] − d i l a t i o n [ 0 ] ∗ ( k e r n e l _ s i z e [ 0 ] − 1 ) s t r i d e [ 0 ] H_{out}=\frac{H_{in}+2*padding[0]-dilation[0]*(kernel\_{size}[0]-1)}{stride[0]} Hout=stride[0]Hin+2padding[0]dilation[0](kernel_size[0]1)
    W o u t = H i n + 2 ∗ p a d d i n g [ 1 ] − d i l a t i o n [ 1 ] ∗ ( k e r n e l _ s i z e [ 1 ] − 1 ) s t r i d e [ 1 ] W_{out}=\frac{H_{in}+2*padding[1]-dilation[1]*(kernel\_{size}[1]-1)}{stride[1]} Wout=stride[1]Hin+2padding[1]dilation[1](kernel_size[1]1)
import torch
import torch.nn as nn

# 创建一个 Conv2d 对象
conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)

# 打印 Conv2d 对象的参数
print(conv_layer)

# 创建一个随机输入张量,形状为 (batch_size, in_channels, height, width)
input_tensor = torch.randn(1, 3, 32, 32)

# 通过卷积层前向传播输入张量
output_tensor = conv_layer(input_tensor)

# 打印输出张量的形状
print(output_tensor.shape)

在这里插入图片描述
对上述示例输出形状计算:

  • 输入张量形状(1,3,32,32)
  • 卷积核大小为3*3
  • 步幅为1
  • 填充为1
    输出高度
    H o u t = 32 − 2 ∗ 1 + 3 − 1 1 = 32 H_{out}=\frac{32-2*1+3-1}{1}=32 Hout=13221+31=32
    输出宽度
    W o u t = 32 − 2 ∗ 1 + 3 − 1 1 = 32 W_{out}=\frac{32-2*1+3-1}{1}=32 Wout=13221+31=32

2.3.5 stack

torch.stack 是 PyTorch 中的一个函数,用于沿新维度连接一系列张量。它的作用类似于 torch.cat,但不同的是,torch.cat 是在现有维度上进行连接,而 torch.stack 会在指定的维度上插入一个新的维度,然后在这个新维度上进行连接。

torch.stack(tensors, dim=0)

参数

  • tensors (sequence of Tensors): 要连接的张量序列。
  • dim (int): 新插入维度的索引位置。默认值为 0。
Tensor1.shapeTensor2.shapedimout
(3,3)(3,3)0(2,2,3)
(3,3)(3,3)1(3,2,3)
(3,3)(3,3)2(3,3,2)

沿着维度0进行stack

import torch

# 创建两个相同形状的张量
x = torch.arange(9).reshape(3,3)
y = torch.randn(3,3)
# 沿着0维度
z = torch.stack([x,y],0)
z
tensor([[[ 0.0000,  1.0000,  2.0000],
         [ 3.0000,  4.0000,  5.0000],
         [ 6.0000,  7.0000,  8.0000]],

        [[ 0.8259, -1.7941,  0.8862],
         [ 0.6030, -0.7413,  0.7847],
         [-0.0850,  0.7196, -0.7993]]])
z.shape
torch.Size([2, 3, 3])

沿着维度1进行stack

z1 = torch.stack((x,y),1)
z1
tensor([[[ 0.0000,  1.0000,  2.0000],
         [ 0.8259, -1.7941,  0.8862]],

        [[ 3.0000,  4.0000,  5.0000],
         [ 0.6030, -0.7413,  0.7847]],

        [[ 6.0000,  7.0000,  8.0000],
         [-0.0850,  0.7196, -0.7993]]])
z1.shape
torch.Size([3, 2, 3])

沿着维度2进行stack

z2 = torch.stack((x,y),2)
z2
tensor([[[ 0.0000,  0.8259],
         [ 1.0000, -1.7941],
         [ 2.0000,  0.8862]],

        [[ 3.0000,  0.6030],
         [ 4.0000, -0.7413],
         [ 5.0000,  0.7847]],

        [[ 6.0000, -0.0850],
         [ 7.0000,  0.7196],
         [ 8.0000, -0.7993]]])
z2.shape
torch.Size([3, 3, 2])

2.3.6 cat

torch.cat 是 PyTorch 中的一个函数,用于沿已有的维度连接一系列张量。与 torch.stack 不同的是,torch.cat 不会在连接过程中创建新的维度,而是直接在指定的维度上进行连接。

torch.cat(tensors, dim=0)
  • 参数
  • tensors (sequence of Tensors): 要连接的张量序列,这些张量在除 dim 维之外的其他维度上必须具有相同的形状。
  • dim (int): 指定在该维度上连接张量。默认值为 0。
Tensor1.shapeTensor2.shapedimout
(3,3)(3,3)0(6,3)
(3,3)(3,3)1(3,6)

沿着维度0进行cat

c0 = torch.cat((x,y),0)
c0
tensor([[ 0.0000,  1.0000,  2.0000],
        [ 3.0000,  4.0000,  5.0000],
        [ 6.0000,  7.0000,  8.0000],
        [ 0.8259, -1.7941,  0.8862],
        [ 0.6030, -0.7413,  0.7847],
        [-0.0850,  0.7196, -0.7993]])
c0.shape
torch.Size([6, 3])

沿着维度1进行cat

c1 =torch.cat((x,y),1)
c1
tensor([[ 0.0000,  1.0000,  2.0000,  0.8259, -1.7941,  0.8862],
        [ 3.0000,  4.0000,  5.0000,  0.6030, -0.7413,  0.7847],
        [ 6.0000,  7.0000,  8.0000, -0.0850,  0.7196, -0.7993]])
c1.shape
torch.Size([3, 6])

2.3.7 完整代码

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((8,8))
print(comp_conv2d(conv2d, X).shape)

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

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

def corr2d_multi_in(X, K):
    return sum(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]]])
print(corr2d_multi_in(X, K))

def corr2d_multi_in_out(X, K):
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

K = torch.stack((K, K+1, K+2), 0)
print(K.shape)
print(corr2d_multi_in_out(X,K))
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 动手深度学习v2是一本非常好的深度学习教材,是从谷歌机器习研究员李沐所主持的Gluon团队创作的。它提供了丰富的案例和实际应用,深入浅出地介绍了深度学习的基础理论和实践技能。 下载动手深度学习v2非常简单,可以通过访问官方网站来获取。首先,打开谷歌或百度搜索引擎,搜索"动手深度学习v2下载",就可以找到相关的下载链接。建议选择官网下载,因为官网下载最为安全可靠。 进入官网后,点击首页上的"下载"按钮,然后在目录下找到本书的下载链接,下载适合你的版本即可。此外,动手深度学习v2还有在线阅读的版本,方便习者随时随地习。 总的来说,动手深度学习v2是一本非常优秀的深度学习教材,相关下载链接也十分便捷,能够帮助广大习者更好地掌握深度学习相关的知识和技能。 ### 回答2: 动手深度学习v2是一本非常优秀的深度学习入门书籍,笔者十分推荐。如果您想要下载该书籍,可以使用以下方法: 1.进入动手深度学习v2的官网(https://zh.d2l.ai/),点击右上角的“Github”按钮,进入书籍的Github仓库。 2.在仓库中找到“releases”目录,选择最新的版本号,点击进入。 3.在该版本的页面中,找到“Source code (zip)”或“Source code (tar.gz)”选项,点击下载压缩包。 4.下载完成后,解压缩文件即可得到电子书的文件夹,其中包括PDF和HTML格式的书籍。 除此之外,您也可以在该官网中找到由中文社区翻译的在线电子书版本。在该电子书中,您可以直接在线阅读和习。值得注意的是,该书籍的在线翻译版本可能会比英文原版稍有滞后。如果您想要阅读最新的内容,请下载英文原版或者在该官网上查看最新的更新。 ### 回答3: 深度学习是现在的热门话题之一。而动手深度学习v2是一本非常好的深度学习教材,旨在为做实际项目的习者提供知识技能和实战经验。为了下载此书,您需要按照以下步骤进行。 首先,您需要访问动手深度学习官方网站,网址为d2l.ai。然后,您需要找到下载页面,这个页面可以通过页面上的“全书下载”按钮或主页面上的一个标签来访问。 在下载页面,您需要选择您所需要的版本,v2版本是最新版本。接着,您需要选择您所需的格式。您可以选择PDF格式或HTML格式,下方还提供了在线阅读链接。 若您选择了PDF格式,则需要点击下载链接,页面会跳到GitHub仓库中。在GitHub页面,您需要选择ZIP文件并下载。下载完成后,您就可以在本地解压并阅读这本书了。 若您选择了HTML格式,则不需下载,只需点击在线阅读链接即可。页面会跳转到包含书籍所有章节、实例代码、作者笔记等信息的HTML页面,您可以任意阅读或者下载章节(在左侧点击对应章节)。 总之,动手深度学习v2是一本亲身实践的深度学习教材,其深入浅出的讲解以及丰富的实战案例,能够帮助初者快速掌握深度学习这一技术,同时也是深度学习领域专业人士的必备读物。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值