897|8

169

帖子

1

TA的资源

纯净的硅(初级)

楼主
 

《动手学深度学习PyTorch版》阅读分享四 手写识别小试牛刀(基于CNN) [复制链接]

本帖最后由 cc1989summer 于 2024-10-4 00:29 编辑

 

上一篇我们学习了卷积神经网络(CNN)的概念与原理

https://bbs.eeworld.com.cn/thread-1295074-1-1.html

 

 

下面是运用卷积神经网络,进行经典的手写数字识别的过程。

  

输入是一张28*28像素的黑白照片。经过卷积、池化、激活、全链接,最后输出0~10个数字的概率。

 

但说了那么多,理论和实践总有隔阂,不如跑个例子实践实践,加深认识。

 

 

在开始Pytorch进行手写识别前,首先安装Python、Anaconda、与Pytorch,设置好虚拟环境。

详见:

https://bbs.eeworld.com.cn/thread-1294276-1-1.html

 

接下来安装Pycharm软件:(免费社区版)

https://www.jetbrains.com/pycharm/download/?section=windows

 

  

 

 

安装完成后需要关联好前面设置的虚拟环境。

 

Anaconda中设置好的虚拟环境:

 

该虚拟环境目录下对应的Python程序

  

 

 

Pycharm中关联好前面设置的虚拟环境

  

  

 

设置完成后,进行测试:

 

import torch

print(torch.__version__)

运行结果正常:

  

接下来安装几个基本的软件包。

 

pip install torch torchvision matplotlib

 

缺什么就在Pycharm命令行输入安装指令:

 

  

 

接下来我们步入正题,进行手写识别。

需要用到MNIST数据集

MNIST数据集来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST)。训练集(training set)由来自250个不同人手写的数字构成,其中50%是高中学生,50%来自人口普查局(the Census Bureau)的工作人员。测试集(test set)也是同样比例的手写数字数据,但保证了测试集和训练集的作者集不相交。

MNIST数据集一共有7万张图片,其中6万张是训练集,1万张是测试集。每张图片是28 × 28 28\times 2828×28的0 − 9 0-90−9的手写数字图片组成。每个图片是黑底白字的形式,黑底用0表示,白字用0-1之间的浮点数表示,越接近1,颜色越白。

 

其实就是下面几个文件,接下来的例程会自动帮我们下载。

  

第一步,加载MNIST数据集

import torch

from torch.utils.data import DataLoader

from torchvision import datasets, transforms

import matplotlib.pyplot as plt

# 数据预处理:将图像转换为张量,并进行标准化

transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])

# 下载并加载 MNIST 训练集和测试集

train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)

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

# 加载数据集

train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)

test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)

# 查看数据集的大小

print(f"训练集大小: {len(train_dataset)}")

print(f"测试集大小: {len(test_dataset)}")

# 可视化部分样本

examples = enumerate(train_loader)

batch_idx, (example_data, example_targets) = next(examples)

plt.figure(figsize=(10, 3))

for i in range(6):

    plt.subplot(1, 6, i + 1)

    plt.imshow(example_data[i][0], cmap='gray')

    plt.title(f"Label: {example_targets[i]}")

    plt.axis('off')

plt.show()

 

以下是运行结果。

  

还可以查看更多。

  

 

 

第二步,构建卷积神经网络

 

 

 

import torch.nn as nn

import torch.nn.functional as F

# 定义 CNN 模型

class CNN(nn.Module):

    def __init__(self):

        super(CNN, self).__init__()

        # 卷积层1: 输入通道为1(灰度图),输出通道为16,卷积核大小为3x3

        self.conv1 = nn.Conv2d(1, 16, kernel_size=3)

        # 卷积层2: 输入通道为16,输出通道为32,卷积核大小为3x3

        self.conv2 = nn.Conv2d(16, 32, kernel_size=3)

        # 全连接层1: 输入为32*5*5(展平后的特征图),输出为128

        self.fc1 = nn.Linear(32 * 5 * 5, 128)

        # 全连接层2: 输入为128,输出为10(10个类别)

        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):

        # 卷积层 + ReLU + 最大池化层

        x = F.relu(F.max_pool2d(self.conv1(x), 2))

        x = F.relu(F.max_pool2d(self.conv2(x), 2))

        # 展平成一维向量

        x = x.view(-1, 32 * 5 * 5)

        # 全连接层 + ReLU

        x = F.relu(self.fc1(x))

        # 输出层

        x = self.fc2(x)

        return x

