CNN卷积神经网络之基础(一)



卷积神经网络(CNN)入门:从原理到代码

卷积神经网络(Convolutional Neural Network, CNN)是深度学习中最常用的模型之一,尤其在图像识别、目标检测等任务中表现优异。本文将带你从基础概念出发,理解 CNN 的核心机制,并通过 PyTorch 代码实现一个可运行的卷积操作案例。


一、为什么需要 CNN?

传统的全连接神经网络(Fully Connected Network)在处理图像时会遇到两个问题:

  • 参数量巨大:一张 224×224 的图像,若使用全连接层,参数量将爆炸。
  • 无法提取局部特征:图像中的物体具有平移、缩放、旋转不变性,全连接层难以捕捉这些特征。

CNN 通过以下三个特性解决了上述问题:

特性描述
局部连接每个神经元只连接输入图像的局部区域,减少参数量
权重共享同一个卷积核在图像上滑动,使用相同权重,进一步减少参数并提取平移不变特征
池化通过下采样保留主要特征,增强模型对位置变化的鲁棒性

二、核心组件详解

1. 卷积操作(Convolution)

卷积的本质是:用一个可学习的滤波器(卷积核)在图像上滑动,进行加权求和,生成特征图(Feature Map)。
在这里插入图片描述

代码示例:使用 PyTorch 实现二维卷积
import torch
import torch.nn as nn

# 输入图像(单通道 3x3)
input_matrix = torch.tensor([
    [1., 2., 3.],
    [4., 5., 6.],
    [7., 8., 9.]
], dtype=torch.float32)

# 卷积核(2x2)
kernel = torch.tensor([
    [0., 1.],
    [2., 3.]
], dtype=torch.float32)

# 转换为4维张量 (batch_size, channels, height, width)
input_tensor = input_matrix.view(1, 1, 3, 3)

# 创建卷积层
conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=2, bias=False)
conv.weight.data = kernel.view(1, 1, 2, 2)

# 执行卷积
output = conv(input_tensor).squeeze().detach()
print("卷积结果:\n", output)

输出结果:

卷积结果:
tensor([[ 11., 16.],
		[ 26., 31.]])

2. 步长(Stride)与填充(Padding)

  • 步长(stride):控制卷积核每次移动的像素数,影响输出特征图大小。
    举例说明:
    假设有一个大小为5×5的输入图像(为了简化问题,不考虑颜色通道等复杂情况),而卷积核的大小是3×3。
    如果步长设置为1,那么卷积核就从左上角开始,每次向右移动1个单位,当到达图像边缘后,向下移动1个单位,继续向右扫描。这样在横向和纵向都会有很多重叠的计算区域,最终得到的输出特征图尺寸较大,会得到一个3×3的矩阵,可以捕捉到更密集的空间细节。
    若步长设置为2,则卷积核在每次移动时会跳过1个单位(因为步长是2),这样输出特征图的尺寸就会减小,会得到一个2×2的矩阵,计算量也会相应减少。较大的步长容易导致特征图中信息的稀疏,但可以有效降低模型的复杂度。

  • 填充(padding):在图像边缘补零,保持输出尺寸与输入一致。
    举例说明:
    假设我们有一张 5×5 的图像(简化为黑白图像,忽略颜色通道)。当我们使用一个 3×3 的卷积核进行卷积操作,并且步长为 1 时,如果没有 padding,输出的特征图尺寸就会变成 3×3。这是因为卷积核只能完全覆盖在原始图像的范围内进行计算。
    加齐边缘的作用:如果在原始图像的四周添加一层零填充(padding 的大小设为 1),那么整个图像的尺寸就变成了 7×7(5+2×1)。此时,3×3 的卷积核仍然使用步长 1 进行计算,输出的特征图尺寸就会回到 5×5。这样就能确保输出的特征图在尺寸上与输入图像保持一致,从而便于后续的处理和分析。
    在这里插入图片描述
    在这里插入图片描述
示例:计算输出特征图大小
import torch.nn as nn

# 输入:5x5 图像
input = torch.randn(1, 1, 5, 5)

# 卷积层:3x3 卷积核,步长1,填充0
conv = nn.Conv2d(1, 1, kernel_size=3, stride=1, padding=0)
output = conv(input)
print("输出特征图尺寸:", output.shape)

输出:

输出特征图尺寸: torch.Size([1, 1, 3, 3])

若设置 padding=1,则输出尺寸将恢复为 5×5。


3. 池化(Pooling)

池化层用于下采样,常用的是 最大池化(Max Pooling),保留区域内最大值。

import torch.nn as nn

# 输入:4x4 特征图
input = torch.tensor([[[[1, 2, 3, 4],
                        [5, 6, 7, 8],
                        [9, 10, 11, 12],
                        [13, 14, 15, 16]]]], dtype=torch.float32)

# 最大池化:2x2 池化核
pool = nn.MaxPool2d(kernel_size=2, stride=2)
output = pool(input)
print("池化后结果:\n", output.squeeze())

输出:

池化后结果:
 tensor([[ 6.,  8.],
         [14., 16.]])

三、完整案例:构建一个简单的 CNN 模块

下面是一个完整的 CNN 模块,包含卷积、ReLU 激活和最大池化:

import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv = nn.Conv2d(1, 8, kernel_size=3, padding=1)
        self.relu = nn.ReLU()
        self.pool = nn.MaxPool2d(2)

    def forward(self, x):
        x = self.conv(x)
        x = self.relu(x)
        x = self.pool(x)
        return x

# 测试
model = SimpleCNN()
input = torch.randn(1, 1, 28, 28)
output = model(input)
print("输出形状:", output.shape)

输出:

输出形状: torch.Size([1, 8, 14, 14])

四、总结

模块作用
卷积提取局部特征,减少参数量
激活函数引入非线性,提升表达能力
池化降维、增强鲁棒性
全连接层最终分类或回归输出(可选)

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