PyTorch实战(4)——卷积神经网络(Convolutional Neural Network, CNN)详解
PyTorch实战(4)——卷积神经网络详解
- 0. 前言
- 1. 全连接网络的缺陷
- 2. 卷积神经网络基本组件
- 2.1 卷积
- 2.2 步幅和填充
- 2.3 池化
- 2.3 卷积神经网络完整流程
- 3. 卷积和池化相比全连接网络的优势
- 4. 使用 PyTorch 构建卷积神经网络
- 4.1 使用 PyTorch 构建 CNN 架构
- 4.2 验证 CNN 输出
- 小结
- 系列链接
0. 前言
卷积神经网络 (Convolutional Neural Network
, CNN
) 是一种非常强大的深度学习模型,广泛应用于图像分析、目标检测、图像生成等任务中。CNN
的核心思想是卷积操作和参数共享,卷积操作通过滑动滤波器(也称为卷积核)在输入数据上进行元素级的乘积和求和运算,从而提取局部特征。通过多个滤波器的组合,CNN
可以学习到不同层次的特征表示,从低级到高级的抽象特征。本节从传统全连接神经网络的缺陷为切入点,介绍了卷积神经网络的优势及其基本组件,并使用 PyTorch
构建卷积神经网络。
1. 全连接网络的缺陷
在深入研究卷积神经网络 (Convolutional Neural Network
, CNN
) 之前,我们首先介绍传统深度神经网络的主要缺陷。传统深度前馈神经网络(也称全连接网络)的局限性之一是它不满足平移不变性,也就是说,在全连接网络看来,图像右上角有猫与位于图像中心的猫被视为不同对象,即使这是同一只猫。另外,全连接网络受对象大小的影响,如果训练集中大多数图像中的对象较大,而训练数据集图像中包含相同的对象但占据图像画面的比例较小,则全连接网络可能无法对图像进行正确分类。
接下来,我们通过具体示例来了解全连接网络的缺陷,继续使用在 PyTorch 构建深度神经网络中基于 Fashion-MNIST
数据集构建的模型,并预测给定图像对应的类别。
(1) 从训练图像中获取随机图像:
ix = 24150
plt.imshow(tr_images[ix], cmap='gray')
plt.title(fmnist.classes[tr_targets[ix]])
plt.show()
(2) 将图像输入到训练完毕的神经网络模型中,对输入图像执行预处理,并预测图像对应于各类别的概率:
img = tr_images[ix]/255.
img = img.view(28*28)
img = img.to(device)np_output = model(img).cpu().detach().numpy()
print(np.exp(np_output)/np.sum(np.exp(np_output)))
"""
[3.1946290e-02 1.2138572e-03 8.1082803e-01 9.7291003e-04 8.0925472e-022.9379700e-07 7.3724821e-02 3.3111525e-07 3.1927411e-04 6.8671055e-05]
"""
从输出结果中,可以看到概率最高的是第 2
个索引,对应于 Pullover
类别。
(3) 多次平移图像,并记录预测结果。
创建一个存储预测结果的列表:
preds = []
创建循环,将图像从原始位置向右移动:
for px in range(-5,6):
对图像进行预处理:
img = tr_images[ix]/255.img = img.view(28, 28)
在 for
循环中平移图像:
img2 = np.roll(img, px, axis=1)
在以上代码中,使用 axis=1
指定图像像素水平移动,将移动后的图像存储为张量对象并注册到设备中:
img3 = torch.Tensor(img2).view(28*28).to(device)
将 img3
输入到经过训练的模型以预测图像类别,并将其追加到存储预测结果列表中:
np_output = model(img3).cpu().detach().numpy()preds.append(np.exp(np_output)/np.sum(np.exp(np_output)))
(4) 可视化模型对所有平移图像的预测( -5
像素到 +5
像素):
import seaborn as sns
fig, ax = plt.subplots(1,1, figsize=(12,10))
plt.title('Probability of each class for various translations')
sns.heatmap(np.array(preds), annot=True, ax=ax, fmt='.2f', xticklabels=fmnist.classes, yticklabels=[str(i)+str(' pixels') for i in range(-5,6)], cmap='gray')
plt.show()
图像内容并没有任何变化,因为对图像像素执行了平移,然而,当平移超过 2
个像素时,图像的预测类别发生了改变。这是因为在训练模型时,所有训练图像中的内容都处于中心位置,当使用偏离中心的平移图像进行测试时,模型将输出错误预测结果。这些问题的存在就是我们需要使用 CNN
的原因。
2. 卷积神经网络基本组件
卷积神经网络 (Convolutional Neural Network
, CNN
) 是处理图像时最常用的架构,CNN
解决了传统全连接神经网络的主要缺陷,除了图像分类,还可以用于目标检测、图像分割、GAN
等等,本质上,在使用图像作为输入的网络中,都可以使用 CNN
架构。在本节中,我们将详细介绍 CNN
中卷积过程的工作原理。
2.1 卷积
卷积本质上是两个矩阵之间的乘法(矩阵乘法是训练神经网络的关键要素)——通常一个矩阵具有较大尺寸,另一个矩阵则较小。为了确保我们对卷积过程有较好的理解,我们首先查看以下例子。
假设我们有两个矩阵用于执行卷积。给定矩阵 A
和矩阵 B
如下:
在进行卷积时,我们将较小的矩阵在较大的矩阵上滑动,在上述两个矩阵中,当较小的矩阵 B 需要在较大矩阵的整个区域上滑动时,会得到 9
次乘法运算,过程如下:
在矩阵 A
中从第 1
个元素开始选取与矩阵 B
相同尺寸的子矩阵 [ 1 2 0 1 1 1 3 3 2 ] \left[ \begin{array}{ccc} 1 & 2 & 0\\ 1 & 1 & 1\\ 3 & 3 & 2\\\end{array}\right] 113213012 和矩阵 B
相乘并求和:
1 × 3 + 2 × 1 + 0 × 1 + 1 × 2 + 1 × 3 + 1 × 1 + 3 × 2 + 3 × 2 + 2 × 3 = 29 1\times 3+2\times 1+0\times 1+1\times 2+1\times 3+1\times 1+3\times 2+3\times 2 + 2\times 3=29 1×3+2×1+0×1+1×2+1×3+1×1+3×2+3×2+2×3=29
然后,向右滑动一个窗口,选择第 2
个与矩阵 B
相同尺寸的子矩阵 [ 2 0 2 1 1 2 3 2 1 ] \left[ \begin{array}{ccc} 2 & 0 & 2\\ 1 & 1 & 2\\ 3 & 2 & 1\\\end{array}\right] 213012221 和矩阵 B
相乘并求和:
2 × 3 + 0 × 1 + 2 × 1 + 1 × 2 + 1 × 3 + 2 × 1 + 3 × 2 + 2 × 2 + 1 × 3 = 28 2\times 3+0\times 1+2\times 1+1\times 2+1\times 3+2\times 1+3\times 2+2\times 2 + 1\times 3=28 2×3+0×1+2×1+1×2+1×3+2×1+3×2+2×2+1×3=28
然后,再向右滑动一个窗口,选择第 3
个与矩阵 B
相同尺寸的子矩阵 [ 0 2 3 1 2 0 2 1 2 ] \left[ \begin{array}{ccc} 0 & 2 & 3\\ 1 & 2 & 0\\ 2 & 1 & 2\\\end{array}\right] 012221302 和矩阵 B
相乘并求和:
0 × 3 + 2 × 1 + 3 × 1 + 1 × 2 + 2 × 3 + 0 × 1 + 2 × 2 + 1 × 2 + 2 × 3 = 25 0\times 3+2\times 1+3\times 1+1\times 2+2\times 3+0\times 1+2\times 2+1\times 2 + 2\times 3=25 0×3+2×1+3×1+1×2+2×3+0×1+2×2+1×2+2×3=25
当向右滑到尽头时,向下滑动一个窗口,并从矩阵 A
左边开始,选择第 4
个与矩阵 B
相同尺寸的子矩阵 [ 1 1 1 3 3 2 1 0 2 ] \left[ \begin{array}{ccc} 1 & 1 & 1\\ 3 & 3 & 2\\ 1 & 0 & 2\\\end{array}\right] 131130122 和矩阵 B
相乘并求和:
1 × 3 + 1 × 1 + 1 × 1 + 3 × 2 + 3 × 3 + 2 × 1 + 1 × 2 + 0 × 2 + 2 × 3 = 30 1\times 3+1\times 1+1\times 1+3\times 2+3\times 3+2\times 1+1\times 2+0\times 2 + 2\times 3=30 1×3+1×1+1×1+3×2+3×3+2×1+1×2+0×2+2×3=30
然后,继续向右滑动,并重复以上过程滑动矩阵窗口,直到滑动到最后一个子矩阵为止,得到最终的结果 [ 29 28 25 30 30 27 20 24 34 ] \left[ \begin{array}{ccc} 29 & 28 & 25\\ 30 & 30 & 27\\ 20 & 24 & 34\\\end{array}\right] 293020283024252734 :
完整的卷积计算过程如以下动图所示:
通常,我们把较小的矩阵 B
称为滤波器 (filter
) 或卷积核 (kernel
),使用 ⊗ \otimes ⊗ 表示卷积运算,较小矩阵中的值通过梯度下降被优化学习,卷积核中的值则为网络权重。在计算机视觉中,卷积后得到的矩阵,也称为特征图 (feature map
)。
滤波器是在模型开始训练时随机初始化的权重矩阵,模型会在训练过程中学习滤波器的最佳权重值。一般来说,CNN
中的滤波器越多,模型能够学习到的图像特征就越多,在后续学习中我们会介绍滤波器学习到的内容。滤波器能够学习图像中的不同特征,例如,某个滤波器可能会学习到如何分辨猫的耳朵,并在图像包含猫的耳朵时能够卷积得到较高激活(即矩阵乘法值)。
卷积核的通道数与其所乘矩阵的通道数相等。例如,当图像输入形状为 5 x 5 x 3
时(其中 3
为图像通道数),形状为 3 x 3
的卷积核也将具有 3
个通道,以便进行矩阵卷积运算:
可以看到无论卷积核有多少通道,一个卷积核计算后都只能得到一个通道。多为了捕获图像中的更多特征,通常我们会使用多个卷积核,得到多个通道的特征图,当使用多个卷积核时,计算过程如下:
处理具有三个通道的彩色图像时,与原始图像卷积的滤波器也需要具有三个通道(每次卷积的计算结果为单个输出矩阵)。如果滤波器与网络中间输出进行卷积,比如中间输出形状为 64 x 112 x 112
,则每个滤波器都包括 64
个通道来获取输出;此外,如果有 512 个滤波器与中间层输出进行卷积,则卷积输出后的形状为 512 x 111 x 111
。
需要注意的是,卷积并不等同于滤波,最直观的区别在于滤波后的图像大小不变,而卷积会改变图像大小,关于它们之间更详细的计算差异,并非本节重点,因此不再展开介绍。
2.2 步幅和填充
2.2.1 步幅
在前面的示例中,卷积核每次计算时在水平和垂直方向只移动一个单位,因此可以说卷积核的步幅 (Strides
) 为 (1, 1)
,步幅越大,卷积操作跳过的值越多,例如以下为步幅为 (2, 2)
时的卷积过程:
2.1.3 填充
在前面的示例中,卷积操作对于输入矩阵的不同位置计算的次数并不相同,具体来说对于边缘的数值在卷积时,仅仅使用一次,而位于中心的值则会被多次使用,因此可能导致卷积错过图像边缘的一些重要信息。如果要增加对于图像边缘的考虑,我们将在输入矩阵的边缘周围的填充 (Padding
) 0
,下图展示了用 0
填充边缘后的矩阵进行的卷积运算,这种填充形式进行的卷积,称为 same
填充,卷积后得到的矩阵大小为 ⌊ d + 2 p − k s ⌋ + 1 \lfloor\frac {d+2p-k} s\rfloor+1 ⌊sd+2p−k⌋+1,其中 s s s 表示步幅, p p p 表示填充大小, k k k 表示滤波器尺寸。而未进行填充时执行卷积运算,也称为 valid
填充。
完成此操作后,可以在卷积操作的输出之上执行激活函数,CNN
支持常见的所有可用激活函数,包括 Sigmoid
,ReLU
和 LeakyReLU
等。
2.3 池化
研究了卷积的工作原理之后,我们将了解用于卷积操作之后的另一个常用操作:池化 (Pooling
)。假设卷积操作的输出如下,为 2 x 2
:
[ 29 28 20 24 ] \left[ \begin{array}{cc} 29 & 28\\ 20 & 24\\\end{array}\right] [29202824]
假设使用池化块(或者类比卷积核,我们也可以称之为池化核)为 2 x 2
的最大池化,那么将会输出 29
作为池化结果。假设卷积步骤的输出是一个更大的矩阵,如下所示:
[ 29 28 25 29 20 24 30 26 27 23 26 27 24 25 23 31 ] \left[ \begin{array}{cccc} 29 & 28 & 25 & 29\\ 20 & 24 & 30 & 26\\ 27 & 23 & 26 & 27\\ 24 & 25 & 23 & 31\\\end{array}\right] 29202724282423252530262329262731
当池化核为 2 x 2
,且步幅为 2
时,最大池化会将此矩阵划分为 2 x 2
的非重叠块,并且仅保留每个块中最大的元素值,如下所示:
[ 29 28 ∣ 25 29 20 24 ∣ 30 26 — — — — — 27 23 ∣ 26 27 24 25 ∣ 23 31 ] = [ 29 30 27 31 ] \left[ \begin{array}{ccccc} 29 & 28 & | & 25 & 29\\ 20 & 24 & | & 30 & 26\\ —&—&—&—&—\\ 27 & 23 & | & 26 & 27\\ 24 & 25 & | & 23 & 31\\\end{array}\right]=\left[ \begin{array}{cc} 29 & 30\\ 27 & 31\\\end{array}\right] 2920—27242824—2325∣∣—∣∣2530—26232926—2731 =[29273031]
从每个池化块中,最大池化仅选择具有最高值的元素。除了最大池化外,也可以使用平均池化,其将输出每个池化块中的平均值作为结果,在实践中,与其他类型的池化相比,最常使用的池化为最大池化。
2.3 卷积神经网络完整流程
我们已经了解了卷积、滤波器和池化,以及它们对图像维度的影响。在 CNN
中通常还需要另一个关键组件——展平层。
为了理解展平过程,使用上一节得到的池化层输出,将输出展平后输出如下:
[ 29 30 27 31 ] \left[ \begin{array}{cccc} 29 & 30 & 27 & 31\end{array}\right] [29302731]
这样,就可以将 flatten
层视为全连接层的输入层,将其通过若干隐藏层后,获得用于预测图像类别的输出。综上,一个 CNN
的完整流程如下:
在上图中,可以看到 CNN
模型的整体流程,首先将图像通过多个滤波器进行卷积,然后进行池化(并数次重复执行卷积和池化过程),然后最后的池化操作输出展平,这部分称为特征学习 (feature learning
)。
特征学习部分基本上由卷积和池化操作构成,使用滤波器从图像中提取相关特征,使用池化聚合特征信息,从而减少展平层的节点数量。如果直接展平输入图像,即使图像大小仅为 300 x 300=90000
像素,如果在隐藏层中有 1000
个神经节点,则在隐藏层就大约需要 900000x1000=90000000
个参数,计算量巨大。而卷积和池化有助于减少图像特征数量,降低计算量。最后,网络的分类 (classification
) 部分类似于在使用 PyTorch 构建神经网络中介绍的全连接神经网络。
3. 卷积和池化相比全连接网络的优势
传统神经网络的缺点之一是每个像素都具有不同的权重。因此,如果这些权重要用于除原始像素以外的相邻像素,则神经网络得到的输出将不是非常准确。在 CNN
中,图像中的像素共享由每个卷积核构成的权重,相比全连接网络具有以下优势:
- 参数共享:在卷积层中,权重参数被共享,这意味着每个卷积核在整个输入图像上进行滑动并提取特征,这种参数共享的方式显著减少了需要学习的参数数量,降低了模型复杂度,从而减少了过拟合的风险
- 局部感知和空间结构:卷积层通过使用局部感知域(感受野)的方式来识别图像中的特征,利用了图像的空间结构信息,这使得卷积神经网络在处理图像等二维数据时能够更好地捕捉到图像的局部特征和空间关系,从而提高了图像处理的效果
- 参数量减少:由于卷积层采用参数共享的机制,卷积神经网络通常比全连接网络具有更少的参数量,这不仅减少了训练网络所需的计算资源和时间,而且降低了过拟合的风险,有助于更好地泛化到新的数据集
- 平移不变性:卷积操作具有平移不变性,也就是说,当输入图像发生平移时,卷积层的输出不会改变,这种平移不变性使得卷积神经网络对于图像中的平移和位置变化具有鲁棒性,可以更好地处理具有不同位置和尺度的图像
- 降低计算复杂度:由于参数共享和局部感知机制,卷积神经网络的计算复杂度相对较低,这使得
CNN
在处理大规模图像数据时比全连接网络更高效,并且适用于部署在资源受限的设备上,如移动设备和嵌入式系统
接下来,我们从卷积和池化角度理解感受野,感受野是卷积神经网络中每个网络层输出的特征图中的单个元素映射回原始输入特征中的区域大小,假设我们对形状为 100 x 100
的图像执行两次卷积池化操作,两个卷积池化操作结束时的输出的形状为 25 x 25
(假设在卷积操作时使用填充操作),25 x 25
的输出中的每个单元对应于原始图像中尺寸为 4 x 4
的部分。通常网络层越深,其输出特征的元素对应感受野越大。
4. 使用 PyTorch 构建卷积神经网络
CNN
是计算机视觉的基础模块之一,在了解其工作原理后,本节中,我们通过代码了解 CNN
前向传播过程中的计算流程。
首先,我们使用 PyTorch
在一个简单数据示例上构建一个 CNN
架构,然后通过在 Python
中从零开始构建前向传播来验证输出结果。
4.1 使用 PyTorch 构建 CNN 架构
(1) 首先,导入相关的库并创建数据集:
import torch
from torch import nn
from torch.utils.data import TensorDataset, DataLoader
from torch.optim import Adam
device = 'cuda' if torch.cuda.is_available() else 'cpu'X_train = torch.tensor([[[[1,2,3,4],[2,3,4,5],[5,6,7,8],[1,3,4,5]]],[[[-1,2,3,-4],[2,-3,4,5],[-5,6,-7,8],[-1,-3,-4,-5]]]]).to(device).float()
X_train /= 8
y_train = torch.tensor([[0],[1]]).to(device).float()
需要注意的是,与 Keras
等机器学习库不同,PyTorch
期望输入的形状为 N x C x H x W
,其中 N
是图像数量(批大小),C
是通道数,H
是高度,W
是宽度。
将输入数据除以最大输入值缩放输入数据集,使其范围在 -1
到 +1
之间。以上输入数据集的形状为 (2,1,4,4)
,因为有两个数据点,每个数据点的形状为 4 x 4
并且有 1
个通道。
(2) 定义模型架构:
def get_model():model = nn.Sequential(nn.Conv2d(1, 1, kernel_size=3),nn.MaxPool2d(2),nn.ReLU(),nn.Flatten(),nn.Linear(1, 1),nn.Sigmoid(),).to(device)loss_fn = nn.BCELoss()optimizer = Adam(model.parameters(), lr=1e-2)return model, loss_fn, optimizer
在以上模型中,指定输入图像中有 1
个通道,使用 nn.Conv2d
方法指定卷积后包括 1
个通道(大小为 3 x 3
的滤波器),使用 nn.MaxPool2d
执行最大池化,使用 nn.ReLU()
执行 ReLU
激活,然后展平激活值并连接到输出层,输出层中包含一个神经元。由于输出为二分类问题,因此使用二元交叉熵损失 nn.BCELoss()
,还指定使用学习率为 0.001
的 Adam
优化器进行优化。
(3) 调用 get_model()
函数初始化模型、损失函数 (loss_fn
) 和优化器后,使用 torch_summary
(可以使用 pip install torch_summary
命令安装 torch_summary
库)查看模型架构摘要:
from torchsummary import summary
model, loss_fn, optimizer = get_model()
print(summary(model, tuple(X_train.shape[1:])))
"""
----------------------------------------------------------------Layer (type) Output Shape Param #
================================================================Conv2d-1 [-1, 1, 2, 2] 10MaxPool2d-2 [-1, 1, 1, 1] 0ReLU-3 [-1, 1, 1, 1] 0Flatten-4 [-1, 1] 0Linear-5 [-1, 1] 2Sigmoid-6 [-1, 1] 0
================================================================
Total params: 12
Trainable params: 12
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.00
Params size (MB): 0.00
Estimated Total Size (MB): 0.00
----------------------------------------------------------------
"""
接下来,我们介绍每一网络层的参数来源。 Conv2d
类的参数如下:
在示例中,指定卷积核大小 (kernel_size
) 为 3
,输出通道数 (out_channels
) 为 1
(即滤波器数量为 1
),其中初始(输入)通道的数量为 1
。对于每个输入图像,形状为 1 x 4 x 4
的输入使用滤波器尺寸为 3x3
的卷积,因此,输出形状为 1 x 2 x 2
。网络包含 10
个参数( 3 x 3 = 9
个权重参数和 1
个卷积核偏置)。而 MaxPool2d
、ReLU
和 Flatten
层没有参数,因为这些计算并不涉及权重或偏置。
全连接层有 2
个参数( 1
个权重和 1
个偏置),因此,共有 12
个参数( 10
个来自卷积操作,2
个来自全连接层)。
(4) 重用在使用 PyTorch 构建神经网络中的代码训练模型,使用 PyTorch
构建深度神经网络,其中定义了训练批数据的函数 train_batch()
;然后,获取 DataLoader
并在 2,000
个 epoch
上对其进行训练。
定义在批数据上训练模型的函数 train_batch()
:
def train_batch(x, y, model, optimizer, loss_fn):model.train()prediction = model(x)# print(prediction)batch_loss = loss_fn(prediction, y)batch_loss.backward()optimizer.step()optimizer.zero_grad()return batch_loss.item()
通过使用 TensorDataset
方法指定数据集,然后使用 DataLoader
加载数据集定义训练 DataLoader
:
trn_dl = DataLoader(TensorDataset(X_train, y_train))
在以上代码中,直接利用 TensorDataset
方法,该方法提供与输入数据对应的对象。接下来,训练模型:
for epoch in range(2000):for ix, batch in enumerate(iter(trn_dl)):x, y = batchbatch_loss = train_batch(x, y, model, optimizer, loss_fn)
(5) 利用第一个数据点执行前向传递:
print(model(X_train[:1]))
# tensor([[0.0028]], device='cuda:0', grad_fn=<SigmoidBackward>)
在下一节中,我们将了解 CNN
中的前向传播工作原理,并从零开始构建 CNN
前向传播流程,验证本节模型计算结果。
4.2 验证 CNN 输出
在本节中,通过实现 CNN
的前向传播过程来验证从模型中获得的输出,本节仅用于帮助了解 CNN
的工作原理,而无需在实际应用场景中执行。
(1) 提取上一小节架构的卷积层和全连接层的权重和偏置。
提取模型的各个层:
print(list(model.children()))
"""
[Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1)), MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False), ReLU(), Flatten(start_dim=1, end_dim=-1), Linear(in_features=1, out_features=1, bias=True), Sigmoid()]
"""
提取模型中的所有层对应的 weights
属性:
(cnn_w, cnn_b), (lin_w, lin_b) = [(layer.weight.data, layer.bias.data) for layer in list(model.children()) if hasattr(layer, 'weight')]
在以上代码中,hasattr(layer,'weight')
会返回一个布尔值用于指示网络层是否包含权重属性。
只有卷积 (Conv2d
) 层和全连接层包含参数的网络层,分别保存为 cnn_w
和 cnn_b
以及 lin_w
和 lin_b
。cnn_w
的形状为 1 x 1 x 3 x 3
,对应于具有一个通道、形状为 3 x 3
的一个滤波器,cnn_b
的形状为 `1,对应于此滤波器的偏置值。
(2) 要对输入值执行 cnn_w
卷积运算,必须初始化一个零矩阵用于存储计算结果 (sumprod
),其中高度为 h_i - h_k + 1
,宽度为 w_i - w_k + 1
,其中 h_i
表示输入高度,h_k
表示滤波器高度,w_i
表示输入宽度,w_k
表示滤波器宽度:
h_im, w_im = X_train.shape[2:]
h_conv, w_conv = cnn_w.shape[2:]
sumprod = torch.zeros((h_im - h_conv + 1, w_im - w_conv + 1))
(3) 接下来,我们通过模拟卷积过程对输入数据执行卷积,沿着行和列执行矩阵乘法(卷积),首先将滤波器 (cnn_w
) 形状由 1 x 1 x 3 x 3
重塑为 3 x 3
,执行卷积后添加滤波器偏置项 (cnn_b
),填充到结果 sumprod
中:
for i in range(h_im - h_conv + 1):for j in range(w_im - w_conv + 1):img_subset = X_train[0, 0, i:(i+3), j:(j+3)]model_filter = cnn_w.reshape(3,3)val = torch.sum(img_subset*model_filter) + cnn_bsumprod[i,j] = val
在以上代码中,img_subset
存储了与滤波器执行卷积的输入部分。假设输入形状为 4 x 4
,滤波器形状为 3 x 3
,则输出形状为 2 x 2
,sumprod
的输出如下:
tensor([[-2.2831, -2.9537],[-0.6738, -1.5616]])
(4) 在输出 (sumprod
) 上使用最大池化 (MaxPooling
),然后执行 ReLU
激活。
对输出执行池化操作:
pooling_layer_output = torch.max(sumprod)
通过将输出最小值限制为 0
,模拟 ReLU
激活函数:
print(pooling_layer_output.clamp_min_(0))
(5) 通过线性激活传递以上输出:
intermediate_output_value = pooling_layer_output * lin_w + lin_b
(5) 由于使用二元交叉熵损失函数,因此通过 sigmoid
函数计算输出结果:
print(torch.sigmoid(intermediate_output_value))
# tensor([[0.0028]], device='cuda:0')
使用以上代码可以得到与使用 PyTorch
的 forward
方法相同输出结果,从而验证了 CNN
的计算流程。
小结
卷积神经网络 (Convolutional Neural Network
, CNN
) 是一种广泛应用的深度学习模型。通过参数共享、局部感知和空间结构等优势,能够更好地处理图像数据,并在图像识别、目标检测和图像生成等任务中展现出强大的能力。在本节中,介绍了卷积的计算方法以及卷积神经网络的基本组件,并使用 PyTorch
构建了卷积神经网络以深入了解其工作原理。
系列链接
PyTorch生成式人工智能实战:从零打造创意引擎
PyTorch实战(1)——神经网络与模型训练过程详解
PyTorch实战(2)——PyTorch基础
PyTorch实战(3)——使用PyTorch构建神经网络
PyTorch实战(5)——分类任务详解
PyTorch实战(6)——生成模型(Generative Model)详解
相关文章:
PyTorch实战(4)——卷积神经网络(Convolutional Neural Network, CNN)详解
PyTorch实战(4)——卷积神经网络详解 0. 前言1. 全连接网络的缺陷2. 卷积神经网络基本组件2.1 卷积2.2 步幅和填充2.3 池化2.3 卷积神经网络完整流程 3. 卷积和池化相比全连接网络的优势4. 使用 PyTorch 构建卷积神经网络4.1 使用 PyTorch 构建 CNN 架构…...
【Python】Python常用控制结构详解:条件判断、遍历与循环控制
Python提供了多种控制结构来处理逻辑判断和循环操作,包括if-else条件分支、switch替代方案、遍历方法以及循环控制语句break和continue。以下是对这些功能的详细说明及示例: 一、条件判断:if-else与多分支结构 单分支结构 • 语法࿱…...
在Linux中安装JDK并且搭建Java环境
1.首先准备好JDK的Linux的安装包 2.打开Linux,进入root的文件夹,直接拖入即可 3.输入解压命令,后面指定的是位置(注意不要填写错误,就填写这个) 4.之后进入我们安装的jdk的文件 利用pwd命令,展示我们安装的目录,之后…...
理解多智能体深度确定性策略梯度MADDPG算法:基于python从零实现
引言:多智能体强化学习(MARL) 多智能体强化学习(MARL)将强化学习拓展到多个智能体在共享环境中相互交互的场景。这些智能体可能相互合作、竞争,或者目标混杂。MARL 引入了单智能体设置中不存在的独特挑战。…...
【AI大语言模型本质分析框架】
AI大语言模型本质分析框架 ——从教育危机到智能本质的七层递进式解构 第一层:现象观察——阴(显性危机)与阳(隐性变革)的共存 观点1(阴):AI作弊泛滥,传统教育体系崩溃…...
算法模型部署后_python脚本API测试指南-记录3
API 测试指南 服务运行后,可以通过以下方式测试: Curl: curl -X POST -F "file./test_dataset/surface/surface57.png" http://<服务器IP>:9000/api/v1/predictPython 脚本: (参考 svm_request测试.py) import requestsurl http://…...
鸿蒙(HarmonyOS)应用开发入门教程
目录 第一章:鸿蒙系统简介 1.1 什么是鸿蒙系统? 1.2 鸿蒙系统架构 第二章:开发环境搭建 2.1 安装DevEco Studio 步骤1:下载与安装 步骤2:首次配置 步骤3:设备准备 2.2 创建第一个项目 第三章:鸿蒙应用开发基础 3.1 核心概念:Ability与AbilitySlice 示例代码…...
MIT XV6 - 1.6 Lab: Xv6 and Unix utilities -uptime
接上文 MIT XV6 - 1.5 Lab: Xv6 and Unix utilities - xargs 第一章持续有点久了,虽然肯定有些特点和细节还没注意到,但这次的主要目的是学习内核部分,决定水一篇然后进入第二章节 uptime 第一章的最后一个实验,选做性质…...
Python语言在地球科学交叉领域中的应用——从数据可视化到常见数据分析方法的使用【实例操作】
前言: Python是功能强大、免费、开源,实现面向对象的编程语言,Python能够运行在Linux、Windows、Macintosh、AIX操作系统上及不同平台(x86和arm),Python简洁的语法和对动态输入的支持,再加上解释…...
flutter 的 json序列化和反序列化
一、json转实体 Instantly parse JSON in any language | quicktype 二、实体中的toJson和fromJson 实现 官方推荐的 两个插件(个人觉得一个实体会多一个.g.dart 文件太多了,不喜欢) json_annotation json_serializable 三、使用 dart_json_mapper 实现上面的功…...
什么是数据集市(Data Mart)?
数据集市(Data Mart)是数据仓库(Data Warehouse)的一个子集,专门针对某个特定业务部门、业务线或主题领域,存储和管理该部门或领域所需的特定数据。它通常包含从企业范围的数据仓库中抽取、筛选和汇总的部分…...
从攻击者角度来看Go1.24的路径遍历攻击防御
目录 一、具体攻击示例 程序 攻击步骤: 二、为什么攻击者能成功? 分析 类比理解 总结 三、TOCTOU 竞态条件漏洞 1、背景:符号链接遍历攻击 2. TOCTOU 竞态条件漏洞 3. 另一种变体:目录移动攻击 4. 问题的核心 四、防…...
[ARM][汇编] 01.基础概念
目录 1.全局标号 1.1.使用方法 1.1.1.声明全局标号 1.1.2.定义全局标号 1.1.3.引用全局标号 1.2.全局标号与局部标号的区别 1.3.注意事项 2.局部标号 2.1.使用方法 2.1.1.定义局部标号 2.1.2.跳转引用 2.2.局部标号与全局标号的对比 2.3.注意事项 3.符号定义伪指…...
杭州电商全平台代运营领军者——品融电商
杭州电商全平台代运营领军者——品融电商:以“效品合一”驱动品牌全域增长 在电商行业竞争日益白热化的当下,品牌如何突破流量焦虑、实现长效增长?作为中国领先的品牌化电商服务商,杭州品融电商(PINKROON)…...
02.Golang 切片(slice)源码分析(一、定义与基础操作实现)
Golang 切片(slice)源码分析(一、定义与基础操作实现) 注意当前go版本代码为1.23 一、定义 slice 的底层数据是数组,slice 是对数组的封装,它描述一个数组的片段。两者都可以通过下标来访问单个元素。 数…...
当生产了~/qt-arm/bin/qmake,可以单独编译其他-源码的某个模块,如下,编译/qtmultimedia
cd ~/qt-everywhere-src-5.15.2/qtmultimedia # 设置交叉编译器和 qmake 路径 export CC/usr/bin/aarch64-linux-gnu-gcc export CXX/usr/bin/aarch64-linux-gnu-g export QMAKE~/qt-arm/bin/qmake # 使用已安装的 qmake export QT_INSTALL_PREFIX~/qt-arm # 安装路径 # 配…...
WordPress 网站上的 jpg、png 和 WebP 图片插件
核心功能 1. 转换 AVIF 并压缩 AVIF 将您 WordPress 网站上的 jpg、png 和 WebP 图片转换为 AVIF 格式,并根据您设置的压缩级别压缩 AVIF 图片。如果原始图片已经是 WordPress 6.5 以上支持的 AVIF 格式,则原始 AVIF 图片将仅被压缩。 2. 转换 WebP 并…...
构造+简单树状
昨日的牛客周赛算是比较简单的,其中最后一道构造题目属实眼前一亮。 倒数第二个题目也是一个很好的模拟题目(考验对二叉树的理解和代码的细节) 给定每一层的节点个数,自己拟定一个父亲节点,构造一个满足条件的二叉树。…...
Flask支持哪些日志框架
目录 ✅ Flask 默认支持的日志框架 ✅ 默认推荐:logging(标准库) ✅ 进阶推荐:Loguru(更优雅的日志库) ✅ Flask 日志级别说明(与标准库一致) ✅ 生产环境建议 ✅ 总结推荐 在 Flask 中,默认的日志系统是基于 Python 标准库 logging 模块 构建的。 ✅ Flask 默认…...
健康养生指南:解锁活力生活的科学密码
健康是人生最珍贵的财富,在快节奏的现代生活中,掌握科学的养生方法至关重要。虽然不借助中医理念,我们依然可以从饮食、运动、睡眠等多个方面入手,打造健康生活方式。 合理的饮食是健康的基石。遵循均衡饮食原则,保证每…...
SAR图像压缩感知
SAR图像压缩感知 matlab代码 对应着汕大闫老师的那本压缩感知及其应用,有需要的可以看一下!! SAR图像压缩感知/baboon.bmp , 66616 SAR图像压缩感知/camera.bmp , 66616 SAR图像压缩感知/DWT.m , 1265 SAR图像压缩感知/Gauss.m , 373 SAR图像…...
定时器设计
定时器设计的必要性 服务器中的定时器设计具有多方面的必要性,主要体现在以下几个关键方面: 任务调度与管理 定时任务执行:服务器常常需要执行一些定时性的任务,如定时备份数据、定时清理缓存、定时更新系统日志等。通过定时器可…...
Spring Boot整合Kafka实战指南:从环境搭建到消息处理全解析
一、环境准备 安装 Kafka 下载 Kafka:从 Apache Kafka 官网下载对应版本的 Kafka。 解压并启动 Kafka: # 启动 Zookeeper(Kafka 依赖 Zookeeper) bin/zookeeper-server-start.sh config/zookeeper.properties# 启动 Kafka bin/ka…...
(done) 补充:xv6 的一个用户程序 init 是怎么启动的 ?它如何启动第一个 bash ?
先看 main.c 从函数名来看,比较相关的就 userinit() 和 scheduler() #include "types.h" #include "param.h" #include "memlayout.h" #include "riscv.h" #include "defs.h"volatile static int started 0;//…...
AI 搜索引擎 MindSearch
背景 RAG是一种利用文档减少大模型的幻觉,AI搜索也是 AI 搜索引擎 MindSearch 是一个开源的 AI 搜索引擎框架,具有与 Perplexity.ai Pro 相同的性能。您可以轻松部署它来构建您自己的搜索引擎,可以使用闭源 LLM(如 GPT、Claude…...
HTML简单语法标签(后续实操:云备份项目)
以下是一些 HTML 的简单语法标签及其功能介绍: 基本结构标签 <!DOCTYPE html>:声明文档类型为 HTML5<html>:HTML 文档的根标签<head>:包含文档元数据(如标题、字符编码等)<title>…...
CentOS 和 RHEL
CentOS 和 RHEL(Red Hat Enterprise Linux)关系非常紧密,简而言之: CentOS 最初是 RHEL 的免费、开源克隆版,几乎与 RHEL 二进制兼容。 CentOS 原是 RHEL 的“免费双胞胎”,但已被放弃,现在推荐…...
java----------->代理模式
目录 什么是代理模式? 为什么会有代理模式? 怎么写代理模式? 实现代理模式总共需要三步: 什么是代理模式? 代理模式:给目标对象提供一个代理对象,并且由代理对象控制目标对象的引用 代理就是…...
Wpf学习片段
IRegionManager 和IContainerExtension IRegionManager 是 Prism 框架中用于管理 UI 区域(Regions)的核心接口,它实现了模块化应用中视图(Views)的动态加载、导航和生命周期管理。 IContainerExtension 是依赖注入&…...
智能手表测试用例文档
智能手表测试用例文档 产品名称:智能手表 A1 版本号:FW v1.0.0 测试负责人:[填写] 编写时间:2025-xx-xx 文档状态:初次版本 📁 测试用例结构说明 字段描述用例编号测试用例唯一编号,如 TC-FUN…...
密码学--希尔密码
一、实验目的 1、通过实现简单的古典密码算法,理解密码学的相关概念 2、理解明文、密文、加密密钥、解密密钥、加密算法、解密算法、流密码与分组密码等。 二、实验内容 1、题目内容描述 ①定义分组字符长度 ②随机生成加密密钥,并验证密钥的可行性 …...
配置Hadoop集群-集群配置
以下是 Hadoop 集群的核心配置步骤,基于之前的免密登录和文件同步基础,完成 Hadoop 分布式环境的搭建: 1. 集群规划 假设集群包含 3 个节点: master:NameNode、ResourceManagerslave1:DataNode、NodeMana…...
第三方软件测评中心分享:软件功能测试类型和测试工具
在数字化时代,软件测试已成为确保产品质量的重要环节。功能测试作为软件测试中的核心部分,关注于软件产品是否按预期功能正常运作。 软件功能测试可以按不同的方式进行分类,主要包括以下几种类型: 1.正功能测试:验…...
Profibus DP主站与Modbus RTU/TCP网关与海仕达变频器轻松实现数据交互
Profibus DP主站与Modbus RTU/TCP网关与海仕达变频器轻松实现数据交互 Profibus DP主站转Modbus RTU/TCP(XD-MDPBm20)网关在Profibus总线侧实现主站功能,在Modbus串口侧实现从站功能。可将ProfibusDP协议的设备(如:海…...
多视角系统,视角之间的切换,输入操作。无人机Pawn视角的实现
一.创建自己的PlayerController。它相当于是灵魂,穿梭在不同Pawn之间。也即是切换视角。不同输入的响应也写在这里。这样即使,都有鼠标操作,也能区分。避免了代码的重复耦合。也可以叫做视角系统。 class LZJGAMEMODE_API ALZJPlayerControl…...
[学习]RTKLib详解:ionex.c、options.c与preceph.c
RTKLib详解:ionex.c、options.c与preceph.c 本文是 RTKLlib详解 系列文章的一篇,目前该系列文章还在持续总结写作中,以发表的如下,有兴趣的可以翻阅。 [学习] RTKlib详解:功能、工具与源码结构解析 [学习]RTKLib详解&…...
【Linux笔记】——进程信号的保存
🔥个人主页🔥:孤寂大仙V 🌈收录专栏🌈:Linux 🌹往期回顾🌹:【Linux笔记】——进程信号的产生 🔖流水不争,争的是滔滔不 一、信号的相关概念二、信…...
教育机构教务管理系统哪个好?
在当今教育培训行业快速发展的背景下,一个高效、专业的教务管理系统已成为教育机构提升运营效率、优化教学质量的关键工具。本文将深入分析爱耕云教务管理系统的核心优势,通过具体功能解析和代码示例展示其技术实现方式,并对比市场上其他主流…...
ZYNQ笔记(二十):Clocking Wizard 动态配置
版本:Vivado2020.2(Vitis) 任务:ZYNQ PS端 通过 AXI4Lite 接口配置 Clocking Wizard IP核输出时钟频率 目录 一、介绍 二、寄存器定义 三、配置 四、PS端代码 一、介绍 Xilinx 的 Clock Wizard IP核 用于在 FPGA 中生成和管理…...
电商平台一站式网络安全架构设计指南
摘要:据 Gartner 统计,采用一体化安全方案的电商企业数据泄露成本降低 67%。本文从攻击链分析到防御体系构建,详解如何实现网络层、应用层、数据层的协同防护。 一、电商安全威胁全景图(2024 攻击态势) 1.1 攻击者完…...
烟花爆竹储存需要注意哪些问题
烟花爆竹储存需要注意哪些问题 烟花爆竹作为易燃易爆物品,其储存安全至关重要。不当的储存方式不仅可能导致产品失效,更可能引发火灾、爆炸等严重事故。以下是烟花爆竹储存需要注意的几个关键问题: 一、储存场所选择 必须选择专用仓库储存…...
C++11详解
文章目录 前言一、列表初始化1.1 {} 初始化1.2 initializer_list 类型 三、声明3.1 auto3.2 decltype 四、右值引用和移动语义4.1 左值引用和右值引用4.2 移动语义 五、可变参数模板六、lambda表达式各部分详细解释示例代码代码解释 七、包装器八、bind注意事项 前言 C11在系统…...
VLM-RL:用于安全自动驾驶的统一视觉语言模型和强化学习框架——论文阅读
《VLM-RL: A Unified Vision Language Models and Reinforcement Learning Framework for Safe Autonomous Driving》2024年12月发表,来自Wisconsin Madison分校和Purdue大学的论文。 近年来,基于强化学习(RL)的学习驾驶策略的方法…...
新手安装java所有工具(jdk、idea,Maven,数据库)
新手安装JAVA工具 介绍JDK11IDEA 2025.1Maven数据库(Navicat Premium Lite) 介绍 涉及安装JAVA所需的各种工具 JDK(以JDK11为例)IDEA(以2025.1为例)Maven(以3.8.8为例)数据库&…...
hive在配置文件中添加了hive.metastore.uris之后进入hive输入命令报错
在hive-site.xml文件中加入配置hive.metastore.uris启动hive后报错 <property><name>hive.metastore.uris</name><value>thrift://node154:9083</value></property> 加完属性就需要手动启动metastore服务,因为不使用 Zookeepe…...
Hive原理
Hive 是构建在 Hadoop 上的数据仓库工具,其核心原理是通过类 SQL 语言(HiveQL)将结构化数据查询转换为分布式计算任务(如 MapReduce、Tez、Spark),并利用 HDFS 存储数据。以下是 Hive 的核心原理和架构: 1. 核心设计思想 数据仓库抽象:将 HDFS 上的文件抽象为…...
cursor 出现 unauthorized request
文档出自:https://www.kdocs.cn/l/csE3iuSauHoS...
uniapp|商品列表加入购物车实现抛物线动画效果、上下左右抛入、多端兼容(H5、APP、微信小程序)
以uniapp框架为基础,详细解析商品列表加入购物车抛物线动画的实现方案。通过动态获取商品点击位置与购物车坐标,结合CSS过渡动画模拟抛物线轨迹,实现从商品图到购物车图标的动态效果。 目录 核心实现原理坐标动态计算抛物线轨迹模拟动画元素控制代码实现详解模板层设计脚本…...
点下4个Winform UI开源控件库
从零学习构建一个完整的系统 今天一起来盘点下4个Winform UI开源控件库,有.Net Framework,也有.Net Core。 1、支持.Net 7的开源UI组件框架 项目简介 这是一个基于.Net Framework、.Net 6开发的,WinForm开源UI框架,框架包含常…...
【AI】mcp server本质就是一个接口服务么
以下为元宝的回答: 你的理解非常准确!MCP Server本质上是一个接口服务,但其设计目标、交互逻辑和使用场景与传统后端接口存在显著差异。以下是两者的对比分析: 1. 核心定位差异 维度MCP Server…...