【深度学习】基于代码一步一步教你深度学习中卷积神经网络(CNN)的原理-CSDN博客

53 阅读7分钟

当谈到基于CNN的深度学习例子时,图像分类是最常见的任务之一。CNN(卷积神经网络)在图像处理任务中表现出色,能够自动学习图像的特征表示。以下是一个基于CNN的图像分类示例,并给每一行添加了注释:

**

  
  
import torchimport torch.nn as nnimport torch.optim as optimimport torchvisionimport torchvision.transforms as transforms # 设置随机种子,以便结果可复现torch.manual_seed(42) # 加载并预处理数据集transform = transforms.Compose([    transforms.ToTensor(),                             # 将图像转换为张量    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 归一化]) trainset = torchvision.datasets.CIFAR10(root=‘./data’, train=True, download=True, transform=transform)trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=2) testset = torchvision.datasets.CIFAR10(root=‘./data’, train=False, download=True, transform=transform)testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False, num_workers=2) # 定义CNN模型class CNN(nn.Module):    def init(self):        super(CNN, self).init()        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)  # 输入通道数为3,输出通道数为16,卷积核大小为3,步长为1,填充为1        self.relu = nn.ReLU()                                          # ReLU激活函数        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)               # 最大池化层,池化核大小为2,步长为2        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)  # 输入通道数为16,输出通道数为32,卷积核大小为3,步长为1,填充为1        self.fc1 = nn.Linear(32  8  8, 128)                            # 全连接层,输入大小为3288,输出大小为128        self.fc2 = nn.Linear(128, 10)                                    # 全连接层,输入大小为128,输出大小为10(类别数)     def forward(self, x):        x = self.relu(self.conv1(x))        x = self.pool(x)        x = self.relu(self.conv2(x))        x = self.pool(x)        x = x.view(x.size(0), -1)        x = self.relu(self.fc1(x))        x = self.fc2(x)        return x # 实例化模型和损失函数net = CNN()criterion = nn.CrossEntropyLoss()                          # 交叉熵损失函数optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  # 随机梯度下降优化器 # 训练模型for epoch in range(10):  # 进行10个epoch的训练    running_loss = 0.0    for i, data in enumerate(trainloader, 0):        inputs, labels = data        optimizer.zero_grad()                # 前向传播、反向传播、优化        outputs = net(inputs)        loss = criterion(outputs, labels)        loss.backward()        optimizer.step()                running_loss += loss.item()        if i % 2000  1999:            print(f‘[{epoch + 1}, {i + 1}] loss: {running_loss / 2000:.3f}’)            running_loss = 0.0 print(‘Finished training’) # 在测试集上评估模型correct = 0total = 0with torch.no_grad():    for data in testloader:        images, labels = data        outputs = net(images)        _, predicted = torch.max(outputs.data, 1)  # 获取每个样本预测的类别索引        total += labels.size(0)        correct += (predicted  labels).sum().item() print(f‘Accuracy on the test set: {100 * correct / total:.2f}%’)

在这个例子中,我们使用了PyTorch来构建和训练一个简单的CNN模型进行CIFAR-10图像分类任务。

首先,我们使用torchvision模块加载CIFAR-10数据集,并进行了预处理(将图像转换为张量并进行归一化)。

然后,我们定义了一个简单的CNN模型。该模型由两个卷积层(带有ReLU激活函数和池化操作)和两个全连接层组成。

接下来,我们实例化了损失函数(交叉熵损失)和优化器(随机梯度下降)。

然后,我们使用训练集进行模型训练。在每个epoch中,我们通过前向传播计算输出、计算损失、反向传播和优化来更新模型的参数。

最后,我们在测试集上评估训练好的模型,并计算分类准确率。

这个基于CNN的图像分类例子展示了如何使用深度学习来解决实际问题。通过构建一个CNN模型并对其进行训练,我们能够对图像进行分类,并获得模型在测试集上的准确率评估。

下面是代码每部分分段介绍。

**

  
  
import torchimport torch.nn as nnimport torch.optim as optimimport torchvisionimport torchvision.transforms as transforms # 设置随机种子,以便结果可复现torch.manual_seed(42) # 加载并预处理数据集transform = transforms.Compose([    transforms.ToTensor(),                             # 将图像转换为张量    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 归一化]) trainset = torchvision.datasets.CIFAR10(root=‘./data’, train=True, download=True, transform=transform)trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=2) testset = torchvision.datasets.CIFAR10(root=‘./data’, train=False, download=True, transform=transform)testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False, num_workers=2)

首先,我们导入必要的库和模块,包括PyTorch、torchvision和torchvision.transforms。然后,我们设置了随机种子,以确保结果的可重现性。

