CNN学习时的代码

python 复制代码
# 导入PyTorch核心库,用于构建和训练神经网络
import torch
# 导入优化器模块,用于更新模型参数
import torch.optim as optim
# 导入神经网络层模块,用于搭建网络结构
import torch.nn as nn
# 导入激活函数、损失函数等功能性API
import torch.nn.functional as F
# 导入数据集和数据预处理工具
from torchvision import datasets, transforms
# 导入数值计算库
import numpy as np
# 导入绘图库,用于绘制损失曲线
import matplotlib.pyplot as plt

# ===================== 【超参数设置】 =====================
# 输入图像的尺寸,MNIST数据集是28x28像素
input_size = 28
# 分类类别数量,0-9共10个数字
num_classes = 10
# 训练轮数:将整个训练集完整训练几遍
num_epochs = 10
# 批次大小:每次喂给模型多少张图片一起训练
batch_size = 10

# ===================== 【加载MNIST数据集】 =====================
# 加载训练数据集
train_dataset = datasets.MNIST(
    root='./data',  # 数据集存放路径
    train=True,     # True表示加载训练集
    transform=transforms.ToTensor(),  # 将图片转换为PyTorch张量
    download=True   # 如果本地没有数据集,自动从网上下载
)

# 加载测试数据集
test_dataset = datasets.MNIST(
    root='./data',   # 数据集存放路径
    train=False,     # False表示加载测试集
    transform=transforms.ToTensor()  # 将图片转换为PyTorch张量
)

# ===================== 【构建数据加载器】 =====================
# 训练集加载器:按批次加载数据,并打乱顺序
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=True
)

# ===================== 【定义CNN神经网络模型】 =====================
class CNN(nn.Module):  # 定义CNN类,继承PyTorch的nn.Module
    def __init__(self):
        super(CNN, self).__init__()  # 初始化父类,固定写法
        
        # 第一个卷积模块:卷积+激活+池化
        self.conv1 = nn.Sequential(
            nn.Conv2d(
                in_channels=1,    # 输入通道数:灰度图为1
                out_channels=16,  # 输出通道数:生成16张特征图
                kernel_size=5,    # 卷积核大小5x5
                stride=1,         # 卷积步长为1
                padding=2         # 填充2圈0,保持输出尺寸不变
            ),
            nn.ReLU(),            # 激活函数,增加非线性
            nn.MaxPool2d(kernel_size=2)  # 最大池化,尺寸缩小一半
        )
        
        # 第二个卷积模块
        self.conv2 = nn.Sequential(
            nn.Conv2d(16, 32, 5, 1, 2),  # 输入16通道→输出32通道
            nn.ReLU(),
            nn.MaxPool2d(2)  # 尺寸再缩小一半
        )
        
        # 全连接层:将卷积特征映射到10个分类结果
        self.out = nn.Linear(32 * 7 * 7, 10)

    # 前向传播:定义数据流向
    def forward(self, x):
        x = self.conv1(x)    # 输入经过第一个卷积模块
        x = self.conv2(x)    # 经过第二个卷积模块
        x = x.view(x.size(0), -1)  # 展平特征图,适配全连接层
        output = self.out(x)  # 全连接层输出分类结果
        return output

# ===================== 【初始化模型、优化器、损失函数】 =====================
model = CNN()  # 创建CNN模型实例
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam优化器
loss_func = nn.CrossEntropyLoss()  # 交叉熵损失函数,用于分类任务

# ===================== 【开始训练模型】 =====================
print("开始训练...")
train_loss_list = []  # 保存每轮的平均损失,用于绘图

# 循环训练指定轮数
for epoch in range(num_epochs):
    total_loss = 0  # 累计当前轮的总损失
    # 遍历训练集中的每一个批次
    for i, (images, labels) in enumerate(train_loader):
        output = model(images)  # 前向传播:计算模型输出
        loss = loss_func(output, labels)  # 计算损失值
        
        optimizer.zero_grad()  # 清空上一步的梯度
        loss.backward()        # 反向传播:计算梯度
        optimizer.step()       # 更新模型参数
        
        total_loss += loss.item()  # 累加损失

    avg_loss = total_loss / len(train_loader)  # 计算本轮平均损失
    train_loss_list.append(avg_loss)  # 保存损失
    print(f"Epoch [{epoch+1}/{num_epochs}] 平均损失: {avg_loss:.4f}")

# ===================== 【测试模型准确率】 =====================
print("\n开始测试...")
correct = 0  # 预测正确的样本数
total = 0    # 总样本数

