• 基于Paddle的手写数字识别模型


      百度飞桨(paddlepaddle)是百度的开源深度学习平台,今天就利用paddle来编写入门级的手写数字模型.

    一,准备数据

    1. 下载数据集,这里我们使用的是MNIST数据集

      1. # 下载原始的 MNIST 数据集并进行解压
      2. wget https://paddle-imagenet-models-name.bj.bcebos.com/data/mnist.tar
      3. tar -xf mnist.tar

      数据集的目录格式如下:

      1. mnist.
      2. ├── train
      3. │   └── imgs
      4. │   ├── 0
      5. │   ├── 1
      6. │   ├── 2
      7. │   ├── 3
      8. │   ├── 4
      9. │   ├── 5
      10. │   ├── 6
      11. │   ├── 7
      12. │   ├── 8
      13. │   └── 9
      14. └── val
      15. └── imgs
      16. ├── 0
      17. ├── 1
      18. ├── 2
      19. ├── 3
      20. ├── 4
      21. ├── 5
      22. ├── 6
      23. ├── 7
      24. ├── 8
      25. └── 9

      train和val目录下均有一个标签文件label.txt

    2. 定义数据加载模块,这里使用百度paddle提供paddle.io.Dataset来实现自定义的MyDataSet:
      1. class MyDataSet(Dataset):
      2. def __init__(self, data_dir, label_path, tansform=None):
      3. super(MyDataSet, self).__init__()
      4. self.data_list = []
      5. with open(label_path, encoding='utf-8') as f:
      6. for line in f.readlines():
      7. image_path, label = line.split('\t')
      8. image_path = os.path.join(data_dir, image_path)
      9. self.data_list.append([image_path, label])
      10. self.tansform = tansform
      11. def __getitem__(self, index):
      12. image_path, label = self.data_list[index]
      13. image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
      14. image = image.astype('float32')
      15. # 应用图像变换
      16. if self.tansform is not None:
      17. self.tansform(image)
      18. label = int(label)
      19. return image, label
      20. def __len__(self):
      21. return len(self.data_list)

    二,模型实现

    这里我们参照LeNet进行实现,下面看一下LeNet的网络结构

     定义一个MyNet:

    1. class MyNet(nn.Layer):
    2. def __init__(self, num_classes=10):
    3. super().__init__()
    4. self.num_classes = num_classes
    5. # 定义
    6. self.conv1 = nn.Conv2D(1, 6, 3, stride=1, padding=1)
    7. self.conv2 = nn.Conv2D(6, 16, 5, stride=1, padding=0)
    8. self.relu = nn.ReLU()
    9. self.features = nn.Sequential(
    10. self.conv1,
    11. self.relu,
    12. nn.MaxPool2D(2, 2),
    13. self.conv2,
    14. self.relu,
    15. nn.MaxPool2D(2, 2))
    16. if num_classes > 0:
    17. self.linear = nn.Sequential(
    18. nn.Linear(400, 120),
    19. nn.Linear(120, 84),
    20. nn.Linear(84, num_classes)
    21. )
    22. def forward(self, x):
    23. x = self.features(x)
    24. if self.num_classes > 0:
    25. x = paddle.flatten(x, 1)
    26. x = self.linear(x)
    27. return x

    三,模型训练

    1. # 定义一个网络
    2. model = MyNet()
    3. # 可视化模型组网结构和参数
    4. params_info = paddle.summary(model, (1, 1, 28, 28))
    5. print(params_info)

    这里定义一个MyNet的网络,然后查看网络的结构,下面开始进行模型训练

    1. total_epoch = 5
    2. batch_size = 16
    3. # transform = F.normalize(mean=[127.5], std=[127.5], data_format=['CHW'])
    4. transform = Normalize(mean=[127.5], std=[127.5], data_format=['CHW'])
    5. # 训练集
    6. data_dir_train = './mnist/train'
    7. label_path_train = './mnist/train/label.txt'
    8. # 加载数据
    9. train_dataset = MyDataSet(data_dir_train, label_path_train, transform)
    10. val_dataset = MyDataSet(data_dir_val, label_path_val, transform)
    11. print(f'训练图片张数:{len(train_dataset)} 测试集图张数:{len(val_dataset)}')
    12. train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    13. optim = paddle.optimizer.Adam(parameters=model.parameters())
    14. # 设置损失函数
    15. loss_fn = paddle.nn.CrossEntropyLoss()
    16. for epoch in range(total_epoch):
    17. for batch_id, data in enumerate(train_loader):
    18. x_data = data[0] # 训练数据
    19. y_data = data[1] # 训练数据标签
    20. # print(y_data)
    21. # print(y_data.shape)
    22. # 增加维度
    23. x_data = paddle.unsqueeze(x_data, axis=1)
    24. predicts = model(x_data) # 预测结果
    25. # print(f'predicts:{predicts} predicts.shape={predicts.shape}')
    26. y_data = paddle.unsqueeze(y_data, axis=1)
    27. # 计算损失 等价于 prepare 中loss的设置
    28. loss = loss_fn(predicts, y_data)
    29. # 计算准确率 等价于 prepare 中metrics的设置
    30. acc = paddle.metric.accuracy(predicts, y_data)
    31. # 下面的反向传播、打印训练信息、更新参数、梯度清零都被封装到 Model.fit() 中
    32. # 反向传播
    33. loss.backward()
    34. # print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id + 1, loss.numpy(),
    35. # acc.numpy()))
    36. if (batch_id + 1) % 100 == 0:
    37. print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id + 1, loss.numpy(),
    38. acc.numpy()))
    39. write_to_log("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id + 1, loss.numpy(),
    40. acc.numpy()))
    41. # 更新参数
    42. optim.step()
    43. # 梯度清零
    44. optim.clear_grad()
    45. paddle.save(model.state_dict(), f'./mynet/mynet.ep{epoch}.pdparams')

    注意输入的数据的维度要与网络结构保持一致 

    四,模型推理

    下面来看一下模型的效果:

    输出结果:

     

     

     

  • 相关阅读:
    程序员面试金典 - 面试题 17.17. 多次搜索
    用Excel绘制统计图
    【ECMAScript6】代理与反射
    python如何使用gspread读取google在线excel数据?
    ElementUI之CUD+表单验证
    7天学完Spring:Spring框架搭建和解析以及Bean对象的创建
    java正则表达式
    WPF——自定义日历
    “智能合约审计:确保区块链应用安全的关键步骤“
    洛谷P5724 【深基4.习5】求极差 / 最大跨度值
  • 原文地址:https://blog.csdn.net/zhouzying/article/details/127973065