接下来,我们定义了一个数据预处理的管道transform。在这个例子中,我们将图像转换为张量,并进行归一化处理。

然后,我们使用torchvision.datasets.CIFAR10加载CIFAR-10数据集,通过设置root指定数据集的存储路径,train=True表示加载训练集,download=True表示如果数据集不存在,则下载数据集。我们还传入了之前定义的数据预处理管道transform

通过torch.utils.data.DataLoader,我们创建了训练集和测试集的数据加载器。batch_size参数指定每个批次的样本数量,shuffle=True表示在每个epoch中打乱数据,num_workers表示用于数据加载的线程数。

**

  
  
# 定义CNN模型class CNN(nn.Module):    def init(self):        super(CNN, self).init()        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)  # 输入通道数为3,输出通道数为16,卷积核大小为3,步长为1,填充为1        self.relu = nn.ReLU()                                          # ReLU激活函数        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)               # 最大池化层,池化核大小为2,步长为2        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)  # 输入通道数为16,输出通道数为32,卷积核大小为3,步长为1,填充为1        self.fc1 = nn.Linear(32  8  8, 128)                            # 全连接层,输入大小为3288,输出大小为128        self.fc2 = nn.Linear(128, 10)                                    # 全连接层,输入大小为128,输出大小为10(类别数)     def forward(self, x):        x = self.relu(self.conv1(x))        x = self.pool(x)        x = self.relu(self.conv2(x))        x = self.pool(x)        x = x.view(x.size(0), -1)        x = self.relu(self.fc1(x))        x = self.fc2(x)        return x

我们定义了一个简单的CNN模型。这个CNN模型包含了两个卷积层(conv1conv2),每个卷积层后面都跟着一个ReLU激活函数和一个最大池化层(pool)。最后,我们有两个全连接层(fc1fc2)。

init方法中,我们定义了模型的各个层次和参数。每个卷积层的参数包括输入通道数、输出通道数、卷积核大小、步长和填充。每个全连接层的参数包括输入大小和输出大小。

forward方法中,我们定义了模型的前向传播过程。我们使用ReLU激活函数来引入非线性性,使用最大池化层来降低特征图的尺寸。通过view方法,我们将特征图展平成一维向量,以便传递给全连接层。最后一层是一个全连接层,输出的大小为类别数(在这个例子中为10)。

**

  
  
# 实例化模型和损失函数net = CNN()criterion = nn.CrossEntropyLoss()                          # 交叉熵损失函数optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  # 随机梯度下降优化器

我们实例化了之前定义的CNN模型,并定义了损失函数和优化器。在这个例子中,我们使用交叉熵损失函数和随机梯度下降(SGD)优化器。

**

  
  
# 训练模型for epoch in range(10):  # 进行10个epoch的训练    running_loss = 0.0    for i, data in enumerate(trainloader, 0):        inputs, labels = data        optimizer.zero_grad()                # 前向传播、反向传播、优化        outputs = net(inputs)        loss = criterion(outputs, labels)        loss.backward()        optimizer.step()                running_loss += loss.item()        if i % 2000  1999:            print(f‘[{epoch + 1}, {i + 1}] loss: {running_loss / 2000:.3f}’)            running_loss = 0.0 print(‘Finished training’)

在训练阶段,我们使用训练集进行模型的训练。我们遍历数据加载器中的每个批次,将输入数据和标签加载到设备上。然后,我们将梯度缓存清零(通过optimizer.zero_grad()),执行前向传播、反向传播和优化步骤。损失函数用于计算输出和标签之间的损失,并通过反向传播计算梯度。优化器根据梯度更新模型的参数。我们还计算并打印出每个epoch的平均损失。

**

  
  
# 在测试集上评估模型correct = 0total = 0with torch.no_grad():    for data in testloader:        images, labels = data        outputs = net(images)        _, predicted = torch.max(outputs.data, 1)  # 获取每个样本预测的类别索引        total += labels.size(0)        correct += (predicted  labels).sum().item() print(f‘Accuracy on the test set: {100 * correct / total:.2f}%’)

在测试阶段,我们使用测试集对训练好的模型进行评估。对于每个样本,我们计算模型的输出并找到最高分数对应的类别索引。然后,我们将预测结果与真实标签进行比较,计算分类正确的样本数。最后,我们计算并打印出模型在测试集上的准确率。

这个基于CNN的图像分类例子展示了如何使用深度学习来解决实际问题。通过构建一个CNN模型并对其进行训练,我们能够对图像进行分类,并获得模型在测试集上的准确率评估。