基于华为云开发者空间的—PyTorch手写体识别实战案例【华为开发者空间】
基于华为云开发者空间的—PyTorch手写体识别实战案例
项目概述
华为云开发者空间
华为云开发者空间汇聚了华为的优质开发资源及工具,旨在为全球开发者提供一个高效、便捷的开发环境。开发者可以在此平台上进行应用的构建、开发、调试、测试、发布和管理,享受从应用构建到发布的全生命周期支持。
核心功能
- 云主机:华为云为每个新生态的开发者免费提供一台云主机,预集成CodeArts IDE、代码仓及JDK、Python等运行时插件,解决本地开发环境中配置复杂、稳定性不足和依赖等问题,为开发者提供性能强大、安全、稳定、高效的开发环境。
- 开发工具:平台聚合了以华为云CodeArts IDE为核心的多元生态开发工具及资源,包括鲲鹏、昇腾、鸿蒙生态的开发工具资源入口,以及丰富的开源镜像、热门开发插件等,覆盖代码托管、开发编译、测试、部署、运维等应用构建全旅程,高效支撑开发者进行各类场景的应用开发。
- API和SDK支持:平台提供全面的API和SDK支持,涵盖安卓、Web以及跨平台开发需求,从位置服务到AI人脸识别,从推送通知到广告集成,满足开发者的多样化需求。
- 技术赋能课程:华为云开发者空间提供海量的技术赋能课程和专业开发者认证内容,帮助开发者提升技能水平,更好地适应市场需求。
平台优势
- 一站式管理:项目的配置、服务启用、代码调试、上线发布等全部都在同一平台操作,无需切换平台,大大提高了效率。
- 丰富的资源:平台汇聚了华为的优质开发资源和工具,为开发者提供强大的技术支持。
- 专业的文档和开发者支持:华为开发者空间的文档详尽而清晰,不仅列出了接口和功能,还提供了操作指南和实用的开发示例。在开发过程中遇到问题,文档通常能够迅速找到解决方案。
使用流程
- 登录华为云首页,点击“开发者->开发者空间”,进入开发者空间页面。
- 点击“立即申请”按钮,申请开发者空间账号。
- 在开发者空间页面,点击“开发桌面(云主机)”按钮,进入云主机配置页面。
- 根据需求配置个人云主机,选择安装Python或Java工具集等,然后点击“安装”按钮。
- 等待环境云主机下载镜像、安装系统、安装工具集。云主机就绪后,点击“在浏览器打开”连接云主机。
- 如果提示实名认证,按照流程指引进行实名认证后,即可使用云主机。
实验背景与目标
深度学习在手写体识别中的应用
随着深度学习技术的迅速发展,手写体识别的准确率得到了显著提升,成为近年来的研究热点之一。该领域的进步不仅推动了智能化系统的发展,还在文档数字化、教育辅助等场景中展现了广阔的应用前景。
PyTorch框架的优势
PyTorch凭借其动态计算图、高效的调试能力和简洁的语法,成为手写体识别项目的首选框架。它的灵活性和可扩展性极大地方便了模型的开发与优化。
项目的技术挑战
手写体识别技术在应对字体多样性、书写风格差异、笔迹不连续等问题时面临诸多挑战。这些因素增加了模型的复杂性,迫使开发者探索更强大的算法与优化策略。
预期成果与实际应用
本项目基于华为云开发者空间搭建,旨在开发一个具有高准确率的手写体识别系统。预期成果包括:
- 提供一种高效、鲁棒的手写体识别解决方案;
- 推动文档数字化转型,提高文档管理效率;
- 支持教育辅助系统,例如自动批改手写试卷、生成手写体练习分析等功能。
MNIST数据集介绍
MNIST(Modified National Institute of Standards and Technology database)数据集是一个手写体数字图片的图像数据集。它包含了大量的手写数字图片,每张图片都对应一个0到9之间的数字标签,这些标签都是经过人工准确标注的。
实验环境与准备
为了顺利开展手写体识别实验,我们将在华为云开发者空间中搭建实验环境并安装必要的软件和工具。以下是具体步骤:
1. 打开华为云开发者空间并启动云主机
进入华为云开发者空间后,找到云主机并点击启动:
云主机启动完成后的界面如下:
2. 下载并安装 PyCharm
进入云主机后,打开左侧的 Firefox 浏览器,访问以下链接以下载 PyCharm:
PyCharm 官方下载页面
下载完成后,界面如下:
安装 PyCharm 后,可以进入其主界面:
3. 安装 PyTorch
在云主机中打开终端,使用以下命令安装 PyTorch:
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
4. 安装 Matplotlib
继续在终端中运行以下命令以安装 Matplotlib,可用于数据可视化:
pip install matplotlib
通过上述步骤,实验环境已经配置完毕。我们成功地搭建了基于华为云的开发环境,并安装了用于手写体识别的必备工具和依赖,包括 PyCharm、PyTorch 和 Matplotlib,为后续实验提供了坚实的基础。
模型架构设计
在本项目中,我们采用基于卷积神经网络(CNN, Convolutional Neural Network)的模型架构来实现手写体识别。CNN 在图像分类任务中表现卓越,具有较强的特征提取能力,尤其适用于 MNIST 数据集中手写数字图片的模式学习。以下是模型设计的详细说明:
1. 模型结构概览
该模型由以下部分组成:
- 输入层:接受 28x28 的灰度图像数据。
- 卷积层(Convolutional Layers):提取图片中的局部特征,如边缘、线条等。
- 池化层(Pooling Layers):对特征进行降维操作,减少计算量并增强模型的平移不变性。
- 全连接层(Fully Connected Layers):将特征映射到高维空间,最终输出每个类别的概率。
- 输出层:使用 Softmax 函数,输出 10 个类别的预测概率。
2. 详细架构描述
层级 | 类型 | 参数说明 |
---|---|---|
输入层 | - | 图像大小为 28x28x1(灰度图),批量大小 Batch Size 可调。 |
卷积层1 | 卷积 | 卷积核大小 3x3,输入通道数 1,输出通道数 32,激活函数为 ReLU。 |
池化层1 | 最大池化 | 池化窗口大小 2x2,步长 2。 |
卷积层2 | 卷积 | 卷积核大小 3x3,输入通道数 32,输出通道数 64,激活函数为 ReLU。 |
池化层2 | 最大池化 | 池化窗口大小 2x2,步长 2。 |
Dropout | Dropout 正则化 | 丢弃率设置为 0.25,防止过拟合。 |
展平层 | Flatten | 将二维特征图展开为一维特征向量,输入大小 64x7x7(即 Flatten 为 3136)。 |
全连接层1 | 全连接 | 128 个神经元,激活函数为 ReLU,包含 Dropout(丢弃率 0.5)。 |
全连接层2(输出) | 全连接 | 10 个神经元,激活函数为 Softmax,输出 10 类的概率分布。 |
3. 网络结构图示
4. 核心模块设计分析
卷积层
- 卷积层通过局部感知机制捕获图像特征。
- 第一个卷积层采用 32 个卷积核,特征提取能力适中,适用于简单的 MNIST 数据集。
- 第二个卷积层的卷积核数量增加到 64,能够提取更高阶的特征。
池化层
- 最大池化有效减少特征图的大小,保留主要特征并增强网络的鲁棒性。
- 池化窗口为 2x2,可将每层特征图尺寸减半,降低计算成本。
Dropout
- Dropout 在训练过程中随机丢弃部分神经元,缓解过拟合问题,提升模型泛化能力。
全连接层
- 展平层将二维特征图展开为一维向量,为全连接层输入做好准备。
- 全连接层负责将抽象的特征映射到类别标签空间,经过激活函数后输出分类结果。
Softmax 输出层
- Softmax 层对全连接层的输出进行归一化,生成属于每个类别的概率值,确保总概率和为 1。
5. 实现代码示例(PyTorch)
以下是基于上述设计的 PyTorch 模型代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
class HandwritingRecognitionModel(nn.Module):
def __init__(self):
super(HandwritingRecognitionModel, self).__init__()
# 卷积层1
self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1)
# 卷积层2
self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)
# 最大池化层
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
# Dropout层
self.dropout1 = nn.Dropout(0.25)
self.dropout2 = nn.Dropout(0.5)
# 全连接层1
self.fc1 = nn.Linear(64 * 7 * 7, 128)
# 全连接层2
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = self.pool(x)
x = F.relu(self.conv2(x))
x = self.pool(x)
x = self.dropout1(x)
x = x.view(-1, 64 * 7 * 7) # 展平
x = F.relu(self.fc1(x))
x = self.dropout2(x)
x = self.fc2(x)
return F.log_softmax(x, dim=1)
# 模型实例化
model = HandwritingRecognitionModel()
print(model)
6. 设计优势
- 高效性:通过卷积和池化的层级组合,模型能够快速提取特征并减少计算复杂度。
- 鲁棒性:通过 Dropout 和正则化手段有效降低过拟合风险。
- 灵活性:设计简单且易扩展,可适配更复杂的数据集和应用场景。
该模型结构在手写体识别任务中具有出色的表现,并为后续优化提供了良好的基础。
实验代码实现
import torch
import numpy as np
from matplotlib import pyplot as plt
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
import torch.nn.functional as F
"""
卷积运算 使用mnist数据集,和10-4,11类似的,只是这里:1.输出训练轮的acc 2.模型上使用torch.nn.Sequential
"""
batch_size = 64
learning_rate = 0.01
momentum = 0.5
EPOCH = 10
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
# softmax归一化指数函数,其中0.1307是mean均值和0.3081是std标准差
train_dataset = datasets.MNIST(root='./data/mnist', train=True, transform=transform,download=True) # 本地没有就加上download=True
test_dataset = datasets.MNIST(root='./data/mnist', train=False, transform=transform,download=True) # train=True训练集,=False测试集
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
fig = plt.figure()
for i in range(12):
plt.subplot(3, 4, i+1)
plt.tight_layout()
plt.imshow(train_dataset.train_data[i], cmap='gray', interpolation='none')
plt.title("Labels: {}".format(train_dataset.train_labels[i]))
plt.xticks([])
plt.yticks([])
plt.show()
# 训练集乱序,测试集有序
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = torch.nn.Sequential(
torch.nn.Conv2d(1, 10, kernel_size=5),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2),
)
self.conv2 = torch.nn.Sequential(
torch.nn.Conv2d(10, 20, kernel_size=5),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2),
)
self.fc = torch.nn.Sequential(
torch.nn.Linear(320, 50),
torch.nn.Linear(50, 10),
)
def forward(self, x):
batch_size = x.size(0)
x = self.conv1(x) # 一层卷积层,一层池化层,一层激活层(图是先卷积后激活再池化,差别不大)
x = self.conv2(x) # 再来一次
x = x.view(batch_size, -1) # flatten 变成全连接网络需要的输入 (batch, 20,4,4) ==> (batch,320), -1 此处自动算出的是320
x = self.fc(x)
return x # 最后输出的是维度为10的,也就是(对应数学符号的0~9)
model = Net()
# Construct loss and optimizer ------------------------------------------------------------------------------
criterion = torch.nn.CrossEntropyLoss() # 交叉熵损失
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum) # lr学习率,momentum冲量
# Train and Test CLASS --------------------------------------------------------------------------------------
# 把单独的一轮一环封装在函数类里
def train(epoch):
running_loss = 0.0 # 这整个epoch的loss清零
running_total = 0
running_correct = 0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
optimizer.zero_grad()
# forward + backward + update
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
# 把运行中的loss累加起来,为了下面300次一除
running_loss += loss.item()
# 把运行中的准确率acc算出来
_, predicted = torch.max(outputs.data, dim=1)
running_total += inputs.shape[0]
running_correct += (predicted == target).sum().item()
if batch_idx % 300 == 299: # 不想要每一次都出loss,浪费时间,选择每300次出一个平均损失,和准确率
print('[%d, %5d]: loss: %.3f , acc: %.2f %%'
% (epoch + 1, batch_idx + 1, running_loss / 300, 100 * running_correct / running_total))
running_loss = 0.0 # 这小批300的loss清零
running_total = 0
running_correct = 0 # 这小批300的acc清零
# torch.save(model.state_dict(), './model_Mnist.pth')
# torch.save(optimizer.state_dict(), './optimizer_Mnist.pth')
def test():
correct = 0
total = 0
with torch.no_grad(): # 测试集不用算梯度
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, dim=1) # dim = 1 列是第0个维度,行是第1个维度,沿着行(第1个维度)去找1.最大值和2.最大值的下标
total += labels.size(0) # 张量之间的比较运算
correct += (predicted == labels).sum().item()
acc = correct / total
print('[%d / %d]: Accuracy on test set: %.1f %% ' % (epoch+1, EPOCH, 100 * acc)) # 求测试的准确率,正确数/总数
return acc
# Start train and Test --------------------------------------------------------------------------------------
if __name__ == '__main__':
acc_list_test = []
for epoch in range(EPOCH):
train(epoch)
# if epoch % 10 == 9: #每训练10轮 测试1次
acc_test = test()
acc_list_test.append(acc_test)
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()
代码作用总结
这段代码的主要功能是 利用卷积神经网络(CNN)实现对 MNIST 手写数字数据集的分类任务。其具体作用如下:
- 数据加载与预处理:
- 利用
torchvision.datasets.MNIST
下载并加载 MNIST 数据集。 - 对数据进行标准化处理,使其均值为 0.1307,标准差为 0.3081,有助于加速模型收敛。
- 使用
DataLoader
将数据划分为训练集和测试集,方便进行批量处理。
- 模型定义:
- 构建了一个简单的 CNN 模型,包括两层卷积层和一层全连接层。
- 卷积层 提取输入图片的局部特征。
- 激活函数 引入非线性能力。
- 池化层 减少特征维度,保留关键信息。
- 全连接层 将提取的特征映射到分类结果(数字 0~9)。
- 训练过程:
- 通过交叉熵损失函数和 SGD 优化器,逐步调整模型参数以最小化分类误差。
- 在每个
epoch
中,模型通过多批次训练逐渐学习手写数字的特征。 - 每隔 300 次批次打印一次当前的损失值和准确率,用于监控训练效果。
- 测试过程:
- 在测试集上评估模型的性能,计算整体分类准确率。
- 记录每轮训练后的测试集准确率,用于分析模型在未见数据上的泛化能力。
- 结果可视化:
- 绘制测试集准确率随训练轮次变化的曲线图,清晰展示模型性能的提升趋势。
核心目标
代码的核心目标是通过构建和训练 CNN 模型,实现对手写数字图片的 准确分类,并通过可视化手段直观地展示模型的学习效果。
应用场景
- 深度学习入门:
- 适合作为学习 PyTorch 和 CNN 的基础案例,涵盖了数据加载、模型构建、训练和评估全流程。
- MNIST 数据集研究:
- 为后续更复杂网络的开发(如 ResNet、Transformer)奠定基础。
- 分类任务的基础框架:
- 模型结构与训练框架可以扩展到其他图片分类任务。
训练过程如下:
总结
本篇文章详细介绍了华为云开发者空间的优势和使用流程,结合PyTorch完成了手写体识别的完整实践。通过免费云主机和在线开发环境,开发者可以快速搭建实验环境并实现深度学习项目。
文章以手写体识别为案例,基于卷积神经网络(CNN)设计了模型架构,包括输入层、卷积层、池化层和全连接层。实验过程中利用MNIST数据集进行训练和测试,展示了模型的构建、优化与性能评估。
通过此次实践,证明了华为云开发者空间在深度学习项目中的便捷性和高效性,为文档数字化、教育系统等应用提供了技术支持,极具参考价值。
正在参加【有奖征集 第34期】华为开发者空间一行代码快速上云,参与视频、文章投稿赢2000元开发者礼包
链接:https://bbs.huaweicloud.com/blogs/438987
- 点赞
- 收藏
- 关注作者
评论(0)