# 手写数字识别 **Repository Path**: swjtuhc-software-studio/handwritten-digit-recognition ## Basic Information - **Project Name**: 手写数字识别 - **Description**: 利用深度学习框架完成手写数字识别 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-25 - **Last Updated**: 2024-10-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 一、引言 手写数字识别是计算机视觉领域的一个重要课题,广泛应用于邮政编码识别、银行支票处理等领域。近年来,随着深度学习技术的快速发展,神经网络在图像识别任务中取得了显著的成果。本文将介绍如何使用PaddlePaddle框架构建一个全连接神经网络,实现手写数字识别。 ## 二、PaddlePaddle简介 PaddlePaddle是百度开源的一款深度学习框架,具有易用、高效、可扩展等特点。它提供了丰富的API,支持多种深度学习模型,可以轻松实现全连接神经网络、卷积神经网络、循环神经网络等。 ## 三、数据准备 本文使用的手写数字数据集为MNIST,它包含了0到9的手写数字图片,共有60000个训练样本和10000个测试样本。每个样本都是一个28x28的灰度图像。 首先,我们需要加载数据集并进行预处理: ```python 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构建一个全连接神经网络: ```python 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() ``` ## 五、模型训练 接下来,我们对模型进行训练。首先定义损失函数和优化器: ```python # 定义损失函数 loss_fn = nn.CrossEntropyLoss() # 定义优化器 optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.001) ``` 然后进行训练: ```python # 训练模型 epochs = 5 for epoch in range(epochs): 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()}") ``` ## 六、模型评估 训练完成后,我们使用测试数据集对模型进行评估: ```python # 评估模型 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}") ``` ## 七、总体代码 ```python 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): 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') ``` ## 八、训练完成后的使用 ```python # 导入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) ``` ## 自定义数据集的训练 当前代码下请保证你的数据集目录结构为: ```python dataset/ train/ 0/ 0_0.jpg 0_1.jpg ... 1/ 1_0.jpg 1_1.jpg ... ... ``` ```python 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): 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') ```