Pytorch:二维卷积及其伴随定义


二维卷积运算是一种在多个领域,特别是在信号处理和图像处理中,非常关键的技术。理解二维卷积的数学原理对于进一步理解相关技术如图像滤波、特征提取等有重要意义。

一、基本定义

二维卷积涉及两个主要的函数:

  1. 输入函数 f ( x , y ) f(x, y) f(x,y),通常是一个图像,其中 x x x y y y 是图像上的像素坐标。
  2. 卷积核(或滤波器) g ( x , y ) g(x, y) g(x,y),它定义了在每个像素位置上如何结合 f ( x , y ) f(x, y) f(x,y) 周围的像素。

1.1、卷积运算

二维卷积操作定义为: ( f ∗ g ) ( i , j ) = ∑ m ∑ n f ( m , n ) ⋅ g ( i − m , j − n ) (f * g)(i, j) = \sum_m \sum_n f(m, n) \cdot g(i - m, j - n) (fg)(i,j)=mnf(m,n)g(im,jn)其中:

  • ( i , j ) (i, j) (i,j) 是输出图像中的坐标。
  • m m m n n n 是遍历整个输入图像 f f f 的索引。
  • f ( m , n ) f(m, n) f(m,n) 是输入图像在位置 ( m , n ) (m, n) (m,n) 的像素值。
  • g ( i − m , j − n ) g(i - m, j - n) g(im,jn) 是卷积核在相对于 ( i , j ) (i, j) (i,j) 的偏移位置 ( m , n ) (m, n) (m,n) 的值。

在深度学习问题中,二维卷积并不需要这样复杂考虑,因为卷积核会通过训练修改参数,卷积核是否翻转并不影响,因此只需要对应位置相乘即可。不过卷积核的定义如此,因此我们在这里初学时,考虑翻转的问题。

1.2、边界效应

在实际应用中,输入图像的边缘处理是卷积运算中一个需要特别注意的问题。由于卷积核可能超出图像边界,通常有几种处理方法:

  1. 扩展边界(比如通过复制边缘像素)。
  2. 填充零(零填充)。
  3. 忽略边界区域,只对图像的内部区域进行卷积,这将导致输出图像比输入图像小。

1.3、例子

这里将通过一个简单的例子来演示二维卷积的基本操作,即使用一个小的卷积核来对一个小的图像进行卷积处理。我们将使用以下输入图像 f f f 和卷积核 g g g

输入图像 f f f
设输入图像为一个 3 × 3 3 \times 3 3×3 矩阵:
f = [ 1 2 3 4 5 6 7 8 9 ] f = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} f= 147258369
卷积核 g g g
设卷积核为一个 2 × 2 2 \times 2 2×2 矩阵:
g = [ 1 0 0 − 1 ] g = \begin{bmatrix} 1& 0 \\ 0 & -1 \end{bmatrix} g=[1001]
卷积操作
进行卷积操作时,先将卷积核进行180°翻转,卷积核 g g g 将会在输入图像 f f f从左到右、从上到下滑动。在每个位置上,卷积核覆盖的图像部分与卷积核对应元素相乘后的结果求和,形成新的图像 h h h 的一个元素。

因为我们使用了 2 × 2 2 \times 2 2×2 的卷积核,所以输出图像 h h h 的大小将是 ( 3 − 2 + 1 ) × ( 3 − 2 + 1 ) = 2 × 2 (3-2+1) \times (3-2+1) = 2 \times 2 (32+1)×(32+1)=2×2,计算如下:

