前言
在深度学习的领域中,卷积操作无疑是一项至关重要的技术。这项技术的应用不仅限于计算机视觉,还渗透到自然语言处理、音频处理等多个领域。如果对卷积操作感到好奇,但又觉得深入学习似乎有些门槛,那么这里正是起点。
本文我们将快速踏入卷积操作的世界,探讨卷积的基础知识。我们将深入了解一维、二维卷积以及一些高级操作,同时通过实际案例和代码演示,快速理解和运用这一强大的技术,不再让卷积成为深水区。
一、卷积的基本概念
卷积操作是深度学习领域中不可或缺的核心概念之一。在我们深入了解各种卷积操作之前,让我们先回顾一下基础知识,为后续的探讨打下坚实的基础。
1.1 卷积的基本概念
卷积是一种数学运算,它通过在输入数据上滑动一个卷积核(filter
)来提取特征。卷积核是一个小的矩阵,它包含了一组可学习的权重。在卷积操作中,卷积核的每个元素与输入数据(input
)对应位置的元素相乘,然后将所有乘积的结果相加,得到输出的一个元素。通过在整个输入数据上移动卷积核,我们可以生成一个输出特征图(feature map
)。
1.2 卷积核、步幅和填充
卷积核(Kernel): 这是卷积操作的关键组成部分,用于提取输入数据的特征。不同的卷积核可以捕捉不同的特征,如边缘、纹理等。
步幅(Stride): 步幅定义了卷积核在输入数据上滑动的步长。调整步幅可以影响输出特征图的大小。
填充(Padding): 填充是在输入数据的边缘添加额外的值,以防止卷积操作导致输出特征图尺寸过小。填充有助于保持输入输出大小的一致性。
1.2.1 卷积核(Kernel)和滤波器(Filter)
提取数据的精华
卷积核,有时也称为滤波器,是卷积操作的核心。它类似于一把特殊设计的“窗户”,通过在输入数据上滑动并捕捉不同位置的特征,实现对数据信息的提取。卷积核的设计直接影响到模型学习到的特征,例如边缘、纹理或更高层次的抽象特征。
与之相对,滤波器是卷积核的一个术语,通常用于描述卷积操作中的权重矩阵。因此,当我们讨论卷积核时,我们实际上是在谈论模型通过滤波器学习到的特征提取方式。
1.2.2 步幅(Stride)
调整视野,影响特征图的尺寸
步幅是卷积核在输入数据上滑动的步长。通过调整步幅,我们可以控制卷积核在输入数据上的移动速度,进而影响输出特征图的尺寸。较大的步幅可以减小输出特征图的尺寸,而较小的步幅则会保持更多的信息,产生更大尺寸的输出特征图。在实际应用中,通过调整步幅,我们可以平衡计算效率和特征表达的抽象程度。
1.2.3 填充(Padding)
保持大小一致,防止信息丢失
填充是在输入数据的边缘添加额外的值,以防止卷积操作导致输出特征图尺寸过小。当卷积核在输入数据边缘处移动时,如果没有填充,可能会导致信息的丢失。填充的引入有助于保持输入输出大小的一致性,特别是在多层卷积操作中,以确保模型能够捕捉到更全局和丰富的特征。
卷积核、步幅和填充是卷积操作中三个关键的超参数,它们共同影响着模型对输入数据的理解和特征的提取。在实践中,灵活地调整这些参数,结合具体任务的需求,是构建高效卷积神经网络的关键一步。
1.3 通道(Channels)
在深度学习中,我们经常会处理具有多个通道的数据。通道是数据的另一维度,通常表示不同的特征或信息。对于图像数据来说,通道可以理解为颜色通道(例如,RGB图像有三个通道),对于其他类型的数据,通道可以表示不同的特征维度。
卷积操作可以同时作用于数据的每个通道。对于具有多个通道的输入数据和卷积核,每个通道都有一个对应的卷积核,它们分别对应相同位置的数据进行卷积操作。卷积操作的结果是对各个通道的卷积结果按通道进行叠加,形成最终的输出。
通道的引入使得卷积神经网络能够更有效地学习多层次的特征表示,从而提高模型的表达能力。在卷积神经网络的每一层,不同通道的卷积核可以学习捕捉不同抽象层次的特征,从边缘、纹理到更高级的语义特征。
因此,卷积操作中的卷积核不仅在空间上滑动,还在通道上进行操作,这为深度学习模型提供了更大的灵活性和表达能力。
1.4 维度(Dimensions)
在深度学习中,维度是指数据的属性或特征的个数,也可以理解为数据的形状。在卷积神经网络中,我们通常会处理具有多个维度的数据,例如一张彩色图像数据具有高度、宽度和通道三个维度。
1.4.1 二维数据的维度
灰度图像一般只有两个维度。
- 高度(Height): 表示图像数据沿垂直方向的像素个数。
- 宽度(Width): 表示图像数据沿水平方向的像素个数。
可以用以下形式表示:
数据维度
=
高度
×
宽度
=
Height
×
Width
\begin{aligned} \text{数据维度} &= \text{高度} \times \text{宽度} \\ &= \text{Height} \times \text{Width} \end{aligned}
数据维度=高度×宽度=Height×Width
1.4.2 三维数据的维度
一张彩色图像都是一个具有高度、宽度和通道的三维数据。
- 高度(Height): 表示图像数据沿垂直方向的像素个数。
- 宽度(Width): 表示图像数据沿水平方向的像素个数。
- 通道(Channels): 表示图像数据的颜色通道个数,例如,对于RGB图像,通道数为3。
可以用以下形式表示:
数据维度
=
高度
×
宽度
×
通道
=
Height
×
Width
×
Channels
\begin{aligned} \text{数据维度} &= \text{高度} \times \text{宽度} \times \text{通道} \\ &= \text{Height} \times \text{Width} \times \text{Channels} \end{aligned}
数据维度=高度×宽度×通道=Height×Width×Channels
1.4.3 四维数据的维度
对于深度学习任务中的四维数据,通常用于表示序列数据或视频数据,其维度包括样本数、时间步(序列长度)、高度、宽度以及通道。具体而言:
- 样本数(Batch Size): 表示数据集中包含的样本个数。
- 时间步(Time Steps): 表示序列数据中的时间步或视频中的帧数。
- 高度(Height): 表示图像数据沿垂直方向的像素个数。
- 宽度(Width): 表示图像数据沿水平方向的像素个数。
- 通道(Channels): 表示图像数据的颜色通道个数,例如,对于RGB图像,通道数为3。
对于一个具有样本数、时间步、高度、宽度和通道的四维数据,可以用以下形式表示:
数据维度
=
样本数
×
时间步
×
高度
×
宽度
×
通道
=
Batch Size
×
Time Steps
×
Height
×
Width
×
Channels
\begin{aligned} \text{数据维度} &= \text{样本数} \times \text{时间步} \times \text{高度} \times \text{宽度} \times \text{通道} \\ &= \text{Batch Size} \times \text{Time Steps} \times \text{Height} \times \text{Width} \times \text{Channels} \end{aligned}
数据维度=样本数×时间步×高度×宽度×通道=Batch Size×Time Steps×Height×Width×Channels
1.4.4 样本的维度
在深度学习中,我们经常处理的是具有多个样本的数据集,每个样本可以是一个具有多个维度的数据。例如,一个包含多张图像的数据集,每张图像都是一个具有高度、宽度和通道的三维数据。
- 样本数(Batch Size): 表示数据集中包含的样本个数。
对于一个具有样本数、高度、宽度和通道的三维数据,可以用以下形式表示:
数据维度
=
样本数
×
高度
×
宽度
×
通道
=
Batch Size
×
Height
×
Width
×
Channels
\begin{aligned} \text{数据维度} &= \text{样本数} \times \text{高度} \times \text{宽度} \times \text{通道} \\ &= \text{Batch Size} \times \text{Height} \times \text{Width} \times \text{Channels} \end{aligned}
数据维度=样本数×高度×宽度×通道=Batch Size×Height×Width×Channels
1.4.5 卷积操作中的维度
在卷积神经网络中,卷积操作涉及到输入数据、卷积核和输出特征图。这三者之间的维度关系需要满足一定规则,以确保卷积操作能够正确进行。
- 输入数据维度: 样本数 × 输入高度 × 输入宽度 × 输入通道 Batch Size × Input Height × Input Width × Input Channels \text{样本数} \times \text{输入高度} \times \text{输入宽度} \times \text{输入通道}\\ \text{Batch Size} \times \text{Input Height} \times \text{Input Width} \times \text{Input Channels} 样本数×输入高度×输入宽度×输入通道Batch Size×Input Height×Input Width×Input Channels
- 卷积核维度: 卷积核高度 × 卷积核宽度 × 输入通道 × 输出通道 Kernel Height × Kernel Width × Input Channels × Output Channels \text{卷积核高度} \times \text{卷积核宽度} \times \text{输入通道} \times \text{输出通道}\\\text{Kernel Height} \times \text{Kernel Width} \times \text{Input Channels} \times \text{Output Channels} 卷积核高度×卷积核宽度×输入通道×输出通道Kernel Height×Kernel Width×Input Channels×Output Channels
- 输出特征图维度: 样本数 × 输出高度 × 输出宽度 × 输出通道 Batch Size × Output Height × Output Width × Output Channels \text{样本数} \times \text{输出高度} \times \text{输出宽度} \times \text{输出通道}\\\text{Batch Size} \times \text{Output Height} \times \text{Output Width} \times \text{Output Channels} 样本数×输出高度×输出宽度×输出通道Batch Size×Output Height×Output Width×Output Channels
1.4.6 池化操作中的维度
在池化操作中,通常会涉及输入数据和输出数据的维度。池化操作并不改变通道数,只会对高度和宽度进行降采样。
- 输入数据维度: 样本数 × 输入高度 × 输入宽度 × 输入通道 Batch Size × Input Height × Input Width × Input Channels \text{样本数} \times \text{输入高度} \times \text{输入宽度} \times \text{输入通道}\\ \text{Batch Size} \times \text{Input Height} \times \text{Input Width} \times \text{Input Channels} 样本数×输入高度×输入宽度×输入通道Batch Size×Input Height×Input Width×Input Channels
- 输出数据维度: 样本数 × 输出高度 × 输出宽度 × 输入通道 Batch Size × Output Height × Output Width × Input Channels \text{样本数} \times \text{输出高度} \times \text{输出宽度} \times \text{输入通道}\\ \text{Batch Size} \times \text{Output Height} \times \text{Output Width} \times \text{Input Channels} 样本数×输出高度×输出宽度×输入通道Batch Size×Output Height×Output Width×Input Channels
在理解卷积神经网络的维度变换时,注意这些维度的变化对于网络的架构设计和调整非常关键。在构建模型时,确保不同层次之间的维度匹配是保证模型正常工作的关键一步。
1.5 常见用途
卷积是深度学习中一种关键的操作,它在图像处理、自然语言处理等领域起到了重要作用。
图像处理:在图像处理中,卷积可用于边缘检测、图像模糊等任务。通过不同设计的卷积核,可以提取图像中的各种特征。
计算机视觉:在计算机视觉任务中,卷积在卷积神经网络(CNN)中得到了广泛应用。通过卷积层,CNN可以自动提取图像中的高级特征,实现图像分类、目标检测等任务。
自然语言处理:在自然语言处理中,卷积可以用于文本分类、情感分析等任务。通过卷积操作,模型可以捕捉文本中的局部特征,识别关键的语义信息。
二、常见的卷积操作
在这一章节,我们将深入探讨常见的卷积操作,包括概念定义、基本原理和公式计算、应用场景,并通过Python和TensorFlow提供实际案例来加深理解。
2.1 一维卷积
2.1.1 概念定义
一维卷积是卷积操作在处理序列数据时的应用,它通过在输入序列上滑动一维卷积核,提取序列中的局部特征。卷积核的每个元素与输入序列对应位置的元素相乘,然后将结果相加,生成输出序列。
2.1.2 基本原理和公式计算
一维卷积的基本原理是通过卷积核在输入序列上滑动,逐步提取局部特征。一维卷积的计算公式如下:
Y
(
i
)
=
∑
m
X
(
i
+
m
)
⋅
K
(
m
)
Y(i) = \sum_{m} X(i+m) \cdot K(m)
Y(i)=m∑X(i+m)⋅K(m)
其中,
Y
(
i
)
Y(i)
Y(i)表示输出序列的一个元素,
X
(
i
+
m
)
X(i+m)
X(i+m)表示输入序列的一个元素,
K
(
m
)
K(m)
K(m)表示一维卷积核的一个元素。
在一维卷积中,使用Padding
可以调整输出序列的长度,以保持输入和输出的大小关系。Padding
是在输入序列的两端添加零值,以便更好地处理边缘信息。一般来说,如果输入序列长度为
N
N
N,卷积核的长度为
K
K
K,填充的大小为
P
P
P,那么输出序列的长度为
N
out
N_{\text{out}}
Nout 可以通过以下公式计算:
N
out
=
N
+
2
P
−
K
+
1
N_{\text{out}} = N + 2P - K + 1
Nout=N+2P−K+1
其中,
N
out
N_{\text{out}}
Nout 是输出序列的长度,
N
N
N 是输入序列的长度,
K
K
K 是卷积核的长度,
P
P
P 是Padding
的大小。这个公式确保了卷积核在输入序列上滑动时,能够覆盖整个输入序列,而不会超出序列的边界。
在实际计算中,需要考虑Padding
的影响,确保卷积核在输入序列上的滑动能够正确计算输出序列。
2.1.3 应用场景
一维卷积在自然语言处理中的文本分类、音频处理中的声谱图特征提取等任务中得到了广泛应用。它能有效捕捉序列中的局部模式,为模型提供丰富的信息。
2.1.4 Python源码实现
让我们通过简单的Python代码来实现一维卷积操作。假设我们有一个输入序列 input_sequence
和一个一维卷积核 kernel
:
import numpy as np
def one_dimensional_convolution(input_sequence, kernel):
input_len = len(input_sequence)
kernel_len = len(kernel)
output_len = input_len - kernel_len + 1
output_sequence = np.zeros(output_len)
for i in range(output_len):
output_sequence[i] = np.sum(input_sequence[i:i+kernel_len] * kernel)
return output_sequence
# 示例
input_sequence = np.array([1, 2, 1, 2, 1])
kernel = np.array([1, 0, -1])
output_sequence = one_dimensional_convolution(input_sequence, kernel)
print("Input Sequence:", input_sequence)
print("Kernel:", kernel)
print("Output Sequence after 1D Convolution:", output_sequence)
运行结果:
Input Sequence: [1 2 1 2 1]
Kernel: [ 1 0 -1]
Output Sequence after 1D Convolution: [0. 0. 0.]
2.1.5 TensorFlow案例
在TensorFlow中,我们可以使用 tf.nn.conv1d
函数来实现一维卷积。以下是一个简单的例子:
import tensorflow as tf
# 示例
input_sequence = tf.constant([1.0, 2.0, 1.0, 2.0, 1.0], dtype=tf.float32)
kernel = tf.constant([1.0, 0.0, -1.0], dtype=tf.float32)
output_sequence = tf.nn.conv1d(tf.reshape(input_sequence, (1, -1, 1)), tf.reshape(kernel, (-1, 1, 1)), stride=1, padding='VALID')
output_sequence = tf.reshape(output_sequence, (-1,))
print("Input Sequence:", input_sequence.numpy())
print("Kernel:", kernel.numpy())
print("Output Sequence after 1D Convolution:", output_sequence.numpy())
运行结果:
Input Sequence: [1. 2. 1. 2. 1.]
Kernel: [ 1. 0. -1.]
Output Sequence after 1D Convolution: [0. 0. 0.]
2.1.6 计算例题
(
1
)
\pmb{(1)}
(1)假设有一个长度为5的输入序列 [1, 2, 3, 4, 5]
和一个一维卷积核 [1, -1, 1]
,在不使用Padding
的情况下,请计算一维卷积的输出序列。
手算过程:
将卷积核放在输入序列上,从左到右滑动,逐步计算输出序列。
对于第一个位置(i=0):
1 × 1 + 2 × ( − 1 ) + 3 × 1 = 2 1 \times 1 + 2 \times (-1) + 3 \times 1 = 2 1×1+2×(−1)+3×1=2对于第二个位置(i=1):
2 × 1 + 3 × ( − 1 ) + 4 × 1 = 3 2 \times 1 + 3 \times (-1) + 4 \times 1 = 3 2×1+3×(−1)+4×1=3对于第三个位置(i=2):
3 × 1 + 4 × ( − 1 ) + 5 × 1 = 4 3 \times 1 + 4 \times (-1) + 5 \times 1 = 4 3×1+4×(−1)+5×1=4
因此,得到一维卷积的输出序列为 [2, 3, 4]
。
(
2
)
\pmb{(2)}
(2)对于左右各填充一个0
的情况下,请计算一维卷积的输出序列。
当使用padding的情况下,我们在输入序列两端各填充零,即
[
0
,
1
,
2
,
3
,
4
,
5
,
0
]
[0, 1, 2, 3, 4, 5, 0]
[0,1,2,3,4,5,0]。
手算过程:
将卷积核放在输入序列上,从左到右滑动,逐步计算输出序列。
对于第一个位置(i=0):
0 × 1 + 1 × ( − 1 ) + 2 × 1 = 1 0 \times 1 + 1 \times (-1) + 2 \times 1 = 1 0×1+1×(−1)+2×1=1对于第二个位置(i=1):
1 × 1 + 2 × ( − 1 ) + 3 × 1 = 2 1 \times 1 + 2 \times (-1) + 3 \times 1 = 2 1×1+2×(−1)+3×1=2对于第三个位置(i=2):
2 × 1 + 3 × ( − 1 ) + 4 × 1 = 3 2 \times 1 + 3 \times (-1) + 4 \times 1 = 3 2×1+3×(−1)+4×1=3对于第四个位置(i=3):
3 × 1 + 4 × ( − 1 ) + 5 × 1 = 4 3 \times 1 + 4 \times (-1) + 5 \times 1 = 4 3×1+4×(−1)+5×1=4对于第五个位置(i=4):
4 × 1 + 5 × ( − 1 ) + 0 × 1 = − 1 4 \times 1 + 5 \times (-1) + 0 \times 1 = -1 4×1+5×(−1)+0×1=−1
因此,得到一维卷积的输出序列为 [1, 2, 3, 4, -1]
。
2.2 二维卷积
2.2.1 概念定义
二维卷积是卷积操作在二维数据(如图像)上的应用。它通过在输入数据上滑动二维卷积核,逐步提取局部特征。每个卷积核的元素与输入图像对应位置的元素相乘,然后将结果相加,生成输出特征图。
2.2.2 基本原理和公式计算
2.2.2.1 基本原理
假设输入图像为
X
X
X,卷积核为
K
K
K,输出特征图为
Y
Y
Y,则二维卷积的计算公式为:
Y
(
i
,
j
)
=
∑
m
∑
n
X
(
i
+
m
,
j
+
n
)
⋅
K
(
m
,
n
)
Y(i, j) = \sum_{m}\sum_{n} X(i+m, j+n) \cdot K(m, n)
Y(i,j)=m∑n∑X(i+m,j+n)⋅K(m,n)
2.2.2.2 输出特征图尺寸
输入特征图尺寸为 H in × W in H_{\text{in}} \times W_{\text{in}} Hin×Win,卷积核尺寸为 K × K K \times K K×K,步幅为 S S S,填充为 P P P。输出特征图的尺寸可以通过以下公式计算:
H out = H in − K + 2 P S + 1 H_{\text{out}} = \frac{{H_{\text{in}} - K + 2P}}{S} + 1 Hout=SHin−K+2P+1
W out = W in − K + 2 P S + 1 W_{\text{out}} = \frac{{W_{\text{in}} - K + 2P}}{S} + 1 Wout=SWin−K+2P+1
这里, H out H_{\text{out}} Hout 和 W out W_{\text{out}} Wout 分别表示输出特征图的高度和宽度。
2.2.2.3 参数量的计算
参数量(Params)是指模型中需要学习的参数的总数。对于二维卷积来说,参数量主要包括卷积核的权重和一个偏置项(bias)。其计算公式为:
Params = C in × C out × K × K + C out \text{Params} = C_{\text{in}} \times C_{\text{out}} \times K \times K + C_{\text{out}} Params=Cin×Cout×K×K+Cout
其中,
- C in C_{\text{in}} Cin 表示输入通道数,
- C out C_{\text{out}} Cout 表示输出通道数,
- K × K K \times K K×K 表示卷积核的尺寸,
- C out C_{\text{out}} Cout 表示输出通道数,
- + C out +C_{\text{out}} +Cout 表示偏置项。
2.2.2.4 计算量的估算
计算量(FLOPs,即浮点运算数)表示在模型的前向传播过程中进行的总浮点运算次数。对于二维卷积,计算量的估算公式为:
FLOPs = C in × C out × K × K × H out × W out \text{FLOPs} = C_{\text{in}} \times C_{\text{out}} \times K \times K \times H_{\text{out}} \times W_{\text{out}} FLOPs=Cin×Cout×K×K×Hout×Wout
其中,
- C in C_{\text{in}} Cin 表示输入通道数,
- C out C_{\text{out}} Cout 表示输出通道数,
- K × K K \times K K×K 表示卷积核的尺寸,
- H out H_{\text{out}} Hout 和 W out W_{\text{out}} Wout 表示输出特征图的高度和宽度。
2.2.3 应用场景
二维卷积广泛应用于图像处理、计算机视觉等领域。它能够有效提取图像中的各种特征,如边缘、纹理、物体等,为模型提供更丰富的信息。
2.2.4 Python源码实现
让我们通过Python代码来实现二维卷积操作。假设有一个简单的灰度图像和一个卷积核:
import numpy as np
def convolution2d(input_image, kernel):
# 获取输入图像和卷积核的尺寸
input_height, input_width = input_image.shape
kernel_height, kernel_width = kernel.shape
# 计算输出特征图的尺寸
output_height = input_height - kernel_height + 1
output_width = input_width - kernel_width + 1
# 初始化输出特征图
output_image = np.zeros((output_height, output_width))
# 进行二维卷积操作
for i in range(output_height):
for j in range(output_width):
output_image[i, j] = np.sum(input_image[i:i + kernel_height, j:j + kernel_width] * kernel)
return output_image
# 示例
input_image = np.array([[1, 2, 1],
[4, 5, 4],
[7, 8, 7]])
kernel = np.array([[1, 0],
[0, -1]])
output_image = convolution2d(input_image, kernel)
print("Input Image:\n", input_image)
print("\nKernel:\n", kernel)
print("\nOutput Image after 2D Convolution:\n", output_image)
运行结果:
Input Image:
[[1 2 1]
[4 5 4]
[7 8 7]]
Kernel:
[[ 1 0]
[ 0 -1]]
Output Image after 2D Convolution:
[[-4. -2.]
[-4. -2.]]
2.2.5 TensorFlow案例
在TensorFlow中,我们可以使用 tf.nn.conv2d
函数来实现二维卷积。以下是一个简单的例子:
import tensorflow as tf
import numpy as np
# 定义输入图像和卷积核
input_image = tf.constant([[[1.0, 2.0, 1.0],
[4.0, 5.0, 4.0],
[7.0, 8.0, 7.0]]], shape=[1, 3, 3, 1], dtype=tf.float32)
kernel = tf.constant([[[1.0, 0.0],
[0.0, -1.0]]], shape=[2, 2, 1, 1], dtype=tf.float32)
# 进行二维卷积操作
output_image = tf.nn.conv2d(input_image, kernel, strides=[1, 1, 1, 1], padding='VALID')
# 输入图像、卷积核和输出图像的值
input_image_vals = input_image.numpy().squeeze()
kernel_vals = kernel.numpy().squeeze()
output_image_vals = output_image.numpy().squeeze()
# 打印输入图像、卷积核和输出图像
print("Input Image:\n", np.array2string(input_image_vals, precision=2, separator=', ', suppress_small=True))
print("\nKernel:\n", np.array2string(kernel_vals, precision=2, separator=', ', suppress_small=True))
print("\nOutput Image after 2D Convolution:\n", np.array2string(output_image_vals, precision=2, separator=', ', suppress_small=True))
运行结果:
Input Image:
[[1., 2., 1.],
[4., 5., 4.],
[7., 8., 7.]]
Kernel:
[[ 1., 0.],
[ 0., -1.]]
Output Image after 2D Convolution:
[[-4., -2.],
[-4., -2.]]
2.2.6 计算例题
(
1
)
\pmb{(1)}
(1) 假设有输入图像:
[
1
2
3
4
5
6
7
8
9
]
\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{bmatrix}
147258369
卷积核:
[
1
0
−
1
1
]
\begin{bmatrix} 1 & 0 \\ -1 & 1 \\ \end{bmatrix}
[1−101]
对于不使用 Padding,步长为1 的情况,输出图像计算计算过程如下:
对于第一个位置(i=0, j=0): 1 × 1 + 2 × 0 + 4 × ( − 1 ) + 5 × 1 = 2 1 \times 1 + 2 \times 0 + 4 \times (-1) + 5 \times 1 = 2 1×1+2×0+4×(−1)+5×1=2
对于第一个位置(i=0, j=1): 2 × 1 + 3 × 0 + 5 × ( − 1 ) + 6 × 1 = 3 2 \times 1 + 3 \times 0 + 5 \times (-1) + 6 \times 1 = 3 2×1+3×0+5×(−1)+6×1=3
对于第一个位置(i=1, j=0): 4 × 1 + 5 × 0 + 7 × ( − 1 ) + 8 × 1 = 5 4 \times 1 + 5 \times 0 + 7 \times (-1) + 8 \times 1 = 5 4×1+5×0+7×(−1)+8×1=5
对于第一个位置(i=1, j=1): 5 × 1 + 6 × 0 + 8 × ( − 1 ) + 9 × 1 = 6 5 \times 1 + 6 \times 0 + 8 \times (-1) + 9 \times 1 = 6 5×1+6×0+8×(−1)+9×1=6
因此,不使用 padding 的情况下,二维卷积的输出图像为:
[
2
3
5
6
]
\begin{bmatrix} 2 & 3 \\ 5 & 6 \\ \end{bmatrix}
[2536]
( 2 ) \pmb{(2)} (2) 在上述输入图像和卷积核的基础上,将输入图像的周围填充一圈零,步长为1的情况下。新的输入图像如下:
[ 0 0 0 0 0 0 1 2 3 0 0 4 5 6 0 0 7 8 9 0 0 0 0 0 0 ] \begin{bmatrix} 0 & 0 & 0 & 0 & 0\\ 0 & 1 & 2 & 3 & 0\\ 0 & 4 & 5 & 6 & 0\\ 0 & 7 & 8 & 9 & 0\\ 0 & 0 & 0 & 0 & 0\\ \end{bmatrix} 0000001470025800369000000
使用与第一部分相同的卷积操作进行计算,二维卷积的输出图像为:
[
1
1
1
−
3
4
2
3
−
3
7
5
6
−
3
0
7
8
9
]
\begin{bmatrix} 1 & 1 & 1 & -3\\ 4 & 2 & 3 & -3\\ 7 & 5 & 6 & -3\\ 0 & 7 & 8 & 9\\ \end{bmatrix}
147012571368−3−3−39
(
3
)
\pmb{(3)}
(3) 如何保持输入和输出的尺寸相同?
已知
H
out
=
H
in
=
4
,
K
=
2
,
S
=
1
H_{\text{out}}= H_{\text{in}}=4, K=2, S=1
Hout=Hin=4,K=2,S=1,根据:
H
out
=
H
in
−
K
+
2
P
S
+
1
H_{\text{out}} = \frac{{H_{\text{in}} - K + 2P}}{S} + 1
Hout=SHin−K+2P+1
得:
P
=
0.5
P=0.5
P=0.5。这意味着只能加一半的填充,新的输入图像如下:
[
1
2
3
0
4
5
6
0
7
8
9
0
0
0
0
0
]
\begin{bmatrix} 1 & 2 & 3 & 0\\ 4 & 5 & 6 & 0\\ 7 & 8 & 9 & 0\\ 0 & 0 & 0 & 0\\ \end{bmatrix}
1470258036900000
使用与第一部分相同的卷积操作进行计算,二维卷积的输出图像为:
[
2
3
−
3
5
6
−
3
7
8
9
]
\begin{bmatrix} 2 & 3 & -3\\ 5 & 6 & -3\\ 7 & 8 & 9\\ \end{bmatrix}
257368−3−39
2.3 深度可分离卷积
2.3.1 概念定义
深度可分离卷积是一种卷积神经网络中的卷积操作,它将标准的卷积分解为两个步骤:深度卷积和逐点卷积。
深度可分离卷积的好处在于显著减少了参数数量,因为深度卷积阶段的卷积核是通道独立的,逐点卷积则对通道进行组合,提高了计算效率。这种结构在轻量化模型设计、移动设备和嵌入式系统等场景中具有重要的应用价值。
2.3.2 基本原理和公式计算
2.3.2.1 基本原理
-
深度卷积(Depthwise Convolution)
在深度卷积中,对输入的每个通道使用单独的卷积核进行卷积操作。具体来说,如果输入数据有 D D D 个通道,那么就会有 D D D 个卷积核,每个卷积核只与输入的对应通道进行卷积。这样产生的输出包含了每个输入通道的卷积结果,形成了多个通道的特征图。
深度卷积的输出计算方式如下:
输出 ( i , j , k ) = ∑ d = 1 D 输入 ( i , j , d ) × 卷积核 ( k ) \text{输出}(i, j, k) = \sum_{d=1}^{D} \text{输入}(i, j, d) \times \text{卷积核}(k) 输出(i,j,k)=∑d=1D输入(i,j,d)×卷积核(k)
其中, ( i , j ) (i, j) (i,j) 表示输出特征图的位置, D D D 表示输入通道数, k k k 表示输出通道数。 -
逐点卷积(Pointwise Convolution)
逐点卷积是使用 1 × 1 1 \times 1 1×1 的卷积核对深度卷积的输出进行卷积。这相当于在通道维度上进行全连接的卷积操作。逐点卷积的作用是将深度卷积的输出进行非线性映射和通道的组合,从而得到最终的输出特征图。
逐点卷积的输出计算方式如下:
输出 ( i , j , m ) = ∑ k = 1 K 深度卷积输出 ( i , j , k ) × 卷积核 ( m , k ) \text{输出}(i, j, m) = \sum_{k=1}^{K} \text{深度卷积输出}(i, j, k) \times \text{卷积核}(m, k) 输出(i,j,m)=∑k=1K深度卷积输出(i,j,k)×卷积核(m,k)
其中, ( i , j ) (i, j) (i,j) 表示输出特征图的位置, K K K 表示深度卷积的输出通道数, m m m 表示逐点卷积的输出通道数。
2.3.2.2 输出特征图尺寸
深度可分离卷积的输出特征图尺寸计算公式与标准卷积相同,取决于输入特征图尺寸、卷积核大小、步幅和填充。
2.3.2.3 参数量的计算
深度可分离卷积的参数量计算分为两个部分:深度卷积的参数和逐点卷积的参数。
-
深度卷积的参数量为: D × K × K × M D \times K \times K \times M D×K×K×M,其中 D D D 为输入通道数, K × K K \times K K×K为深度卷积核大小, M M M 为输出通道数。
-
逐点卷积的参数量为: M × N M \times N M×N,其中 , M M M 为一次逐点卷积的参数量, N N N 为逐点卷积核大小。
深度可分离卷积的总参数量为深度卷积阶段和逐点卷积阶段的参数量之和:
总参数量 = 深度卷积参数量 + 逐点卷积参数量 \text{总参数量} = \text{深度卷积参数量} + \text{逐点卷积参数量} 总参数量=深度卷积参数量+逐点卷积参数量
总参数量 = D × K × K × M + M × N \text{总参数量} = D \times K \times K \times M + M \times N 总参数量=D×K×K×M+M×N
这里, D D D 是输入通道数, K K K 是深度卷积核大小, M M M 是深度卷积阶段的输出通道数, N N N 是逐点卷积阶段的输出通道数。
总的来说,深度可分离卷积通过减少深度卷积阶段的参数数量,从而大幅度减小了总的参数量,适用于轻量化模型设计和移动端部署。
2.3.2.4 计算量的估算
深度可分离卷积的计算量估算也包括深度卷积阶段和逐点卷积阶段的计算量。
-
深度卷积阶段的计算量估算:深度卷积阶段的计算量取决于输入特征图的大小、深度卷积核的大小、深度卷积阶段的输出通道数。假设输入特征图的大小为 H × W H \times W H×W,深度卷积核大小为 K × K K \times K K×K,深度卷积阶段的输出通道数为 M M M,则深度卷积阶段的计算量估算如下:
深度卷积计算量 = H × W × K × K × M \text{深度卷积计算量} = H \times W \times K \times K \times M 深度卷积计算量=H×W×K×K×M -
逐点卷积阶段的计算量估算:逐点卷积阶段的计算量取决于深度卷积阶段的输出通道数、逐点卷积的输出通道数。假设深度卷积阶段的输出通道数为 M M M,逐点卷积的输出通道数为 N N N,则逐点卷积阶段的计算量估算如下:
逐点卷积计算量 = H × W × M × N \text{逐点卷积计算量} = H \times W \times M \times N 逐点卷积计算量=H×W×M×N
深度可分离卷积的总计算量为深度卷积阶段和逐点卷积阶段的计算量之和:
总计算量 = 深度卷积计算量 + 逐点卷积计算量 \text{总计算量} = \text{深度卷积计算量} + \text{逐点卷积计算量} 总计算量=深度卷积计算量+逐点卷积计算量
总计算量 = H × W × K × K × M + H × W × M × N \text{总计算量} = H \times W \times K \times K \times M + H \times W \times M \times N 总计算量=H×W×K×K×M+H×W×M×N
这里, H H H 和 W W W 分别是输入特征图的高度和宽度, K K K 是深度卷积核大小, M M M 是深度卷积阶段的输出通道数, N N N 是逐点卷积阶段的输出通道数。
2.3.3 应用场景
深度可分离卷积常用于轻量化模型设计,特别适用于移动设备和嵌入式系统,可以在保持模型性能的同时显著减少参数和计算开销。
2.3.4 Python源码实现
import numpy as np
def depthwise_conv2d(input, kernel):
"""
深度可分离卷积实现。
参数:
- input: 输入的2D数组(输入特征图)。
- kernel: 深度可分离卷积核。
返回:
- output: 深度可分离卷积后的输出特征图。
"""
input_height, input_width = input.shape
kernel_height, kernel_width = kernel.shape
# 用零初始化输出特征图
output = np.zeros((input_height - kernel_height + 1, input_width - kernel_width + 1))
# 深度卷积
for i in range(input_height - kernel_height + 1):
for j in range(input_width - kernel_width + 1):
output[i, j] = np.sum(input[i:i + kernel_height, j:j + kernel_width] * kernel)
return output
def pointwise_conv2d(input, kernel):
"""
逐点卷积实现。
参数:
- input: 输入的2D数组(输入特征图)。
- kernel: 逐点卷积核。
返回:
- output: 逐点卷积后的输出特征图。
"""
output = np.zeros((input.shape[0], input.shape[1], kernel.shape[0]))
for i in range(kernel.shape[0]):
output[i] = np.multiply(input, kernel[i])
return output
def depthwise_separable_conv2d(input, depthwise_kernel, pointwise_kernel):
"""
深度可分离卷积实现。
参数:
- input: 输入的2D数组(输入特征图)。
- depthwise_kernel: 深度可分离卷积深度卷积核。
- pointwise_kernel: 深度可分离卷积逐点卷积核。
返回:
- output: 深度可分离卷积后的输出特征图。
"""
# 深度卷积
depthwise_output = depthwise_conv2d(input, depthwise_kernel)
# 逐点卷积
output = pointwise_conv2d(depthwise_output, pointwise_kernel)
return output
# 用固定整数矩阵进行测试
input_feature_map = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
depthwise_kernel = np.array([[1, 0],
[0, -1]])
pointwise_kernel = np.array([[2], [-1]])
result = depthwise_separable_conv2d(input_feature_map, depthwise_kernel, pointwise_kernel)
print("深度可分离卷积后的输出特征图:\n", result)
运行结果:
深度可分离卷积后的输出特征图:
[[[-8. -8.]
[-8. -8.]]
[[ 4. 4.]
[ 4. 4.]]]
2.3.5 TensorFlow案例
import tensorflow as tf
import numpy as np
# 将NumPy数组转换为TensorFlow张量
input_feature_map = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
depthwise_kernel = np.array([[1, 0],
[0, -1]])
pointwise_kernel = np.array([[2], [-1]])
input_feature_map = tf.constant(input_feature_map, dtype=tf.float32)
depthwise_kernel = tf.constant(depthwise_kernel, dtype=tf.float32)
pointwise_kernel = tf.constant(pointwise_kernel, dtype=tf.float32)
# TensorFlow深度可分离卷积实现
depthwise_output = tf.nn.depthwise_conv2d(input_feature_map[None, :, :, None],
depthwise_kernel[:, :, None, None],
strides=[1, 1, 1, 1],
padding='VALID')
# 修改pointwise_kernel的形状
pointwise_kernel = np.transpose(pointwise_kernel)[:, None, None, :]
pointwise_output = tf.nn.conv2d(depthwise_output, pointwise_kernel,
strides=[1, 1, 1, 1],
padding='VALID')
# 提取两个独立的矩阵
channel_1_output = pointwise_output.numpy()[:, :, :, 0]
channel_2_output = pointwise_output.numpy()[:, :, :, 1]
print("通道 1 的输出矩阵:\n", channel_1_output)
print("通道 2 的输出矩阵:\n", channel_2_output)
运行结果:
通道 1 的输出矩阵:
[[[-8. -8.]
[-8. -8.]]]
通道 2 的输出矩阵:
[[[4. 4.]
[4. 4.]]]
2.4 转置卷积(反卷积)
2.4.1 概念定义
转置卷积,也称为反卷积或上采样,是卷积神经网络中的一种操作,用于将低分辨率的特征图上采样到高分辨率。它的核心思想是通过在输入之间插入零来进行上采样,并使用卷积核执行卷积操作。
2.4.2 基本原理和公式计算
2.4.2.1 基本原理
转置卷积的基本原理是通过卷积核的转置进行操作,实现特征图的上采样。在转置卷积中,卷积核的参数是可学习的,可以通过反向传播进行优化。
转置卷积通过在输入之间插入零来进行上采样,并使用卷积核执行卷积操作的一种操作。下面是转置卷积的基本计算步骤:
零填充(Zero Padding): 在输入特征图的每个元素周围添加零,以便在转置卷积过程中保持空间信息。
卷积核的转置: 将卷积核进行旋转180°。这是因为转置卷积的目标是对输入进行上采样,而不是下采样。
卷积操作: 使用转置后的卷积核对零填充后的输入进行卷积操作。这会导致输出特征图的尺寸增大,实现了上采样效果。
调整输出尺寸: 根据卷积的步幅和填充,调整输出特征图的尺寸。
2.4.2.2 输出特征图尺寸
有文章说,将 H in H_{\text{in}} Hin和 H out H_{\text{out}} Hout交换求解即可,如下:
转置卷积的输出特征图尺寸计算与普通卷积相反。设输入特征图尺寸为 H in × W in H_{\text{in}} \times W_{\text{in}} Hin×Win,卷积核大小为 K × K K \times K K×K,步幅为 S S S,填充为 P P P,则转置卷积的输出特征图尺寸计算如下:
H out = ( H in − 1 ) × S − 2 P + K H_{\text{out}} = (H_{\text{in}} - 1) \times S - 2P + K Hout=(Hin−1)×S−2P+K
W out = ( W in − 1 ) × S − 2 P + K W_{\text{out}} = (W_{\text{in}} - 1) \times S - 2P + K Wout=(Win−1)×S−2P+K
但用这个公式手工代码实现计算长宽时无法计算出正确的结果。
为了得到正确的长宽值,Python源码实现
中仍然使用常规卷积公式:
H
out
=
H
in
−
K
+
2
P
S
+
1
H_{\text{out}} = \frac{{H_{\text{in}} - K + 2P}}{S} + 1
Hout=SHin−K+2P+1
W out = W in − K + 2 P S + 1 W_{\text{out}} = \frac{{W_{\text{in}} - K + 2P}}{S} + 1 Wout=SWin−K+2P+1
哪个公式是正确的,留给读者在评论区交流。
2.4.2.3 参数量的计算
转置卷积的参数量计算与普通卷积相似,取决于输入通道数、卷积核大小和输出通道数。假设输入通道数为 D D D,卷积核大小为 K × K K \times K K×K,输出通道数为 M M M,则参数量计算如下:
参数量 = D × K × K × M \text{参数量} = D \times K \times K \times M 参数量=D×K×K×M
2.4.2.4 计算量的估算
转置卷积的计算量估算与普通卷积相似,取决于输入特征图的大小、卷积核的大小和输出通道数。设输入特征图大小为 H in × W in H_{\text{in}} \times W_{\text{in}} Hin×Win,卷积核大小为 K × K K \times K K×K,输出通道数为 M M M,计算量估算如下:
计算量 = H in × W in × K × K × M \text{计算量} = H_{\text{in}} \times W_{\text{in}} \times K \times K \times M 计算量=Hin×Win×K×K×M
2.4.3 应用场景
转置卷积主要应用于语义分割、图像生成等任务,其中需要将低分辨率的特征图上采样到高分辨率。
2.4.4 Python源码实现
以下是使用 NumPy 库实现转置卷积的简单示例:
import numpy as np
def transpose_convolution(input_data, kernel, stride=1, padding=0):
# 使用 numpy.rot90 两次
rotated_kernel = np.rot90(np.rot90(kernel))
# 使用 numpy.pad 进行填充
padded_data = np.pad(input_data, pad_width=padding, mode='constant', constant_values=0)
input_height, input_width = input_data.shape
kernel_height, kernel_width = kernel.shape
# 原始公式
# output_height = (input_height - 1) * stride - 2 * padding + kernel_height
# output_width = (input_width - 1) * stride - 2 * padding + kernel_width
# 常规卷积公式
output_height = int((input_height - kernel_height + 2 * padding) / stride + 1)
output_width =int( (input_width - kernel_width + 2 * padding) / stride + 1)
output = np.zeros((output_height, output_width))
for i in range(0, output_height, stride):
for j in range(0, output_width, stride):
output[i, j] = np.sum(padded_data[i:i + kernel_height, j:j + kernel_width] * rotated_kernel)
return output
# 示例
input_data = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0]])
kernel = np.array([[1.0, 0.0],
[-1.0, 2.0]])
result = transpose_convolution(input_data, kernel, stride=1, padding=1)
print("Input Data:\n", input_data)
print("\nKernel:\n", kernel)
print("\nOutput Data after Transpose Convolution:\n", result)
运行结果:
Input Data:
[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
Kernel:
[[ 1. 0.]
[-1. 2.]]
Output Data after Transpose Convolution:
[[ 1. 2. 3. 0.]
[ 3. 5. 7. 6.]
[ 3. 11. 13. 12.]
[-7. 6. 7. 18.]]
2.4.5 TensorFlow案例
在 TensorFlow 中,可以使用 tf.nn.conv2d_transpose
函数来实现转置卷积。以下是一个简单的示例:
import tensorflow as tf
import numpy as np
# 定义输入图像和卷积核
input_image = tf.constant([[[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0]]], shape=[1, 3, 3, 1], dtype=tf.float32)
kernel = tf.constant([[[1.0, 0.0],
[-1.0, 2.0]]], shape=[2, 2, 1, 1], dtype=tf.float32)
output_image = tf.nn.conv2d_transpose(input_image, kernel, output_shape=[1, 4, 4, 1], strides=[1, 1, 1, 1], padding='VALID')
# 输入图像、卷积核和输出图像的值
input_image_vals = input_image.numpy().squeeze()
kernel_vals = kernel.numpy().squeeze()
output_image_vals = output_image.numpy().squeeze()
# 打印输入图像、卷积核和输出图像
print("Input Image:\n", np.array2string(input_image_vals, precision=2, separator=', ', suppress_small=True))
print("\nKernel:\n", np.array2string(kernel_vals, precision=2, separator=', ', suppress_small=True))
print("\nOutput Image after 2D Transpose Convolution:\n", np.array2string(output_image_vals, precision=2, separator=', ', suppress_small=True))
运行结果:
Input Image:
[[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]]
Kernel:
[[ 1., 0.],
[-1., 2.]]
Output Image after 2D Transpose Convolution:
[[ 1., 2., 3., 0.],
[ 3., 5., 7., 6.],
[ 3., 11., 13., 12.],
[-7., 6., 7., 18.]]
2.4.6 计算例题
下面是一个简单的计算例子,演示了如何通过转置卷积将一个
2
×
2
2 \times 2
2×2的输入特征图上采样为
3
×
3
3 \times 3
3×3的输出特征图:
在转置卷积的计算中,可以使用矩阵表示特征图和卷积核。以下是一个简化的例子,其中特征图和卷积核都用矩阵表示:
假设有一个
2
×
2
2 \times 2
2×2的输入特征图:
[
1
2
3
4
]
\begin{bmatrix} 1 & 2 \\ 3 & 4 \\ \end{bmatrix}
[1324]
和一个
2
×
2
2 \times 2
2×2的转置卷积核:
[
a
b
c
d
]
\begin{bmatrix} a & b \\ c & d \\ \end{bmatrix}
[acbd]
零填充: 在输入特征图周围添加零,变为一个 4 × 4 4 \times 4 4×4的矩阵:
[ 0 0 0 0 0 1 2 0 0 3 4 0 0 0 0 0 ] \begin{bmatrix} 0 & 0 & 0 & 0 \\ 0 & 1 & 2 & 0 \\ 0 & 3 & 4 & 0 \\ 0 & 0 & 0 & 0 \\ \end{bmatrix} 0000013002400000 卷积核的旋转180°:
[ d c b a ] \begin{bmatrix} d & c \\ b & a \\ \end{bmatrix} [dbca]卷积操作: 对零填充后的输入进行卷积操作,计算每个位置的输出。
[ a b + 2 a 2 b c + 3 a d + 2 c + 3 b + 4 a 2 d + 4 b 3 c 3 d + 4 c 4 d ] \begin{bmatrix} a & b+2a & 2b\\ c+3a & d+2c+3b+4a & 2d+4b \\ 3c & 3d+4c & 4d \\ \end{bmatrix} ac+3a3cb+2ad+2c+3b+4a3d+4c2b2d+4b4d 输出: 输出尺寸为 3 × 3 3 \times 3 3×3。
三、高级卷积操作简介
3.1 扩张卷积
卷积神经网络(CNNs)的发展不断推动着卷积操作的创新,其中扩张卷积是一项重要的技术。扩张卷积,也称为膨胀卷积或空洞卷积,通过在卷积核中引入间隔(或膨胀率),使得卷积核的感受野增大,有效地捕捉更广泛的上下文信息。
3.1.1 概念介绍
扩张卷积的关键在于卷积核内插入零,以实现对输入数据更大范围的感知。这种插入零的方式相当于在卷积核的像素之间引入间隔,因此也称为膨胀卷积。通常,扩张卷积的膨胀率(dilation rate)指定了插入零的间隔。
3.1.2 基本原理和公式计算
假设输入数据为 X X X,卷积核为 K K K,膨胀率为 d d d,输出特征图为 Y Y Y,那么扩张卷积的计算公式如下:
Y [ i , j ] = ∑ m = 0 H − 1 ∑ n = 0 W − 1 X [ i ⋅ s + m ⋅ d , j ⋅ s + n ⋅ d ] ⋅ K [ m , n ] Y[i, j] = \sum_{m=0}^{H-1} \sum_{n=0}^{W-1} X[i \cdot s + m \cdot d, j \cdot s + n \cdot d] \cdot K[m, n] Y[i,j]=m=0∑H−1n=0∑W−1X[i⋅s+m⋅d,j⋅s+n⋅d]⋅K[m,n]
其中, H H H 和 W W W 分别是卷积核的高度和宽度, s s s 是步幅。其中, i i i 和 j j j 分别表示输出的行和列, m m m 和 n n n 分别表示卷积核的行和列。 扩张卷积可以通过在卷积核的元素之间插入 d − 1 d-1 d−1 个零来实现膨胀。
这样的扩张卷积操作可以增加每个卷积核的感受野,从而有助于捕捉更广泛的空间信息,同时保持较小的参数量。这在一些视觉任务中,特别是处理大尺度图像或提取全局上下文信息时,通常是有益的。
3.1.3 应用场景
扩张卷积广泛应用于各种计算机视觉任务,特别是在语义分割、图像生成和人体姿态估计等领域。由于其能够捕获更大范围的上下文信息,扩张卷积有助于提高模型的感知能力,使其在处理全局关系和复杂场景时更具优势。
3.2 分组卷积
分组卷积通过将输入和卷积核分成多个组进行独立卷积操作,然后将结果合并。这种操作有助于减少参数量,提高计算效率。
3.2.1 概念介绍
在传统的卷积操作中,一个卷积核会同时处理输入数据的所有通道。而在分组卷积中,输入数据和卷积核被分成若干组,每组进行独立的卷积操作,最后将各组的结果合并。这有助于降低计算复杂度,尤其在深层网络中更为显著。
3.2.2 基本原理和公式计算
假设输入数据为 X X X,卷积核为 K K K,分组数为 G G G,输出特征图为 Y Y Y,那么分组卷积的计算公式如下:
Y = ∑ g = 0 G − 1 X g ∗ K g Y = \sum_{g=0}^{G-1} X_g \ast K_g Y=g=0∑G−1Xg∗Kg
其中, X g X_g Xg 和 K g K_g Kg 分别表示输入数据和卷积核的第 g g g 组。
3.2.3 应用场景
分组卷积常用于模型设计中,特别是在对计算资源有限的移动设备上。通过减少每个卷积层的参数量,分组卷积有助于在有限的内存和计算能力下实现更轻量级的模型。
总结
本文深入探讨了卷积神经网络(CNN)中卷积操作的基本概念和常见操作。
在卷积的基本概念部分,详细介绍了卷积核、步幅和填充等重要概念,以及通道和维度的概念。这些基本概念为理解卷积操作的原理和实现奠定了基础。
接着,文中详细介绍了一维卷积、二维卷积和深度可分离卷积等常见卷积操作。对于每种操作,包括概念定义、基本原理和公式计算、应用场景等方面都进行了详细的阐述。
此外,为了更好地理解,文中还给出了Python源码实现和TensorFlow案例,以及计算例题,使理论与实际结合,加强学习效果。