它通过模拟生物视觉皮层的机制,自动提取数据中的局部特征,并通过层级结构组合成更高层次的抽象表达,极大地提升了图像识别、目标检测、语音识别等领域的性能。

快速学会一个算法,CNN!!_卷积

核心思想

传统的神经网络在处理图像时,通常会将图像的像素数据拉成一维向量,这会破坏图像的空间结构信息(比如像素之间的相对位置关系)。而 CNN 的核心思想在于,它模仿了人类视觉皮层的感知机制,能够自动、自适应地从图像数据中学习并提取层次化的特征,从低级的边缘、纹理到高级的物体部分、整体。

CNN 的主要特点包括

  • 局部感受野
    每个神经元只连接到输入数据的一个局部区域,而不是整个输入。这使得网络可以专注于学习局部模式。
  • 权值共享
    同一个特征检测器(即卷积核)在图像的不同区域滑动,共享相同的权重和偏置。
    这极大地减少了模型的参数数量,降低了过拟合的风险,并使模型具备了平移不变性(无论物体出现在图像的哪个位置,都能被识别)。
  • 池化操作
    通过下采样操作,减少特征图的维度,在保留重要信息的同时,降低计算量,并进一步增强模型的平移不变性。

卷积神经网络的基本组成

一个典型的 CNN 通常由以下几类层组成,它们相互配合,共同完成特征提取和分类任务。

  1. 卷积层:负责从输入数据中提取特征。
  2. 激活函数:通常紧跟在卷积层之后,引入非线性,增强网络的表达能力。
  3. 池化层:也称为下采样层,用于减小特征图的尺寸,从而减少参数,并使模型对特征的位置变化更具鲁棒性。
  4. 全连接层:在特征提取完成后,将学到的特征整合起来,用于最终的分类或回归任务。

这些层通常会以 "卷积层-激活函数-池化层" 的方式堆叠多次,以学习越来越抽象和高级的特征。

1.卷积层

卷积层是 CNN 的核心部分,它通过卷积操作来提取输入数据的局部特征。

卷积操作是利用一个小的矩阵(卷积核或滤波器)在输入图像上进行滑动扫描,并进行点积运算,从而提取图像的局部特征。

快速学会一个算法,CNN!!_卷积_02

我们可以把卷积核看作是一个“特征探测器”,比如一个卷积核专门用于检测垂直边缘,另一个用于检测水平边缘。通过多个不同的卷积核,我们可以提取出多种多样的特征。

参数

  • 卷积核大小:决定感受野大小,影响局部特征提取能力。
  • 输出通道数:决定卷积层输出的深度,影响特征多样性。
  • 步幅:卷积核在输入特征图上滑动的步长,影响输出尺寸。
  • 填充:是否在输入边缘补零,用于控制输出尺寸和保持边界信息。

2.激活函数

卷积操作是线性运算,为了让网络能够学习更复杂的非线性模式,我们需要在卷积层之后引入非线性激活函数。

常用激活函数

  1. ReLU
    它将所有负值都变为0,而正值保持不变。
  2. Sigmoid
  3. Tanh

快速学会一个算法,CNN!!_卷积核_03

3.池化层

池化层通常紧跟在激活函数之后。它的主要目的是降维,减少特征图的尺寸,从而减少网络的计算量和参数数量,并使模型对特征的微小平移具有鲁棒性。

最常见的两种池化方式是最大池化(Max Pooling)和平均池化(Average Pooling)。

  • 最大池化(Max Pooling):在窗口内选择最大值作为输出。这有助于保留最重要的特征,同时丢弃一些不那么重要的细节。
  • 平均池化(Average Pooling):在窗口内计算所有值的平均值作为输出。

快速学会一个算法,CNN!!_池化_04

4. 全连接层

在经过多层卷积和池化操作后,图像的特征已经被提取出来,并编码在一个高维的特征图中。

为了进行分类或回归任务,我们需要将这些特征展平成一个一维向量,然后输入到传统的全连接层中。

全连接层中的每个神经元都与上一层的所有神经元相连接,其工作方式与传统神经网络相同。它将最终提取出的特征作为输入,通过学习不同特征的权重,对它们进行组合,并最终进行分类或回归任务。

快速学会一个算法,CNN!!_卷积核_05

训练过程

CNN 的训练过程与传统神经网络类似,主要使用反向传播算法。

  1. 前向传播:输入数据从输入层开始,依次经过卷积、激活、池化和全连接层,得到最终的预测结果。
  2. 计算损失:将预测结果与真实标签进行比较,使用损失函数(如交叉熵损失)计算出误差。
  3. 反向传播:将误差从输出层向后传播,计算每个参数(卷积核的权重和偏置)对损失的梯度。
  4. 参数更新:使用梯度下降(Gradient Descent)等优化算法,根据梯度更新参数,以减小损失。

通过不断迭代,网络会逐渐学习到最佳的参数,从而实现对图像的高效识别和分类。

案例分享

下面是一个使用 PyTorch 框架实现的卷积神经网络算法(CNN)用于手写数字识别(MNIST数据集)的完整示例代码。

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt# 1. 数据准备
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))
])train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=1000, shuffle=False)# 2. 定义CNN模型
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()self.conv1 = nn.Conv2d(1, 32, kernel_size=5, padding=2)self.relu1 = nn.ReLU()self.pool1 = nn.MaxPool2d(2)self.conv2 = nn.Conv2d(32, 64, kernel_size=5, padding=2)self.relu2 = nn.ReLU()self.pool2 = nn.MaxPool2d(2)self.fc1 = nn.Linear(64 * 7 * 7, 1024)self.relu3 = nn.ReLU()self.fc2 = nn.Linear(1024, 10)def forward(self, x):x = self.pool1(self.relu1(self.conv1(x)))x = self.pool2(self.relu2(self.conv2(x)))x = x.view(x.size(0), -1)x = self.relu3(self.fc1(x))x = self.fc2(x)return xdevice = torch.device('cuda'if torch.cuda.is_available() else'cpu')
model = SimpleCNN().to(device)criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 3. 训练模型
num_epochs = 5
for epoch in range(num_epochs):model.train()running_loss = 0.0for images, labels in train_loader:images, labels = images.to(device), labels.to(device)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item() * images.size(0)epoch_loss = running_loss / len(train_loader.dataset)print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}')# 4. 测试并显示预测结果
model.eval()
correct = 0
total = 0
examples_to_show = 8
examples_shown = 0with torch.no_grad():for images, labels in test_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()for i in range(images.size(0)):if examples_shown >= examples_to_show:breakimg = images[i].cpu().numpy().squeeze()plt.subplot(2, 4, examples_shown + 1)plt.imshow(img, cmap='gray')plt.title(f'Pred: {predicted[i].item()}')plt.axis('off')examples_shown += 1if examples_shown >= examples_to_show:breakprint(f'Accuracy on the test set: {100 * correct / total:.2f}%')
plt.tight_layout()
plt.show()

快速学会一个算法,CNN!!_卷积核_06