输出图像 h h h

  1. 在位置 (0, 0):
    h ( 0 , 0 ) = 1 ⋅ ( − 1 ) + 2 ⋅ 0 + 4 ⋅ 0 + 5 ⋅ 1 = − 1 + 0 + 0 + 5 = 4 h(0, 0) = 1 \cdot (-1) + 2 \cdot 0 + 4 \cdot 0 + 5 \cdot 1 = -1 + 0 + 0 + 5 = 4 h(0,0)=1(1)+20+40+51=1+0+0+5=4

  2. 在位置 (0, 1):
    h ( 0 , 1 ) = 2 ⋅ ( − 1 ) + 3 ⋅ 0 + 5 ⋅ 0 + 6 ⋅ 1 = − 2 + 0 + 0 + 6 = 4 h(0, 1) = 2 \cdot (-1) + 3 \cdot 0 + 5 \cdot 0 + 6 \cdot 1 = -2 + 0 + 0 + 6 = 4 h(0,1)=2(1)+30+50+61=2+0+0+6=4

  3. 在位置 (1, 0):
    h ( 1 , 0 ) = 4 ⋅ ( − 1 ) + 5 ⋅ 0 + 7 ⋅ 0 + 8 ⋅ 1 = − 4 + 0 + 0 + 8 = 4 h(1, 0) = 4 \cdot (-1) + 5 \cdot 0 + 7 \cdot 0 + 8 \cdot 1 = -4 + 0 + 0 + 8 = 4 h(1,0)=4(1)+50+70+81=4+0+0+8=4

  4. 在位置 (1, 1):
    h ( 1 , 1 ) = 5 ⋅ ( − 1 ) + 6 ⋅ 0 + 8 ⋅ 0 + 9 ⋅ 1 = − 5 + 0 + 0 + 9 = 4 h(1, 1) = 5 \cdot (-1) + 6 \cdot 0 + 8 \cdot 0 + 9 \cdot 1 = -5 + 0 + 0 + 9 = 4 h(1,1)=5(1)+60+80+91=5+0+0+9=4

最终,输出图像 h h h 为:
h = [ 4 4 4 4 ] h = \begin{bmatrix} 4 & 4 \\ 4 & 4 \end{bmatrix} h=[4444]

这个简单的例子说明了卷积如何在图像的不同部分“滑动”卷积核。

二、torch.flip()函数

在PyTorch中,torch.flip 是一个非常有用的函数,用于翻转张量中的一个或多个维度。这可以在进行图像处理或数据增强时特别有用,例如,翻转图像以创建更多训练数据或模拟不同的视角。这里我们主要用来翻转卷积核。

2.1、基本用法

函数 torch.flip 的基本语法是:

torch.flip(input, dims)
  • input: 要翻转的张量。
  • dims: 一个整数列表或元组,指定了要翻转的维度。

2.2、示例

假设我们有一个三维的张量(例如,一个颜色图像,其中维度是通道、高度和宽度),我们可以按照以下方式使用 torch.flip

import torch

# 创建一个示例张量,形状为 [3, 4, 4],模拟一个 4x4 的彩色图像(3个颜色通道)
x = torch.arange(3*4*4).reshape(3, 4, 4)

# 输出原始张量
print("Original Tensor:\n", x)

# 沿宽度(最后一个维度,维度编号为2)翻转图像
flipped_x = torch.flip(x, [2])

# 输出翻转后的张量
print("Flipped Tensor:\n", flipped_x)

这个例子中,我们创建了一个形状为 [3, 4, 4] 的张量,并沿着最后一个维度(宽度)翻转。如果你想沿着高度(第二个维度,维度编号为1)或者同时沿着高度和宽度翻转,你可以相应地调整 dims 参数:

# 沿高度翻转
flipped_y = torch.flip(x, [1])
print("Flipped along height:\n", flipped_y)

# 同时沿高度和宽度翻转
flipped_xy = torch.flip(x, [1, 2])
print("Flipped along both height and width:\n", flipped_xy)

这里说的沿高度和宽度翻转,实际上就是同时进行,图像的顶部和底部交换,并同时将左侧和右侧交换。 因此可以实现180°翻转。

2.3、卷积核翻转

import torch
conv2d_kernel=torch.Tensor([1,2,3])
print(conv2d_kernel.size())
conv2d_kernel_flipped=torch.flip(conv2d_kernel,[0])
conv2d_kernel_flipped
torch.Size([3])
tensor([3., 2., 1.])
import torch
conv2d_kernel=torch.Tensor([[1,2,3],[5,6,7]])
print(conv2d_kernel.size())
conv2d_kernel_flipped=torch.flip(conv2d_kernel,[0,1])
conv2d_kernel_flipped
torch.Size([2, 3])
tensor([[7., 6., 5.],
        [3., 2., 1.]])

三、torch.nn.Conv2d类

torch.nn.Conv2d 是 PyTorch 库中的一个非常重要的类,用于实现二维卷积操作,广泛应用于处理图像数据的卷积神经网络(CNN)中。和一维卷积差不多,二维卷积同样有 先定义torch.nn.Conv2d类再输入图像计算 也有 直接使用torch.nn.functional.conv2d函数计算两种方式。

3.1、构造函数参数说明

