LiteralliJeff 发表于 2023-2-6 19:03

卷积神经网络(CNN)简单原理与简单代码实现!

深度学习新手入门福利,本文将给你带来最简单的卷积神经网络理解与代码实现!


CNN(卷积神经网络)是一种用于图像识别和计算机视觉任务的深度学习算法。它基于卷积和池化操作,通过使用卷积核对图像进行扫描并进行特征提取,然后使用池化层降低图像的维度。这样的特征提取方式可以捕捉图像中的位置和形状信息。随后,这些特征会被平铺到全连接层,然后通过一系列的全连接层进行分类或回归。
CNN基本原理

卷积核(Convolutional Kernels)是一种矩阵,它在图像上进行卷积操作,从而提取出图像的特征。具体来说,卷积核沿着图像每一个部分进行扫描,将图像中对应的元素与卷积核中对应的元素相乘并相加。最后形成一个新的矩阵,这个矩阵中的每一个元素代表了原图像在对应区域内的特征值(见下图所示)。



卷积操作的简单理解(就是对应位置相乘相加)

在一次扫描中,无论图像本身有几个通道(例如RGB三通道/RGBA四通道),卷积核会扫描全部通道之后,将扫描结果加和为一张feature map(特征图),此时需要的卷积核数 = 通道数。in_channels是输入卷积层的图像的通道数或上一层传入特征图的数量,out_channels是指这一层输出的特征图的数量,这需要在模型架构中进行设定。然而,单次扫描对图像特征的提取时不够全面的,因此,需要多次扫描,多张特征图(out_channels)来实现对图像的全面表述。因此,在一个卷积层中,卷积核数量 = in_channels x 扫描次数out_channels。通过这种方式,我们就可以使用多个不同的卷积核来提取图像的不同特征。
自然地我们会想到,需要控制特征图的尺寸,而高效降低特征图尺寸的方法被称为池化,最常见的有三种:最大池化(Max Pooling)、平均池化(Average Pooling)、加和池化(Sum Pooling),见下图所示。



三种池化的简单理解

由于CNN可以在处理高维数据时自动学习特征,因此它特别适用于图像分类和识别任务。它在诸如图像分类、目标检测、语音识别等方面有着卓越的表现。
代码实现

下面是通过Pytorch构造一个简单的CNN,用于手写数字识别。虽然网络架构很简单,但是最终测试准确率可以达到98.5%左右(9868/10000),足够新手同学学习与使用!
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

# 加载MNIST数据集,将数据归一化到区间内
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])
#导入训练集和测试集
trainset = datasets.MNIST(root='./data', train=True,
                        transform=transform, download=True)
trainloader = DataLoader(trainset, batch_size=64, shuffle=True)
testset = datasets.MNIST(root='./data', train=False,
                         transform=transform, download=True)
testloader = DataLoader(testset, batch_size=64, shuffle=False)

# 定义卷积神经网络模型
# 需要在Conv2d处定义in_channels、out_channels、卷积核尺寸
# 在经过卷积处理以及两次池化之后,特征图尺寸变为4*4,因此全连接网络的输入神经元数量是4*4*20 = 320
class ConvNet(nn.Module):
    def __init__(self):
      super().__init__()
      self.conv1 = nn.Conv2d(1, 10, 5)
      self.pool = nn.MaxPool2d(2, 2)
      self.conv2 = nn.Conv2d(10, 20, 5)
      self.fc = nn.Linear(320, 10)
    def forward(self, x):
      x = self.pool(torch.relu(self.conv1(x)))
      x = self.pool(torch.relu(self.conv2(x)))
      x = x.view(-1, 320)
      x = self.fc(x)
      return x

# 初始化模型,损失函数和优化器
model = ConvNet()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

# 训练模型
for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(trainloader):
      inputs, labels = data
      optimizer.zero_grad()
      outputs = model(inputs)
      loss = criterion(outputs, labels)
      loss.backward()
      optimizer.step()
      running_loss += loss.item()
    print(f"Epoch: {epoch + 1}/10, Loss: {running_loss / len(trainloader)}")

# 测试模型
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
      images, labels = data
      outputs = model(images)
      _, predicted = torch.max(outputs.data, 1)
      total += labels.size(0)
      correct += (predicted == labels).sum().item()
print('\nTest set: Accuracy: {}/{} ({:.0f}%)\n'.format(
    correct, len(testloader.dataset),
    100. * correct / len(testloader.dataset)))结果也是非常的奈斯,测试集准确率高达98.68%(9868/10000),如下所示



模型结果

同学们快来跟着尝试一下吧。
码字不易,欢迎三连,关于代码若有问题请在评论区交流。
欢迎了解收藏我的机器学习专栏!点赞关注不迷路哦!

Mecanim 发表于 2023-2-6 19:07

感谢!!
页: [1]
查看完整版本: 卷积神经网络(CNN)简单原理与简单代码实现!