# 实例化模型

model = CNN()

print(model)

仔细研究代码,正是我们前面讲到的卷积层、池化、激活、全链接。

运行结果如下:

 

  

 

第三步,训练模型

 

import torch

from torch.utils.data import DataLoader

from torchvision import datasets, transforms

import matplotlib.pyplot as plt

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

# 数据预处理:将图像转换为张量,并进行标准化

transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])

# 下载并加载 MNIST 训练集和测试集

train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)

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

# 加载数据集

train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)

test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)

# 定义 CNN 模型

class CNN(nn.Module):

    def __init__(self):

        super(CNN, self).__init__()

        # 卷积层1: 输入通道为1(灰度图),输出通道为16,卷积核大小为3x3

        self.conv1 = nn.Conv2d(1, 16, kernel_size=3)

        # 卷积层2: 输入通道为16,输出通道为32,卷积核大小为3x3

        self.conv2 = nn.Conv2d(16, 32, kernel_size=3)

        # 全连接层1: 输入为32*5*5(展平后的特征图),输出为128

        self.fc1 = nn.Linear(32 * 5 * 5, 128)

        # 全连接层2: 输入为128,输出为10(10个类别)

        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):

        # 卷积层 + ReLU + 最大池化层

        x = F.relu(F.max_pool2d(self.conv1(x), 2))

        x = F.relu(F.max_pool2d(self.conv2(x), 2))

        # 展平成一维向量

        x = x.view(-1, 32 * 5 * 5)

        # 全连接层 + ReLU

        x = F.relu(self.fc1(x))

        # 输出层

        x = self.fc2(x)

        return x

# 实例化模型

model = CNN()

# 定义损失函数和优化器

criterion = nn.CrossEntropyLoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)

# 将模型移动到 GPU(如果可用)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model.to(device)

# 训练模型

epochs = 5

for epoch in range(epochs):

    running_loss = 0.0

    for images, labels in train_loader:

        images, labels = images.to(device), labels.to(device)

        # 前向传播

        outputs = model(images)

        loss = criterion(outputs, labels)

        # 反向传播和优化

        optimizer.zero_grad()

        loss.backward()

        optimizer.step()

        running_loss += loss.item()

    print(f"Epoch [{epoch + 1}/{epochs}], Loss: {running_loss / len(train_loader):.4f}")

print("训练完成!")

 

经过5次训练,损失函数越来越低,说明正确率提高了

 

 

 

 

 

第四步,测试模型

 

测试环节,我们可以自己画一个图去进行识别,也可以从训练集里抽一个图去测试。

# 从测试集中取出一个样本

example_data, example_target = next(iter(test_loader))

example_data = example_data.to(device)

# 使用模型进行预测

model.eval()

with torch.no_grad():

    output = model(example_data)

# 可视化预测结果

plt.figure(figsize=(10, 3))

for i in range(6):

    plt.subplot(1, 6, i + 1)

    plt.imshow(example_data[i][0].cpu(), cmap='gray')

    plt.title(f"预测: {torch.argmax(output[i]).item()}")

    plt.axis('off')

plt.show()

 

运行结果如以下,百发百中有木有?

准确率98.93%

 

  

 

 

而如果我们把训练模型这段程序拿掉,正确率一下子就很低了,基本全错。

 

# 训练模型

epochs = 5

