4.4 神经网络与 CNN

打开深度学习的大门

image-20260331170612103

在前面的章节中,我们看到传统的计算机视觉方法在现实世界中常常会失败。它们的成功通常依赖于场景符合特定模式或一组假设,例如稳定的光照、干净的背景、固定的视角或可预测的物体形状。一旦这些条件发生变化,性能可能会迅速下降。然而,深度学习采取了一种非常不同的方法。它不再主要依赖人工设计的规则,而是直接从大量数据中学习有用的视觉模式。这使它能够处理外观、背景、尺度、光照和姿态上更大的变化。因此,深度学习使计算机视觉在真实世界应用中变得更加鲁棒和实用。

从规则到学习到的表示

在经典视觉中,我们显式地编写规则:

  • 模糊图像
  • 找到边缘
  • 提取轮廓

而在神经网络中,我们让模型从样例中学习有用的模式。

这是关键的概念转变:系统学习表示,而不是仅仅依赖人工设计的特征。

什么是神经网络

image-20260401094617887

神经网络是由若干层组成的函数,这些层逐步对输入数据进行变换。

每一层都会学习参数。在训练期间,会调整这些参数,使网络的输出对该任务更加有用。

神经网络在代码中是什么样子?

python
import torch
import torch.nn as nn
import torch.nn.functional as F

# 1. Define the Network Structure
class SimpleMLP(nn.Module):
    def __init__(self, input_size=784, hidden_size=128, num_classes=10):
        super(SimpleMLP, self).__init__()
        
        # --- Fully Connected Layers (Dense Layers) ---
        
        # First layer: Maps input features to the first hidden layer
        self.fc1 = nn.Linear(input_size, hidden_size)
        
        # Second layer: Maps first hidden layer to the second hidden layer
        self.fc2 = nn.Linear(hidden_size, 64)
        
        # Output layer: Maps second hidden layer to the number of classes
        self.fc3 = nn.Linear(64, num_classes)
        
        # Optional: Dropout layer to prevent overfitting (drops 20% of neurons)
        self.dropout = nn.Dropout(p=0.2)

    # 2. Define the Data Flow (Forward Pass)
    def forward(self, x):
        # Flatten the input tensor
        # Converts (batch_size, channels, height, width) to (batch_size, -1)
        # Example: 28x28 image becomes a 784-dimensional vector
        x = x.view(x.size(0), -1)  
        
        # First hidden layer: Linear transformation -> ReLU Activation -> Dropout
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        
        # Second hidden layer: Linear transformation -> ReLU Activation
        x = F.relu(self.fc2(x))
        
        # Output layer: Linear transformation (no activation here, usually handled by loss function)
        x = self.fc3(x)
        
        return x

# 3. Instantiate the Model
model = SimpleMLP()
print(model)

试一试

bash
cd 4.4-Neural-Networks-and-CNNs/code
python powerful_neural_network.py

🚀 训练你自己的神经网络,看看它的表现如何!

nn

为什么 CNN 适合处理图像

CNN(卷积神经网络)之所以适合图像,是因为图像并不是随机的数字。在一张图像中,相邻的像素通常属于同一个边缘、形状或纹理,因此局部模式非常重要。CNN 利用这一点,通过使用在图像上扫描的小滤波器来寻找有用的特征,例如边缘、角点和简单的形状。随着网络变得更深,它将这些小特征组合成更大的特征,比如物体的部件,最终是整个物体本身。这就是为什么 CNN 在高效准确地理解图像方面尤其出色。

Input Shape : (1, 9, 9) - Output Shape : (1, 7, 7) - K : (3, 3) - P : (0, 0) - S : (1, 1) - D : (1, 1) - G : 1.gif

CNN 通常具有分层结构,将图像转化为更高层次的视觉理解。它从一张输入图像开始,然后通过若干卷积层学习诸如边缘、纹理和形状等局部模式。这些层之后通常跟随像 ReLU 这样的激活函数池化层,在保留重要信息的同时缩小空间尺寸。在若干这样的模块之后,特征图会被展平或被池化为紧凑的表示,并传入一个或多个全连接层以产生最终预测,例如类别标签。简而言之,常见的 CNN 结构看起来像:

输入 → 卷积 + 激活 → 池化 → 重复的特征提取模块 → 全连接层 → 输出

image-20260401175822373

卷积的优点:

  • 局部模式提取

卷积帮助模型在图像中找到小而有用的模式,例如边缘、角点、纹理或简单形状。这些小模式是理解更大物体的基本构建块。

image-20260401150136006

  • 参数共享

同一个滤波器会作用于图像的不同位置。这意味着模型不需要为每个位置学习一组新的权重,从而更高效,并减少了参数数量。

  • 平移鲁棒性

如果物体移动到图像中的另一个位置,卷积滤波器仍然能够检测到它。换句话说,模型即使在位置变化时仍能识别相同的模式。

特征图

当卷积层处理图像时,会产生特征图。这些特征图响应诸如以下模式:

  • 边缘
  • 角点
  • 纹理
  • 在更深的层中响应更大的语义结构

image-20260401100245367

池化与下采样

池化在保留重要信息的同时减小空间尺寸。

image-20260401103259828 image-20260401104155947

这有助于:

  • 减少计算量
  • 提高鲁棒性
  • 构建更紧凑的表示

试一试

bash
cd 4.4-Neural-Networks-and-CNNs/code
python cnn_process_visualization.py

🚀 运行脚本,体验卷积网络对图像的处理过程。

conv

训练与推理

  • Training:模型通过更新权重来学习
  • Inference:训练好的模型在不更新权重的情况下进行预测

这一区别至关重要,因为后续的部署章节主要聚焦于推理。

CNN 在代码中是什么样子?

python
mport torch
import torch.nn as nn

class TinyCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(32 * 56 * 56, 64),
            nn.ReLU(),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x

model = TinyCNN()
dummy = torch.randn(1, 3, 224, 224)
output = model(dummy)
print(output.shape)

常见误解

  • "CNN 字面上就像人眼一样观察。"
    • CNN 处理的是数值模式。这种类比有助理解,但并非字面意义上的相同。
  • "层数越多性能越好。"
    • 更深的模型可能更强大,但也更难训练和部署。
  • "如果我看懂了代码,就自动理解了训练。"
    • 训练还依赖于数据、损失函数、优化和评估。

练习 / 反思

  1. 用你自己的话解释为什么卷积比纯全连接层更适合处理图像。
  2. 运行 tiny CNN 示例并打印输出形状。
  3. 改变第一个卷积层的输出通道数,并观察模型结构如何变化。
  4. 反思 CNN 与诸如模糊或边缘检测之类的经典滤波器有何不同。

总结

神经网络从数据中学习表示,而 CNN 因为利用了局部结构,在图像方面尤其有效。理解卷积、特征图、池化以及训练与推理的区别,能为学习者迎接现代视觉任务做好准备。

建议下一步

继续学习 4.5 深度学习计算机视觉任务

参考资料