全连接神经网络的手写数字识别——使用PaddlePaddle实现
利用全连接神经网络完成一个案例,有助于帮助同学们进一步理解深度学习
·
一、引言
手写数字识别是计算机视觉领域的一个重要课题,广泛应用于邮政编码识别、银行支票处理等领域。近年来,随着深度学习技术的快速发展,神经网络在图像识别任务中取得了显著的成果。本文将介绍如何使用PaddlePaddle框架构建一个全连接神经网络,实现手写数字识别。
二、PaddlePaddle简介
PaddlePaddle是百度开源的一款深度学习框架,具有易用、高效、可扩展等特点。它提供了丰富的API,支持多种深度学习模型,可以轻松实现全连接神经网络、卷积神经网络、循环神经网络等。
三、数据准备
本文使用的手写数字数据集为MNIST,它包含了0到9的手写数字图片,共有60000个训练样本和10000个测试样本。每个样本都是一个28x28的灰度图像。
首先,我们需要加载数据集并进行预处理:
import paddle
from paddle.vision.transforms import ToTensor
# 加载MNIST数据集
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=ToTensor())
train_dataloader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataloader = paddle.io.DataLoader(test_dataset, batch_size=64, shuffle=True)
四、构建全连接神经网络
全连接神经网络(Fully Connected Neural Network,FCNN)是一种最简单的神经网络结构,每个神经元都与上一层的所有神经元相连。下面我们使用PaddlePaddle构建一个全连接神经网络:
import paddle.nn as nn
# 定义全连接神经网络
class FCNN(nn.Layer):
def __init__(self):
super(FCNN, self).__init__()
self.fc1 = nn.Linear(in_features=28*28, out_features=500)
self.fc2 = nn.Linear(in_features=500, out_features=10)
def forward(self, x):
x = paddle.flatten(x, 1) # 将输入展平
x = nn.functional.relu(self.fc1(x))
x = self.fc2(x)
return x
model = FCNN()
五、模型训练
接下来,我们对模型进行训练。首先定义损失函数和优化器:
# 定义损失函数
loss_fn = nn.CrossEntropyLoss()
# 定义优化器
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.001)
然后进行训练:
# 训练模型
epochs = 5
for epoch in range(epochs):
model.train()
for batch_id, data in enumerate(train_dataloader):
x_data, y_data = data
y_pred = model(x_data)
loss = loss_fn(y_pred, y_data)
loss.backward()
optimizer.step()
optimizer.clear_grad()
if batch_id % 100 == 0:
print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_id}], Loss: {loss.numpy()}")
六、模型评估
训练完成后,我们使用测试数据集对模型进行评估:
# 评估模型
model.eval()
total_correct = 0
total_samples = 0
for data in test_dataloader:
x_data, y_data = data
y_pred = model(x_data)
correct = paddle.sum(paddle.cast(paddle.argmax(y_pred, axis=1) == y_data.squeeze(1), dtype='int32'))
total_correct += correct.numpy()
total_samples += x_data.shape[0]
print(f"模型准确率:{total_correct / total_samples}")
七、总体代码
import paddle
from paddle.vision.transforms import ToTensor
import paddle.nn as nn
# 定义全连接神经网络
class FCNN(nn.Layer):
def __init__(self):
super(FCNN, self).__init__()
self.fc1 = nn.Linear(in_features=28 * 28, out_features=500)
self.fc2 = nn.Linear(in_features=500, out_features=10)
def forward(self, x):
x = paddle.flatten(x, 1) # 将输入展平
x = nn.functional.relu(self.fc1(x))
x = self.fc2(x)
return x
if __name__ == '__main__':
# 加载MNIST数据集
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=ToTensor())
train_dataloader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataloader = paddle.io.DataLoader(test_dataset, batch_size=64, shuffle=True)
model = FCNN()
# 定义损失函数
loss_fn = nn.CrossEntropyLoss()
# 定义优化器
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.001)
# 训练模型
epochs = 5
for epoch in range(epochs):
model.train()
for batch_id, data in enumerate(train_dataloader):
x_data, y_data = data
y_pred = model(x_data)
loss = loss_fn(y_pred, y_data)
loss.backward()
optimizer.step()
optimizer.clear_grad()
if batch_id % 100 == 0:
print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_id}], Loss: {loss.numpy()}")
# 评估模型
model.eval()
total_correct = 0
total_samples = 0
for data in test_dataloader:
x_data, y_data = data
y_pred = model(x_data)
correct = paddle.sum(paddle.cast(paddle.argmax(y_pred, axis=1) == y_data.squeeze(1), dtype='int32'), axis=0)
total_correct += correct.numpy()
total_samples += x_data.shape[0]
print(f"模型准确率:{total_correct / total_samples}")
# 保存模型
paddle.save(model.state_dict(), 'mnist_model.pdparams')
八、训练完成后的使用
# 导入paddle库,这是百度提供的深度学习框架
import paddle
# 导入将图像转换为张量的方法
from paddle.vision.transforms import ToTensor
# 导入神经网络模块,用于定义神经网络层
import paddle.nn as nn
# 从main模块导入我们定义的全连接神经网络类FCNN 也可以自己在本文文件中再定义一个class FCNN 要和之前训练的模型类一模一样。
from main import FCNN
# 实例化我们的模型FCNN
model = FCNN()
# 设置模型进入评估模式,这意味着如Dropout或BatchNorm层会使用不同的行为
model.eval()
# 从磁盘加载模型的参数
model_state_dict = paddle.load('mnist_model.pdparams')
# 将加载的参数设置到模型中
model.set_state_dict(model_state_dict)
# 定义一个函数来处理单张图片并返回其预测结果
def predict(img_path):
# 加载图片,这里的实现可能依赖于具体的实现细节
img = paddle.vision.image_load(img_path)
# 将图片转换为张量类型,并进行归一化处理
img = ToTensor()(img)
# 增加一个维度,模拟batch_size=1的情况,因为模型训练时可能是批量输入
img = paddle.unsqueeze(img, axis=0)
# 使用模型进行预测
pred = model(img)
# 获取预测结果中的最大值索引,即为预测类别
predicted_class = pred.argmax(axis=1).numpy()
# 返回预测类别
return predicted_class
# 调用predict函数来预测指定路径下的图片
ans = predict('dataset/test/0/0.jpg')
# 打印预测结果
print(ans)
自定义数据集的训练
当前代码下请保证你的数据集目录结构为:
dataset/
train/
0/
0_0.jpg
0_1.jpg
...
1/
1_0.jpg
1_1.jpg
...
...
import os
from PIL import Image
import paddle
from paddle import nn
from paddle.vision.transforms import Compose, ToTensor
# 定义模型
class FCNN(nn.Layer):
def __init__(self):
super(FCNN, self).__init__()
self.fc1 = nn.Linear(in_features=28 * 28, out_features=500)
self.fc2 = nn.Linear(in_features=500, out_features=10)
def forward(self, x):
x = paddle.flatten(x, 1) # 将输入展平
x = nn.functional.relu(self.fc1(x))
x = self.fc2(x)
return x
# 自定义数据集
class CustomDataset(paddle.io.Dataset):
def __init__(self, root_dir, transform=None):
"""
初始化方法
:param root_dir: 数据集根目录
:param transform: 可选的变换函数
"""
super().__init__()
self.root_dir = root_dir
self.transform = transform
self.images, self.labels = self._load_data()
def _load_data(self):
images = []
labels = []
for label in os.listdir(self.root_dir):
class_dir = os.path.join(self.root_dir, label)
for image_name in os.listdir(class_dir):
img_path = os.path.join(class_dir, image_name)
images.append(img_path)
labels.append(int(label))
return images, labels
def __getitem__(self, index):
"""
获取一个样本
:param index: 样本索引
:return: (image, label) 元组
"""
img_path, label = self.images[index], self.labels[index]
image = Image.open(img_path).convert('L') # 假设是灰度图
if self.transform is not None:
image = self.transform(image)
return image, label
def __len__(self):
"""
返回数据集中样本的数量
:return: 样本数量
"""
return len(self.images)
if __name__ == '__main__':
# 使用自定义数据集
train_dataset = CustomDataset(root_dir='dataset/train', transform=Compose([ToTensor()]))
train_dataloader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
# 定义模型、损失函数、优化器等
model = FCNN()
loss_fn = nn.CrossEntropyLoss()
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.001)
# 训练模型
epochs = 5
for epoch in range(epochs):
model.train()
for batch_id, (x_data, y_data) in enumerate(train_dataloader):
y_pred = model(x_data)
loss = loss_fn(y_pred, y_data)
loss.backward()
optimizer.step()
optimizer.clear_grad()
if batch_id % 100 == 0:
print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_id}], Loss: {loss.numpy()}")
# 保存模型
paddle.save(model.state_dict(), 'mnist_model.pdparams')
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)