for epoch in range(epochs):

    running_loss = 0.0

    for images, labels in train_loader:

        images, labels = images.to(device), labels.to(device)

        # 前向传播

        outputs = model(images)

        loss = criterion(outputs, labels)

        # 反向传播和优化

        optimizer.zero_grad()

        loss.backward()

        optimizer.step()

        running_loss += loss.item()

    print(f"Epoch [{epoch + 1}/{epochs}], Loss: {running_loss / len(train_loader):.4f}")

print("训练完成!")

 

  

 

本次的分享就到这里。

此帖出自编程基础论坛

最新回复

感谢分享呀。。。。。。。。。。。。。。。。。。。。。。   详情 回复 发表于 2024-10-14 09:19
点赞 关注(1)
 

回复
举报

6822

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

如果我们把训练模型这段程序拿掉,正确率一下子就很低了,基本全错,好吧

此帖出自编程基础论坛

点评

目前还没搞清楚,怎么把训练过的模型保存固定下来,后面做识别直接拿来用,而不用每次识别都要重新从头训练一遍,训练太耗时了(>2分钟)。  详情 回复 发表于 2024-10-6 11:18
 
 
 

回复

169

帖子

1

TA的资源

纯净的硅(初级)

板凳
 
Jacktang 发表于 2024-10-6 09:29 如果我们把训练模型这段程序拿掉,正确率一下子就很低了,基本全错,好吧

目前还没搞清楚,怎么把训练过的模型保存固定下来,后面做识别直接拿来用,而不用每次识别都要重新从头训练一遍,训练太耗时了(>2分钟)。

此帖出自编程基础论坛
 
 
 

回复

57

帖子

5

TA的资源

一粒金砂(高级)

4
 

保存整个模型(序列化模型和权重,依赖python环境,不灵活)

torch.save(model, "model.pth")

加载整个模型

model = torch.load("model.pth")

 

只保存权重文件(模型在代码里写好,保存和加载模型和优化器权重,更灵活)

save_dict = {}
save_dict[f'model_state_dict'] = model.state_dict()
save_dict[f'optimizer_state_dict'] = optimizer.state_dict()
torch.save(save_dict,  "state_dict.pth")

 

加载权重文件

checkpoint = torch.load("state_dict.pth")
model.load_state_dict(checkpoint['model_state_dict'])

optimizer.load_state_dict(checkpoint['optimizer_state_dict'])

此帖出自编程基础论坛

点评

谢谢,很详细的解答,我跑跑试试。  详情 回复 发表于 2024-10-12 20:56
 
 
 

回复

553

帖子

3

TA的资源

纯净的硅(初级)

5
 

训练好的模型是可以保存的,下次使用直接load,无需重新训练

此帖出自编程基础论坛

点评

好的,谢谢解答。  详情 回复 发表于 2024-10-12 20:56
 
 
 

回复

169

帖子

1

TA的资源

纯净的硅(初级)

6
 
MioChan 发表于 2024-10-12 17:50 保存整个模型(序列化模型和权重,依赖python环境,不灵活) torch.save(model, "model.pth") 加 ...

谢谢,很详细的解答,我跑跑试试。

此帖出自编程基础论坛
 
 
 

回复

169

帖子

1

TA的资源

纯净的硅(初级)

7
 
xinmeng_wit 发表于 2024-10-12 20:50 训练好的模型是可以保存的,下次使用直接load,无需重新训练

好的,谢谢解答。

此帖出自编程基础论坛
 
 
 

回复

1388

帖子

1

TA的资源

五彩晶圆(初级)

8
 

感谢分享呀。。。。。。。。。。。。。。。。。。。。。。

此帖出自编程基础论坛

点评

嘿嘿,大家共同进步。  详情 回复 发表于 2024-10-14 15:32
 
 
 

回复

169

帖子

1

TA的资源

纯净的硅(初级)

9
 
hellokitty_bean 发表于 2024-10-14 09:19 感谢分享呀。。。。。。。。。。。。。。。。。。。。。。

嘿嘿,大家共同进步。

此帖出自编程基础论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表