with torch.no_grad():  # 测试时不需要计算梯度,节省资源
    for images, labels in test_loader:
        outputs = model(images)  # 模型预测
        _, predicted = torch.max(outputs.data, 1)  # 获取预测类别
        total += labels.size(0)  # 累计总样本数
        correct += (predicted == labels).sum().item()  # 累计正确数

# 计算并打印准确率
print(f'测试集准确率: {100 * correct / total:.2f}%')

# ===================== 【绘制训练损失曲线】 =====================
plt.plot(train_loss_list, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('训练损失变化')
plt.legend()
plt.show()

超参数 = 人工手动设置的参数

直接调用库内置 MNIST 数据集,无需自己准备图片文件。

python 复制代码
# 导入PyTorch的核心库,提供张量计算、自动求导等基础功能
import torch

# 导入PyTorch的优化器模块,用于更新神经网络的权重参数
import torch.optim as optim

# 导入PyTorch的神经网络层模块,包含卷积层、全连接层等网络组件
import torch.nn as nn

# 导入PyTorch的函数式接口,包含激活函数、损失函数等工具
import torch.nn.functional as F

# 从torchvision库中导入数据集工具和数据预处理工具
from torchvision import datasets, transforms

# 导入numpy数值计算库,用于数组、矩阵相关计算
import numpy as np

# 导入matplotlib的pyplot模块,用于绘制图表可视化数据
import matplotlib.pyplot as plt

# 定义输入图像的尺寸,MNIST数据集的图片大小为28*28像素
input_size = 28

# 定义分类的类别数量,手写数字识别分为0-9共10个类别
num_classes = 10

# 定义训练的总轮数,代表将整个训练集完整训练10次
num_epochs = 10

# 定义批次大小,每次训练时输入模型的样本数量为10
batch_size = 10

# 加载MNIST训练数据集
train_dataset = datasets.MNIST(
    # 指定数据集的存储根目录为当前文件夹下的data文件夹
    root='./data',
    # 设置为True,表示加载训练集数据
    train=True,
    # 数据预处理:将PIL图片格式转换为PyTorch专用的张量格式
    transform=transforms.ToTensor(),
    # 设置为True,如果本地没有数据集,自动从官方服务器下载
    download=True
)

# 加载MNIST测试数据集
test_dataset = datasets.MNIST(
    # 测试集存储路径与训练集一致
    root='./data',
    # 设置为False,表示加载测试集数据
    train=False,
    # 测试集同样需要转换为张量格式
    transform=transforms.ToTensor(),
)

# 创建训练集的数据加载器,用于批量读取数据
train_loader = torch.utils.data.DataLoader(
    # 指定需要加载的训练数据集
    dataset=train_dataset,
    # 设置每个批次包含的样本数,使用上方定义的batch_size
    batch_size=batch_size,
    # 设置为True,训练时打乱数据顺序,防止模型记忆数据顺序
    shuffle=True
)

# 创建测试集的数据加载器
test_loader = torch.utils.data.DataLoader(
    # 指定需要加载的测试数据集
    dataset=test_dataset,
    # 测试批次大小与训练保持一致
    batch_size=batch_size,
    # 测试集打乱顺序,保证测试的随机性
    shuffle=True
)

# 定义CNN神经网络类,继承自nn.Module(PyTorch所有模型的基类)
class CNN(nn.Module):
    # 类的初始化函数,定义网络的层结构
    def __init__(self):
        # 调用父类nn.Module的初始化方法,固定语法
        super(CNN, self).__init__()
        
        # 定义第一个卷积模块,使用Sequential组合多层网络
        self.conv1 = nn.Sequential(
            # 二维卷积层,用于提取图像特征
            nn.Conv2d(
                # 输入通道数:MNIST是灰度图,通道数为1
                in_channels=1,
                # 输出通道数:卷积后生成16张特征图
                out_channels=16,
                # 卷积核的尺寸为5x5
                kernel_size=5,
                # 卷积核移动的步长为1
                stride=1,
                # 图像边缘填充2圈0,保证卷积后尺寸不变
                padding=2,
            ),
            # ReLU激活函数,增加网络的非线性表达能力
            nn.ReLU(),
            # 二维最大池化层,池化核大小2x2,将特征图尺寸缩小一半
            nn.MaxPool2d(kernel_size=2, ),
        )
        
        # 定义第二个卷积模块
        self.conv2 = nn.Sequential(
            # 二维卷积层:输入16通道,输出32通道,卷积核5x5
            nn.Conv2d(16, 32, 5, 1, 2),
            # ReLU激活函数
            nn.ReLU(),
            # 最大池化层,尺寸再次缩小一半
            nn.MaxPool2d(kernel_size=2),
        )
        
        # 定义全连接层:将卷积特征展平后映射为10分类结果
        self.out = nn.Linear(32*7*7, 10)

    # 前向传播函数,定义数据在网络中的流动路径
    def forward(self,x):
        # 输入数据经过第一个卷积模块
        x = self.conv1(x)
        # 数据经过第二个卷积模块
        x = self.conv2(x)
        # 将特征图展平:batch维度保留,其余维度合并为一维
        x = x.view(x.size(0), -1)
        # 数据传入全连接层,得到最终的分类输出
        output = self.out(x)
        # 返回模型的输出结果
        return output

# 实例化CNN模型,创建一个可以训练的网络对象
model = CNN()

# 定义Adam优化器,传入模型参数和学习率lr=0.001
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 定义交叉熵损失函数,适用于多分类任务
loss_func = nn.CrossEntropyLoss()

# 打印训练开始的提示信息
print("开始训练...")

# 创建空列表,用于存储每一轮训练的平均损失值
train_loss_list = []

# 外层循环:遍历每一个训练轮数
for epoch in range(num_epochs):
    # 初始化当前轮次的总损失为0
    total_loss = 0
    # 内层循环:遍历训练集中的每一个批次数据
    for i, (images, labels) in enumerate(train_loader):
        # 前向传播:将图片输入模型,得到预测输出
        output = model(images)
        # 计算损失值:对比预测输出和真实标签
        loss = loss_func(output, labels)
        
        # 清空上一步的梯度,防止梯度累加
        optimizer.zero_grad()
        # 反向传播:计算损失对模型参数的梯度
        loss.backward()
        # 优化器更新模型的权重参数
        optimizer.step()
        
        # 将当前批次的损失值累加到总损失中
        total_loss += loss.item()

    # 计算当前轮次的平均损失:总损失 / 批次数量
    avg_loss = total_loss / len(train_loader)
    # 将平均损失添加到列表中
    train_loss_list.append(avg_loss)
    # 打印当前轮次的训练信息
    print(f"Epoch [{epoch+1}/{num_epochs}] 平均损失: {avg_loss:.4f}")

# 打印测试开始的提示信息
print("\n开始测试...")

# 初始化预测正确的样本数量为0
correct = 0
# 初始化测试集的总样本数量为0
total = 0

# torch.no_grad():测试阶段关闭梯度计算,节省内存和计算资源
with torch.no_grad():
    # 遍历测试集中的每一个批次
    for images, labels in test_loader:
        # 将测试图片输入模型,得到输出
        outputs = model(images)
        # 获取预测结果:取输出中概率最大的类别
        _, predicted = torch.max(outputs.data, 1)
        # 累加当前批次的样本总数
        total += labels.size(0)
        # 统计预测正确的样本数量并累加
        correct += (predicted == labels).sum().item()

# 计算并打印模型在测试集上的准确率
print(f'测试集准确率: {100 * correct / total:.2f}%')

# 绘制训练损失曲线:x轴为轮数,y轴为损失值
plt.plot(train_loss_list, label='Training Loss')
# 设置x轴标签
plt.xlabel('Epoch')
# 设置y轴标签
plt.ylabel('Loss')
# 设置图表标题
plt.title('训练损失变化')
# 显示图例
plt.legend()
# 展示绘制的图表
plt.show()
相关推荐
AskHarries8 小时前
Google Trends 找蓝海赛道:独立开发者如何挖出没人做、但有人搜的项目
人工智能
searchforAI8 小时前
5款AI笔记工具实测:导入体验、结构化输出、后续能力逐项对比
人工智能·笔记·学习·ai·chatgpt·aigc·音视频
pixcarp8 小时前
Redis ZSet:底层设计与实践
数据库·redis·后端·学习·golang·web
学习中.........8 小时前
Agent 记忆力机制设计学习路线:从主流项目中学习
学习
深度学习lover8 小时前
<项目代码>yolo缆绳识别<目标检测>
人工智能·深度学习·yolo·目标检测·项目代码·缆绳识别
Lyon198505288 小时前
从临床医疗说起:当一种科学理论走到边界的时候
人工智能·深度学习·算法·deepseek·ai伦理
美团技术团队8 小时前
从高拟真到真可用,LongCat-Video-Avatar 1.5 正式开源
人工智能·算法
2601_949936968 小时前
2026会计人员能力及学习提升方向指导
大数据·人工智能
XGeFei8 小时前
【Fastapi学习笔记(1)】—— Pydantic模型、依赖注入、请求头-Cookie、响应头
笔记·学习·fastapi