FA :Formulas and Algorithm,CNN:Convolutional Neural Network
1. 引言
卷积神经网络(CNN)是深度学习中最经典的网络结构之一,在图像分类、目标检测等领域有着广泛的应用。本文将从卷积的基本原理出发,结合 PyTorch 框架,手把手带你搭建一个简单的卷积层,并通过 CIFAR10 数据集进行实战演示,最后使用 TensorBoard 可视化卷积前后的图像变化。
2. 卷积原理
在开始写代码之前,我们先来理解卷积的核心概念。
2.1 什么是卷积
卷积操作本质上是一个特征提取的过程:通过一个可学习的卷积核(kernel)在输入数据上滑动,逐位置计算加权和,从而提取出局部特征。
2.2 一维、二维与三维卷积
PyTorch 中提供了三种常用的卷积类:
- Conv1d:一维卷积,常用于处理序列数据(如文本、音频、时间序列)。
- Conv2d:二维卷积,常用于处理图像数据,是本文的主角。
- Conv3d:三维卷积,常用于处理视频、医学影像等立体数据。
2.3 卷积核(kernel_size)
卷积核是卷积操作的核心参数。以 kernel_size=3 为例,它表示使用一个 3 × 3 的卷积核在图像上滑动。
在训练过程中,卷积核中的数值会通过反向传播不断调整优化,最终学习到能够提取有效特征的参数。可以说,训练神经网络的过程,本质上就是对卷积核参数不断调整的过程。
2.4 输入与输出的关系
卷积层的输出尺寸由输入尺寸、卷积核大小、步长(stride)和填充(padding)共同决定。在下面的实战中,我们将通过代码直观地看到输入输出尺寸的变化。
- Input: (N,Cin,Hin,Win)(N, C_{in}, H_{in}, W_{in})(N,Cin,Hin,Win)
- Output: (N,Cout,Hout,Wout)(N, C_{out}, H_{out}, W_{out})(N,Cout,Hout,Wout) where
Hout=⌊Hin+2×padding0−dilation0×(kernel_size0−1)−1stride0+1⌋ H_{out} = \left\lfloor \frac{H_{in} + 2 \times \text{padding}0 - \text{dilation}0 \times (\text{kernel\_size}0 - 1) - 1}{\text{stride}0} + 1 \right\rfloor Hout=⌊stride0Hin+2×padding0−dilation0×(kernel_size0−1)−1+1⌋
Wout=⌊Win+2×padding1−dilation1×(kernel_size1−1)−1stride1+1⌋ W_{out} = \left\lfloor \frac{W_{in} + 2 \times \text{padding}1 - \text{dilation}1 \times (\text{kernel\_size}1 - 1) - 1}{\text{stride}1} + 1 \right\rfloor Wout=⌊stride1Win+2×padding1−dilation1×(kernel_size1−1)−1+1⌋
3. 搭建卷积层
下面我们使用 PyTorch 搭建一个简单的卷积神经网络模型。
3.1 导入依赖
python
import torch
from torch import nn
import torchvision
from torch.nn import Conv2d
from torch.utils.data import DataLoader
3.2 加载 CIFAR10 数据集
python
dataset = torchvision.datasets.CIFAR10(
"./dataset",
train=False,
transform=torchvision.transforms.ToTensor(),
download=True
)
dataloader = DataLoader(dataset, batch_size=64)
3.3 定义卷积网络模型
python
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
# 彩色图像输入为 3 层,我们想让它的输出为 6 层,选用 3 * 3 的卷积核
self.conv1 = Conv2d(
in_channels=3,
out_channels=6,
kernel_size=3,
stride=1,
padding=0
)
def forward(self, x):
x = self.conv1(x)
return x
3.4 实例化模型并查看结构
python
tudui = Tudui()
print(tudui)
运行结果:
text
Files already downloaded and verified
Tudui(
(conv1): Conv2d(3, 6, kernel_size=(3, 3), stride=(1, 1))
)
可以看到,模型包含一个 Conv2d 卷积层,输入通道为 3,输出通道为 6,卷积核大小为 3 × 3。
4. 卷积层处理图片
接下来,我们让卷积层真正处理一批图片,观察输入和输出的尺寸变化。
python
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10(
"./dataset",
train=False,
transform=torchvision.transforms.ToTensor(),
download=True
)
dataloader = DataLoader(dataset, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
# 彩色图像输入为 3 层,我们想让它的输出为 6 层,选用 3 * 3 的卷积核
self.conv1 = Conv2d(
in_channels=3,
out_channels=6,
kernel_size=3,
stride=1,
padding=0
)
def forward(self, x):
x = self.conv1(x)
return x
tudui = Tudui()
for data in dataloader:
imgs, targets = data
output = tudui(imgs)
print(imgs.shape) # 输入为 3 通道 32×32 的 64 张图片
print(output.shape) # 输出为 6 通道 30×30 的 64 张图片
运行结果(节选):
text
Files already downloaded and verified
torch.Size([64, 3, 32, 32])
torch.Size([64, 6, 30, 30])
torch.Size([64, 3, 32, 32])
torch.Size([64, 6, 30, 30])
torch.Size([64, 3, 32, 32])
torch.Size([64, 6, 30, 30])
...
4.1 结果分析
从输出结果可以清晰地看到:
- 输入 :
[64, 3, 32, 32],表示 64 张32 × 32的彩色图片(3 通道)。 - 输出 :
[64, 6, 30, 30],表示 64 张30 × 30的图片,通道数变为 6。
这是因为卷积核大小为 3 × 3、步长为 1、无填充,导致图像尺寸从 32 × 32 缩小为 30 × 30;同时输出通道数由 3 变为 6,实现了特征的提取与升维。
5. TensorBoard 可视化
为了更直观地观察卷积前后的变化,我们使用 TensorBoard 将输入图像和卷积后的输出图像可视化。


5.1 完整代码
python
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10(
"./dataset",
train=False,
transform=torchvision.transforms.ToTensor(),
download=True
)
dataloader = DataLoader(dataset, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
# 彩色图像输入为 3 层,我们想让它的输出为 6 层,选用 3 * 3 的卷积核
self.conv1 = Conv2d(
in_channels=3,
out_channels=6,
kernel_size=3,
stride=1,
padding=0
)
def forward(self, x):
x = self.conv1(x)
return x
tudui = Tudui()
writer = SummaryWriter("logs")
step = 0
for data in dataloader:
imgs, targets = data
output = tudui(imgs)
print(imgs.shape)
print(output.shape)
writer.add_images("input", imgs, step)
# 把原来 6 个通道拉为 3 个通道,为了保证所有维度总数不变,其余的分量分到第一个维度中
output = torch.reshape(output, (-1, 3, 30, 30))
writer.add_images("output", output, step)
step = step + 1
5.2 启动 TensorBoard
在 Anaconda 终端中,激活对应的 Python 环境(如 py3.6.3),然后输入以下命令:
bash
tensorboard --logdir=C:\Users\wangy\Desktop\03CV\logs
将输出的网址复制到浏览器地址栏并回车,即可查看 TensorBoard 中卷积前后的图像对比。
6. 总结
本文从卷积的基本原理出发,完成了以下内容:
- 理解了 Conv1d / Conv2d / Conv3d 的区别与适用场景。
- 掌握了 kernel_size 的含义及其在训练中的动态调整机制。
- 使用 PyTorch 搭建了包含
Conv2d的简单网络模型。 - 通过 CIFAR10 数据集实战,直观看到了卷积前后输入输出尺寸的变化。
- 使用 TensorBoard 可视化卷积前后的图像,加深对卷积特征提取的理解。
卷积层是构建更复杂 CNN(如 LeNet、VGG、ResNet 等)的基础模块。掌握了本文的内容,你就迈出了深度学习图像处理的第一步。接下来可以尝试调整 kernel_size、stride、padding 等参数,观察输出尺寸的变化,进一步加深理解。