torch.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): 输入数据的通道数(对于彩色图像通常是3,灰度图像是1)。
  • out_channels (int): 卷积操作后的输出通道数。这通常对应于卷积核的数量,每个卷积核提取输入数据的一种特定特征。
  • kernel_size (int or tuple): 卷积核的大小。可以是单一整数或一个由两个整数构成的元组(height, width)。
  • stride (int or tuple, optional): 卷积步长,决定卷积核滑动的速度和方式。默认为1。可以是单一整数或一个由两个整数构成的元组。
  • padding (int or tuple, optional): 在输入数据周围填充0的层数,用于控制输出的空间尺寸。默认为0。可以是单一整数或一个由两个整数构成的元组。
  • dilation (int or tuple, optional): 卷积核中元素之间的空间。用于实现空洞卷积(dilated convolution),可以增大感受野。默认为1。
  • groups (int, optional): 将输入通道和输出通道分组,使得每一组使用不同的卷积核。这通常用于实现分组卷积,如在深度可分离卷积中。默认为1。
  • bias (bool, optional): 是否添加偏置项(一个在每个输出通道上加的可学习参数)。默认为True。偏置是一个 C o u t C_{out} Cout通道大小 同维度的张量,输出图像的一个特定通道中的所有元素都会添加上 对应偏置值。

注意:

  • input: 输入张量,形状应为 ( N , C i n , H , W ) (N, C_{in}, H, W) (N,Cin,H,W),其中:
    • N N N是批大小(batch size)
    • C i n C_{in} Cin是通道数(channel number)
    • H H H是图像高度
    • W W W 是图像宽度
  • weight: 卷积核(滤波器)张量,形状应为 ( C o u t , C i n / g r o u p s , k H , k W ) (C_{out}, C_{in}/groups, kH, kW) (Cout,Cin/groups,kH,kW),其中:
    • C o u t C_{out} Cout 是输出通道数
    • k H kH kH 是卷积核的高度
    • k W kW kW 是卷积核的宽度

3.2、示例代码

下面是一个使用 torch.nn.Conv2d 创建卷积层的例子:

import torch
import torch.nn as nn

# 创建一个卷积层
# 输入通道数为 3(彩色图像),输出通道数为 16,卷积核大小为 5x5
# 类对象的初始化
conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=5, stride=1, padding=2, bias=True)

# 假设有一个随机初始化的图像批量,批大小为 10,图像尺寸为 32x32
input_images = torch.randn(10, 3, 32, 32)

# 应用卷积层
output_features = conv_layer(input_images)

# 查看输出特征的形状
print("Output features shape:", output_features.shape)
print("卷积核形状:",conv_layer.weight.shape)

在这个例子中,输入是一个形状为 (10, 3, 32, 32) 的张量,表示有10个32x32像素的彩色图像。经过卷积层处理后,输出的形状为 (10, 16, 32, 32),表示每个图像现在被转换成了16个32x32的特征映射。
卷积核形状为torch.Size([16, 3, 5, 5])

相关推荐

  1. Pytorch及其伴随定义

    2024-04-15 09:38:05       157 阅读
  2. Pytorch:一及其伴随定义

    2024-04-15 09:38:05       32 阅读
  3. numpy矩阵做

    2024-04-15 09:38:05       45 阅读
  4. pytorch学习()、网络的构建和

    2024-04-15 09:38:05       71 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-15 09:38:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-15 09:38:05       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-15 09:38:05       82 阅读
  4. Python语言-面向对象

    2024-04-15 09:38:05       91 阅读

热门阅读

  1. SpringBoot中的常见注解详细介绍,附带代码示例

    2024-04-15 09:38:05       32 阅读
  2. 神经网络模型底层原理与实现10-softmax的实现

    2024-04-15 09:38:05       134 阅读
  3. PyQt5

    PyQt5

    2024-04-15 09:38:05      108 阅读
  4. 如何防御局域网的网络攻击

    2024-04-15 09:38:05       117 阅读
  5. LeetCode 1.两数之和

    2024-04-15 09:38:05       84 阅读
  6. Fortinet年度重磅发布 ,FortiOS 7.6高能登场

    2024-04-15 09:38:05       47 阅读
  7. @CrossOrigin注解解决跨域问题

    2024-04-15 09:38:05       40 阅读
  8. LeetCode 128.最长连续数列

    2024-04-15 09:38:05       41 阅读
  9. UE C++ 知识杂记

    2024-04-15 09:38:05       38 阅读