binglu’s blog
← 返回文章
大模型与深度学习

CNN 卷积神经网络

冰露3 分钟

在最基础的神经网络中,常见的连接方式是全连接层,即上一层的每一个神经元都与下一层的每一个神经元相连。然而这种方式在处理图像时存在明显局限。首先,它需要将图像展平成一维向量,导致参数量极其庞大,计算开销巨大;其次,它无法保留图像的空间结构,一个像素点位置或亮度的轻微变化,往往会被视作完全不同的输入。为了解决这些问题,卷积层被提出。卷积层通过“局部感受野“和”参数共享”的方式,大幅降低了计算复杂度,同时更好地捕捉图像中的局部特征与空间关系,从而在图像领域展现出更强的表现力。

基础神经网络模型

经典的神经网络数学表达式为:

y = g(wx + b)

其中:

  • w:权重
  • x:输入
  • b:偏置
  • g:激活函数

卷积神经网络层级结构

典型的 CNN 架构包含以下几个核心层:

文章配图

输入层 → 卷积层 → 池化层 → 全连接层 → 输出层

为什么需要卷积层?

文章配图

全连接层的局限性

在传统的全连接神经网络中:

  • 每个神经元都与上一层的所有神经元相连

  • 这种连接方式在处理图像时存在明显问题:

    • 参数量庞大:一张简单的图像就需要大量的连接参数
    • 计算开销巨大:即使像素点发生微小变化(轻微变暗或移位),也需要重新计算所有连接
    • 无法有效捕获空间关系:忽略了图像中像素的空间相关性

卷积层的优势

卷积层通过以下方式解决了上述问题:

  1. 局部连接

    • 使用卷积核(通常为 3×3 大小)与图像局部区域进行矩阵运算
    • 卷积核在整个图像上滑动,进行卷积运算
  2. 参数共享

    • 同一个卷积核在不同位置共享参数
    • 大大减少了需要训练的参数数量
  3. 特征提取能力强

    • 更容易捕获图像的局部特征(如边缘、纹理等)
    • 对图像的小幅平移、旋转具有一定的鲁棒性

池化层的作用

池化层位于卷积层之后,主要功能包括:

  • 降维处理:减少特征图的空间尺寸
  • 减少计算量:降低后续层的计算负担
  • 保留重要特征:在降维的同时保持关键信息
  • 增强鲁棒性:对输入的小幅变化更加稳定

示例代码:

# mnist7_torch.py
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np

# 1. 超参数
BATCH_SIZE = 64
EPOCHS     = 10
DEVICE     = 'cuda' if torch.cuda.is_available() else 'cpu'

# 2. 数据加载
transform = transforms.Compose([
    transforms.ToTensor(),            # [0,1]
])

train_ds = datasets.MNIST(root='.', train=True,  download=True, transform=transform)
test_ds  = datasets.MNIST(root='.', train=False, download=True, transform=transform)

train_loader = DataLoader(train_ds, batch_size=BATCH_SIZE, shuffle=True)
test_loader  = DataLoader(test_ds,  batch_size=BATCH_SIZE)

# 3. 网络结构:卷积 → 池化 → 全连接
class CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv = nn.Conv2d(1, 32, kernel_size=3, padding=1)   # 28x28 → 28x28
        self.pool = nn.MaxPool2d(2)                              # 28x28 → 14x14
        self.fc1  = nn.Linear(32 * 14 * 14, 128)
        self.fc2  = nn.Linear(128, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv(x)))   # (B,32,14,14)
        x = torch.flatten(x, 1)               # (B,6272)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = CNN().to(DEVICE)

# 4. 训练
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()

for epoch in range(1, EPOCHS+1):
    model.train()
    for x, y in train_loader:
        x, y = x.to(DEVICE), y.to(DEVICE)
        optimizer.zero_grad()
        out = model(x)
        loss = criterion(out, y)
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch:2d}/{EPOCHS}  loss={loss.item():.4f}')

# 5. 保存 & 加载
torch.save(model.state_dict(), 'mnist_cnn.pt')
model.load_state_dict(torch.load('mnist_cnn.pt', map_location=DEVICE))
model.eval()

# 6. 推理
def preprocess(path):
    img = Image.open(path).convert('L')
    img = img.resize((28, 28))
    img = transforms.ToTensor()(img)          # (1,28,28)
    img = img.unsqueeze(0)                    # (1,1,28,28)
    return img

# 从测试集里拿一张 7 做演示
# seven_idx = (test_ds.targets == 7).nonzero(as_tuple=True)[0][0]
# img_tensor = test_ds[seven_idx][0].unsqueeze(0)  # (1,1,28,28)

# 用自己的图片:
img_tensor = preprocess(r"C:\Users\86182\Desktop\sz.png")

with torch.no_grad():
    logits = model(img_tensor.to(DEVICE))
    probs  = torch.softmax(logits, dim=1)
    pred   = logits.argmax(1).item()

print('预测结果:', pred)
print('概率分布:', probs.cpu().numpy())

# 7. 可视化
plt.imshow(img_tensor[0,0], cmap='gray')
plt.title(f'Predicted: {pred}')
plt.axis('off')
plt.show()

文章配图

可以看到,当前已能够正确识别出了数字 7

总结

卷积神经网络通过引入卷积层和池化层,相比传统全连接网络:

  • ✅ 显著减少了参数量
  • ✅ 降低了计算复杂度
  • ✅ 提高了对图像特征的提取能力
  • ✅ 增强了模型的泛化能力

这种设计使得 CNN 特别适合处理图像等具有空间结构的数据。

当然了,CNN 固然好用,却也并不能适配所有场景,比如,语义理解、问答任务。由于缺乏对复杂语义关系的深度建模能力,因此在需要精准理解、推理和生成自然语言的问答场景中,往往力不从心。

关于 CNN 呢,我找到一个可以可视化展示的网站,感兴趣的朋友可以去体验一下

文章配图

链接如下:

https://poloclub.github.io/cnn-explainer/#article-input