MNIST数据集_CNN

前言

提醒:

文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。

其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。

文章目录

  • 前言
  • 数据集MNIST
  • CNN
      • [1. 卷积层(Convolutional Layer)](#1. 卷积层(Convolutional Layer))
      • [2. 激活函数(Activation Function)](#2. 激活函数(Activation Function))
      • [3. 池化层(Pooling Layer)](#3. 池化层(Pooling Layer))
      • [4. 全连接层(Fully Connected Layer)](#4. 全连接层(Fully Connected Layer))
      • [5. 卷积神经网络的典型结构](#5. 卷积神经网络的典型结构)
      • [6. 卷积神经网络的训练](#6. 卷积神经网络的训练)
      • [7. CNN 训练的优化:梯度下降法](#7. CNN 训练的优化:梯度下降法)
  • 代码分析
    • [def init(self,hidden_channel_size_1,hidden_channel_size_2,num_classes=10):](#def init(self,hidden_channel_size_1,hidden_channel_size_2,num_classes=10):)
        • [1 第一层卷积](#1 第一层卷积)
        • [2 第二层卷积](#2 第二层卷积)
        • [3 全连接层](#3 全连接层)
    • [def forward(self, x):](#def forward(self, x):)
    • [criterion = nn.CrossEntropyLoss()](#criterion = nn.CrossEntropyLoss())
    • [optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)](#optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate))
    • 训练过程
    • 测试模型

数据集MNIST

MNIST(Modified National Institute of Standards and Technology)数据集是一个广泛使用的图像数据集,主要用于训练和测试图像处理系统,尤其是机器学习和计算机视觉领域的算法。MNIST 是手写数字的一个标准化数据集,常用作分类任务的基准数据集。

数据集概述

***MNIST 数据集包含了 28x28 像素的手写数字图像,且图像是灰度图(即每个像素值在 0 到 255 之间)***数据集包含两部分:

  1. 训练集(Training set):

    • 包含 60,000 张图像。
    • 每张图像对应一个标签,表示该图像所表示的数字(0 到 9)。
  2. 测试集(Test set):

    • 包含 10,000 张图像。
    • 用于测试模型的泛化能力。

每张图像的标签为 0 到 9 的一个数字,表示图像中手写数字的类别。

数据集的结构

  • 图像大小: 每张图像的尺寸为 28x28 像素。
  • 灰度级: 每个像素的灰度值介于 0(黑色)到 255(白色)之间。
  • 数据类型: 图像数据通常会被转换为浮点数(归一化为 0 到 1 之间),以便输入到神经网络中进行训练。

数据集的格式

MNIST 数据集的每张图像都由 28x28 的灰度值构成,并且对应一个标签。数据通常以以下格式存储:

  • 每张图像是一个 28x28 的矩阵。
  • 每个标签是一个数字(0 到 9),表示图像中的数字。

使用 MNIST 数据集

MNIST 数据集是机器学习和深度学习初学者常用的入门数据集,适用于各种分类算法的实验和研究。因为它的任务相对简单,所以它常常作为测试新算法的基准。常见的算法包括:

  • 传统的机器学习算法(如支持向量机 SVM、k近邻 KNN 等)。
  • 深度学习模型(如卷积神经网络 CNN)。

例子:如何加载 MNIST 数据集

使用 PyTorch,可以通过 torchvision.datasets.MNIST 来直接加载 MNIST 数据集。

数据集的应用

  • 机器学习: 因为 MNIST 是一个简单且具有代表性的分类问题,它非常适合用来评估和比较不同的机器学习算法。许多研究者和开发者使用它来验证新提出的算法的有效性。
  • 深度学习: 在深度学习领域,MNIST 数据集常常用来作为卷积神经网络(CNN)和其他深度学习模型的初步测试集,帮助开发者快速验证他们的模型效果。

数据集的挑战

尽管 MNIST 数据集非常经典,但它也逐渐暴露出了一些局限性。随着计算机视觉技术的进步,MNIST 的问题变得相对简单,许多现代模型可以达到接近 100% 的准确率。因此,很多研究者现在更倾向于使用更复杂的图像数据集,如 CIFAR-10、CIFAR-100、ImageNet 等。

数据集介绍

使用 PyTorch,可以通过 torchvision.datasets.MNIST 来直接加载 MNIST 数据集:

python 复制代码
# MNIST dataset 
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
train_dataset = torchvision.datasets.MNIST(root='data', 
                                           train=True, 
                                           download=True,
                                           transform=transforms.ToTensor())

test_dataset = torchvision.datasets.MNIST(root='data', 
                                          train=False, 
                                          transform=transforms.ToTensor(),
                                          download=True)

# Data loader
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, 
                                           batch_size=batch_size, 
                                           shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset, 
                                          batch_size=batch_size, 
                                          shuffle=False)

1. 导入必要的库

python 复制代码
import torch
import torchvision
import torchvision.transforms as transforms
  • torch:PyTorch的核心库,提供了多维数组(Tensor)等基础设施。
  • torchvision:一个专门用于计算机视觉任务的库,提供了常用的数据集、模型和图像处理工具。
  • torchvision.transforms:用于数据预处理和数据增强的模块。

2. 加载MNIST数据集

python 复制代码
train_dataset = torchvision.datasets.MNIST(root='data', 
                                           train=True, 
                                           download=True,
                                           transform=transforms.ToTensor())
  • torchvision.datasets.MNIST:这是一个用于加载MNIST数据集的类。MNIST数据集包含手写数字的图像,通常用于图像分类任务。

  • 参数说明

    • root='data':指定数据集存储的根目录。如果该目录不存在,数据集将下载到此位置。
    • train=True :加载训练集。如果设置为False,则加载测试集。
    • download=True :如果在指定的root路径下找不到数据集,将自动下载数据集。
    • transform=transforms.ToTensor() :应用于数据集的转换操作。这里使用了transforms.ToTensor(),它将加载的PIL图像转换为PyTorch的Tensor格式,同时将像素值从[0, 255]范围归一化到[0, 1]范围。

3. 加载测试集

python 复制代码
test_dataset = torchvision.datasets.MNIST(root='data', 
                                          train=False, 
                                          transform=transforms.ToTensor(),
                                          download=True)
  • 这段代码与加载训练集的代码类似,但train=False表示加载的是测试集。其他参数相同。测试集用于模型评估,而训练集用于模型训练。

4. 创建数据加载器

python 复制代码
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, 
                                           batch_size=batch_size, 
                                           shuffle=True)
  • torch.utils.data.DataLoader:这是PyTorch提供的一个工具,用于批量加载数据集,便于在训练和测试模型时使用。

  • 参数说明

    • dataset=train_dataset:指定要加载的数据集,这里是训练集。
    • batch_size=batch_size :每个批次加载的数据样本数量。batch_size是一个变量,通常在代码的其他地方定义。合理的批量大小可以提高训练效率,并有助于模型的收敛。
    • shuffle=True:在每个epoch开始前打乱数据集的顺序,增加训练的随机性,有助于提升模型的泛化能力。
python 复制代码
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, 
                                          batch_size=batch_size, 
                                          shuffle=False)
  • 这段代码用于加载测试集,参数与训练集加载器相似。这里的shuffle=False表示在测试时不打乱数据集。测试集的顺序通常是重要的,以便在评估模型性能时保持一致。

数据集实例

python 复制代码
# MNIST dataset 
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
train_dataset = torchvision.datasets.MNIST(root='data', 
                                           train=True, 
                                           download=True,
                                           transform=transforms.ToTensor())

test_dataset = torchvision.datasets.MNIST(root='data', 
                                          train=False, 
                                          transform=transforms.ToTensor(),
                                          download=True)

# Data loader
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, 
                                           batch_size=100, 
                                           shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset, 
                                          batch_size=100, 
                                          shuffle=False)
                                          
images, labels = zip(*[(train_dataset[i][0], train_dataset[i][1]) for i in range(10)])

# 设置绘图
fig, axes = plt.subplots(2, 5, figsize=(10, 5))

# 展示图像
for i, ax in enumerate(axes.flat):
    # 获取图像数据和标签
    img = images[i].numpy().squeeze()  # 移除多余的维度
    label = labels[i]
    
    # 显示图像
    ax.imshow(img, cmap='gray')
    ax.set_title(f'Label: {label}')
    ax.axis('off')  # 不显示坐标轴

plt.tight_layout()
plt.show()

运行结果为:

CNN

卷积神经网络(Convolutional Neural Networks,CNN)是一种深度学习模型,广泛应用于计算机视觉、语音识别等任务。CNN 通过利用局部连接和权重共享,显著降低了模型参数的数量,从而提高了训练效率并防止过拟合。CNN 的核心是卷积操作,并结合了池化层和全连接层等其他组件。

1. 卷积层(Convolutional Layer)

卷积层是 CNN 的核心,它负责从输入数据中提取特征。其基本操作是 卷积(convolution),通过卷积核(或滤波器)对输入数据进行滑动和局部特征提取。

数学公式:

设输入图像为一个二维矩阵 I I I,卷积核(滤波器)为 K K K,卷积操作输出为特征图 O O O。对于一个输入图像 I I I 和一个卷积核 K K K,卷积的计算公式为:

O ( i , j ) = ( I ∗ K ) ( i , j ) = ∑ m ∑ n I ( i + m , j + n ) K ( m , n ) O(i, j) = (I * K)(i, j) = \sum_m \sum_n I(i+m, j+n) K(m, n) O(i,j)=(I∗K)(i,j)=m∑n∑I(i+m,j+n)K(m,n)

引用自:
【卷积】直观形象的实例,10分钟彻底搞懂
【卷积神经网络】8分钟搞懂CNN,动画讲解喜闻乐见


其中:

  • I ( i , j ) I(i, j) I(i,j) 是输入图像 I I I 在位置 ( i , j ) (i, j) (i,j) 的像素值;
  • K ( m , n ) K(m, n) K(m,n) 是卷积核 K K K 在位置 ( m , n ) (m, n) (m,n) 的权重;
  • O ( i , j ) O(i, j) O(i,j) 是输出特征图在位置 ( i , j ) (i, j) (i,j) 的值。

这里的操作是卷积核在输入图像上滑动并计算加权和。通过卷积层,CNN 能够提取局部特征(例如边缘、纹理、颜色等),并保留空间层次信息。

卷积的步骤:
  1. 卷积核从图像的左上角开始,逐步向右滑动(水平),然后向下滑动(垂直)。
  2. 在每个位置,卷积核与输入图像的局部区域进行加权求和,输出一个新的像素值,生成新的特征图。
  3. 通过多个卷积核,CNN 可以从不同的角度提取不同类型的特征。

2. 激活函数(Activation Function)

卷积操作后的输出通常会经过非线性激活函数,常用的激活函数包括 ReLU(Rectified Linear Unit)。ReLU 的数学公式如下:

ReLU ( x ) = max ⁡ ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x)

ReLU 激活函数帮助网络引入非线性,使其能够学习复杂的特征。它的优点是计算简单且收敛速度较快。

3. 池化层(Pooling Layer)

池化层用于降低特征图的空间维度(宽度和高度),同时保持重要特征。池化层通常有两种操作:最大池化 (Max Pooling)和 平均池化(Average Pooling)。在最大池化中,取池化窗口内的最大值;在平均池化中,取池化窗口内的平均值。

最大池化:

给定池化窗口大小为 2 × 2 2 \times 2 2×2,池化操作可以表示为:

O ( i , j ) = max ⁡ m , n ∈ P ( i , j ) I ( m , n ) O(i, j) = \max_{m, n \in P(i,j)} I(m, n) O(i,j)=m,n∈P(i,j)maxI(m,n)

其中, P ( i , j ) P(i,j) P(i,j) 是以 ( i , j ) (i, j) (i,j) 为中心的池化窗口。

池化操作的作用是减小特征图的尺寸,从而降低计算量并减少模型的参数量。

4. 全连接层(Fully Connected Layer)

在卷积和池化层后,CNN 通常包含一个或多个全连接层(FC),其作用是将高层次的特征组合成最终的分类结果。全连接层的每个神经元与前一层的所有神经元都有连接。

全连接层的计算公式为:

y = f ( W x + b ) y = f(Wx + b) y=f(Wx+b)

其中:

  • x x x 是上一层的输出(例如,经过卷积层和池化层后的特征图展平后形成的向量);
  • W W W 是权重矩阵;
  • b b b 是偏置项;
  • f f f 是激活函数(通常使用 ReLU 或 Sigmoid)。

全连接层的作用是进行分类或回归任务。对于分类任务,通常会在全连接层后使用 Softmax 激活函数,得到每个类别的概率分布。

5. 卷积神经网络的典型结构

一个典型的 CNN 网络结构包括以下几部分:

  1. 卷积层(Convolutional Layer):提取局部特征。
  2. 激活函数(ReLU):引入非线性。
  3. 池化层(Pooling Layer):降维,减少计算量。
  4. 全连接层(Fully Connected Layer):将高层特征映射到最终的输出(如分类标签)。
  5. Softmax 层:将输出转换为概率分布(用于分类任务)。

6. 卷积神经网络的训练

CNN 的训练过程类似于其他神经网络。主要包括以下几个步骤:

  1. 前向传播:输入图像通过卷积层、激活函数、池化层、全连接层,最终输出预测结果。
  2. 计算损失:通过比较预测结果与实际标签,计算损失函数(如交叉熵损失)。
  3. 反向传播:通过反向传播算法计算梯度,并利用梯度下降算法更新网络权重。

损失函数 L L L 通常是交叉熵损失(用于分类任务):

L = − ∑ i = 1 N y i log ⁡ ( y ^ i ) L = - \sum_{i=1}^{N} y_i \log(\hat{y}_i) L=−i=1∑Nyilog(y^i)

其中:

  • y i y_i yi 是实际标签的 one-hot 编码;
  • y ^ i \hat{y}_i y^i 是网络的预测输出。

7. CNN 训练的优化:梯度下降法

在训练过程中,通常使用 梯度下降(Gradient Descent)及其变种(如 Adam、SGD 等)来优化网络的参数。通过计算损失函数对权重的梯度,更新网络中的参数。梯度下降的更新公式为:

W = W − η ∂ L ∂ W W = W - \eta \frac{\partial L}{\partial W} W=W−η∂W∂L

其中:

  • W W W 是权重;
  • η \eta η 是学习率;
  • ∂ L ∂ W \frac{\partial L}{\partial W} ∂W∂L 是损失函数对权重的梯度。

代码分析

python 复制代码
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
# try running the following code, if you see errors on Windows OS

# import os
# os.environ['KMP_DUPLICATE_LIB_OK']='TRUE'
# Device configuration
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# Hyper-parameters 
hidden_channel_size_1 = 16
hidden_channel_size_2 = 32
num_epochs = 5
batch_size = 100
learning_rate = 0.001
# MNIST dataset 
train_dataset = torchvision.datasets.MNIST(root='data', 
                                           train=True, 
                                           download=True,
                                           transform=transforms.ToTensor())

test_dataset = torchvision.datasets.MNIST(root='data', 
                                          train=False, 
                                          transform=transforms.ToTensor(),
                                          download=True)

# Data loader
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, 
                                           batch_size=batch_size, 
                                           shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset, 
                                          batch_size=batch_size, 
                                          shuffle=False)
len(train_dataset),len(test_dataset)
# CNN
class CNeuralNet(nn.Module):
    def __init__(self,hidden_channel_size_1,hidden_channel_size_2,num_classes=10):
        super(CNeuralNet, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, hidden_channel_size_1, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(hidden_channel_size_1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.layer2 = nn.Sequential(
            nn.Conv2d(hidden_channel_size_1, hidden_channel_size_2, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(hidden_channel_size_2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.fc = nn.Linear(7*7*hidden_channel_size_2, num_classes) # originally 28*28, after two MaxPool2d(2), becomes 7*7
        
    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.reshape(out.size(0), -1)
        out = self.fc(out)
        return out
    
model = CNeuralNet(hidden_channel_size_1,hidden_channel_size_2).to(device)
# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)  
# Train the model
total_step = len(train_loader)
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        images = images.to(device)
        labels = labels.to(device)
        
        # Forward pass
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # Backward and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if (i+1) % 100 == 0:
            print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' 
                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))

# Test the model
model.eval()  # eval mode (batchnorm uses moving mean/variance instead of mini-batch mean/variance)
with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

    print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total))

运行结果:

def init(self,hidden_channel_size_1,hidden_channel_size_2,num_classes=10):

python 复制代码
def __init__(self,hidden_channel_size_1,hidden_channel_size_2,num_classes=10):
        super(CNeuralNet, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, hidden_channel_size_1, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(hidden_channel_size_1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.layer2 = nn.Sequential(
            nn.Conv2d(hidden_channel_size_1, hidden_channel_size_2, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(hidden_channel_size_2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.fc = nn.Linear(7*7*hidden_channel_size_2, num_classes) # originally 28*28, after two MaxPool2d(2), becomes 7*7
1 第一层卷积
python 复制代码
self.layer1 = nn.Sequential(
    nn.Conv2d(1, hidden_channel_size_1, kernel_size=5, stride=1, padding=2),
    nn.BatchNorm2d(hidden_channel_size_1),
    nn.ReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2))
  • 卷积层nn.Conv2d(1, hidden_channel_size_1, kernel_size=5, stride=1, padding=2)

    输入通道数为 1(灰度图像),输出通道数为 hidden_channel_size_1(即 16),卷积核大小为 5x5,步幅为 1,填充为 2。这意味着卷积后的输出维度保持为 28x28。

    卷积操作的数学公式为:

    O i , j = ∑ m , n I i + m , j + n ⋅ K m , n O_{i,j} = \sum_{m,n} I_{i+m, j+n} \cdot K_{m,n} Oi,j=m,n∑Ii+m,j+n⋅Km,n

    其中:

    • I I I 是输入图像矩阵, K K K 是卷积核, O O O 是输出特征图。
  • 批量归一化nn.BatchNorm2d(hidden_channel_size_1)

    用于规范化输出,保持均值接近 0,方差接近 1,帮助加速训练并防止梯度消失。

  • ReLU 激活函数nn.ReLU()

    引入非线性,ReLU 的公式为:

    ReLU ( x ) = max ⁡ ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x)

  • 最大池化nn.MaxPool2d(kernel_size=2, stride=2)

    对特征图进行池化操作,使用 2x2 的池化窗口,步幅为 2,这将特征图尺寸减半。即,28x28 的特征图变为 14x14。

2 第二层卷积
python 复制代码
self.layer2 = nn.Sequential(
    nn.Conv2d(hidden_channel_size_1, hidden_channel_size_2, kernel_size=5, stride=1, padding=2),
    nn.BatchNorm2d(hidden_channel_size_2),
    nn.ReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2))
  • 输入特征图大小为 14x14,卷积核大小为 5x5,步幅为 1,填充为 2,因此输出特征图的大小仍然是 14x14。
  • 执行最大池化后,特征图尺寸将减半,变为 7x7。
3 全连接层
python 复制代码
self.fc = nn.Linear(7*7*hidden_channel_size_2, num_classes) 
  • 在经过两次池化后,特征图的尺寸为 7x7,每个卷积层有 hidden_channel_size_2 个通道(即 32)。因此,全连接层的输入大小是 7 × 7 × 32 = 1568 7 \times 7 \times 32 = 1568 7×7×32=1568。
  • 最终输出为 num_classes,即 10(代表数字 0-9 的分类)。

def forward(self, x):

前向传播
python 复制代码
def forward(self, x):
    out = self.layer1(x)
    out = self.layer2(out)
    out = out.reshape(out.size(0), -1)  # Flatten the output from convolution layers
    out = self.fc(out)
    return out
  • out.reshape(out.size(0), -1):将卷积层的输出展平为一维向量,准备进入全连接层。
  • 最终输出是一个大小为 (batch_size, num_classes) 的张量,表示每个输入图像属于每个类别的得分。

criterion = nn.CrossEntropyLoss()

损失函数
python 复制代码
criterion = nn.CrossEntropyLoss()
  • 交叉熵损失:用于分类任务,特别是多类别分类问题。公式为:

L = − ∑ i = 1 C y i log ⁡ ( y ^ i ) L = -\sum_{i=1}^{C} y_i \log(\hat{y}_i) L=−i=1∑Cyilog(y^i)

其中:

  • C C C 是类别数(这里是 10)。
  • y i y_i yi 是实际类别的标签,通常是 one-hot 编码。
  • y ^ i \hat{y}_i y^i 是模型预测的类别概率,通常通过 softmax 激活函数得到。

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

优化器
python 复制代码
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
  • Adam 优化器 :一种自适应的优化算法,结合了 梯度下降自适应学习率

    更新公式如下:

θ t = θ t − 1 − η m t v t + ϵ \theta_t = \theta_{t-1} - \eta \frac{m_t}{\sqrt{v_t} + \epsilon} θt=θt−1−ηvt +ϵmt

其中:

  • θ \theta θ 是网络参数(权重)。
  • m t m_t mt 和 v t v_t vt 分别是梯度的均值和方差估计。
  • η \eta η 是学习率, ϵ \epsilon ϵ 是为了避免除零的常数。

训练过程

python 复制代码
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        images = images.to(device)
        labels = labels.to(device)

        outputs = model(images)  # 前向传播
        loss = criterion(outputs, labels)  # 计算损失

        optimizer.zero_grad()  # 清除之前的梯度
        loss.backward()  # 反向传播
        optimizer.step()  # 更新参数
  • 前向传播:输入图像通过卷积层和全连接层,生成输出。
  • 计算损失:使用交叉熵损失函数计算预测值与真实标签之间的误差。
  • 反向传播:计算梯度并更新网络的参数。

测试模型

python 复制代码
model.eval()  # 设定为评估模式,关闭 dropout 和 batchnorm
with torch.no_grad():
    correct = 0
    total = 0
    for images, labels in test_loader:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
  • 评估模式 :在评估阶段,model.eval() 会让 BatchNorm 使用训练过程中累计的均值和方差。
  • 计算准确率 :通过 torch.max() 获取模型预测的类别索引,然后与实际标签进行比较,计算正确预测的数量,最终计算模型的准确率。

总结

这段代码实现了一个典型的卷积神经网络,包含两个卷积层和一个全连接层,通过训练数据不断优化网络参数,最终在测试数据上进行评估。主要数学公式包括:

  1. 卷积操作:通过卷积核提取局部特征。
  2. ReLU 激活函数:引入非线性变换。
  3. 交叉熵损失:用于多类别分类问题。
  4. 梯度下降优化:通过 Adam 优化器更新模型参数。
相关推荐
Hugging Face3 分钟前
欢迎 PaliGemma 2 – 来自 Google 的新视觉语言模型
人工智能·语言模型·自然语言处理
Bony-21 分钟前
基于卷积神经网络(CNN)和ResNet50的水果与蔬菜图像分类系统
人工智能·分类·cnn
UQI-LIUWJ27 分钟前
datasets 笔记: 文本数据集的预处理(Tokenization)
人工智能·笔记·深度学习
架构师李肯29 分钟前
【活动邀请·深圳】深圳COC社区 & 深圳 AWS UG 2024 re:Invent re:Cap
人工智能
Python机器学习AI33 分钟前
融合机器学习算法:用VotingClassifier实现分类多模型的投票集成
人工智能·机器学习·分类
WeeJot嵌入式1 小时前
长短期记忆网络(LSTM):深度学习中的序列数据处理利器
人工智能·深度学习·lstm
梓羽玩Python1 小时前
字节黑科技 INFP,音频驱动的双边互动视频生成框架,实时生成,轻量又强大!
人工智能
沅_Yuan1 小时前
基于CNN-BiLSTM-selfAttention混合神经网络的多分类预测【MATLAB】
神经网络·分类·cnn·bilstm·selfattention
沅_Yuan1 小时前
基于LSTM长短期记忆神经网络的多分类预测【MATLAB】
神经网络·分类·lstm
千天夜1 小时前
YOLO系列正传(三)神经网络的反向传播(back propagation)与公式推导
人工智能·python·深度学习·神经网络·学习·yolo·卷积神经网络