添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • 使用卷积神经网络进行图像分类
  • CIFAR-100数据集上基于Vision Transformer 实现图片分类
  • GAMMA比赛多模态眼底图像数据集下基于EfficientNet和ResNet构造fundus_img和oct_img的分类模型
  • MosMedData: 新冠肺炎胸部 CT扫描数据集上基于3D-CNN实现二分类
  • 基于图片相似度的图片搜索
  • 基于U-Net卷积神经网络实现宠物图像分割
  • 通过OCR实现验证码识别
  • 通过Sub-Pixel实现图像超分辨率
  • 人脸关键点检测
  • 点云处理:实现PointNet点云分类
  • 点云处理:实现PointNet点云分割
  • 自然语言处理
  • 用N-Gram模型在莎士比亚文集中训练word embedding
  • IMDB 数据集使用BOW网络的文本分类
  • 使用预训练的词向量完成文本分类任务
  • 使用注意力机制的LSTM的机器翻译
  • 基于Transformer实现英语到西班牙语的翻译任务
  • 使用序列到序列模型完成数字加法
  • 使用协同过滤实现电影推荐
  • 强化学习——Actor Critic Method
  • 强化学习——Advantage Actor-Critic(A2C)
  • 强化学习——Deep Deterministic Policy Gradient (DDPG)
  • 强化学习——DQN玩合成大西瓜
  • 用飞桨框架2.0造一个会下五子棋的AI模型
  • 通过AutoEncoder实现时序数据异常检测
  • Jena Climate时间序列数据集上使用LSTM进行温度的预报
  • 证券数据集下使用LSTM模型预测A股走势
  • 使用动转静完成以图搜图
  • 生成式对抗网络
  • 图像风格迁移模型-CycleGAN
  • 通过DCGAN实现人脸图像生成
  • MNIST数据集下用Paddle框架的动态图模式玩耍经典对抗生成网络(GAN)
  • 城市街景分割数据集下使用对抗网络Pix2Pix根据掩码生成街景
  • API 文档
  • 代码贡献流程
  • 新增 API 开发&提交流程
  • 贡献前阅读
  • 开发 API Python 端
  • 开发 C++ 算子
  • API 设计和命名规范
  • API 文档书写规范
  • API 单测开发及验收规范
  • 算子性能优化 提交流程
  • 算子性能优化 方法介绍
  • 算子性能优化 验收规范
  • Kernel Primitive API
  • API 介绍
  • API 介绍 - IO
  • API 介绍 - Compute
  • API 介绍 - OpFunc
  • API 示例
  • 示例 - ElementwiseAdd
  • 示例 - Reduce
  • 示例 - Model
  • 算子数据类型扩展 提交流程
  • 算子数据类型扩展 验收规范
  • 低精度算子开发贡献指南
  • 低精度算子支持开发规范
  • 低精度算子单测开发规范
  • 曙光开发指南
  • 曙光智算平台-Paddle 源码编译和单测执行
  • Paddle 适配 C86 加速卡详解
  • Paddle 框架下 ROCm(HIP)算子单测修复指导
  • 硬件接入飞桨后端指南
  • 硬件接入飞桨后端方案介绍
  • 训练硬件 Custom Device 接入方案介绍
  • 自定义 Runtime
  • Device 接口
  • Memory 接口
  • Stream 接口
  • Event 接口
  • 集合通讯接口
  • Profiler 接口
  • 自定义 Kernel
  • Kernel 函数声明
  • Kernel 实现接口
  • Context API
  • Tensor API
  • Exception API
  • Kernel 注册接口
  • 新硬件接入示例
  • 文档贡献指南
  • 规范和参考信息
  • 报错信息文案书写规范
  • 代码风格检查指南
  • Paddle CI 测试详解
  • 常见问题与解答
  • 2.0 升级常见问题
  • 安装常见问题
  • 数据及其加载常见问题
  • 组网、训练、评估常见问题
  • 模型保存常见问题
  • 参数调整常见问题
  • 分布式训练常见问题
  • 其他常见问题
  • 2.5.0 Release Note
  • 三、实践:手写数字识别任务

    『手写数字识别』是深度学习里的 Hello World 任务,用于对 0 ~ 9 的十类数字进行分类,即输入手写数字的图片,可识别出这个图片中的数字。

    本任务用到的数据集为 MNIST 手写数字数据集 ,用于训练和测试模型。该数据集包含 60000 张训练图片、 10000 张测试图片、以及对应的分类标签文件,每张图片上是一个 0 ~ 9 的手写数字,分辨率为 28 * 28。部分图像和对应的分类标签如下图所示。

    图 1:MNIST 数据集样例

    开始之前,需要使用下面的命令安装 Python 的 matplotlib 库和 numpy 库,matplotlib 库用于可视化图片,numpy 库用于处理数据。

    # 使用 pip 工具安装 matplotlib 和 numpy
    ! python3 -m pip install matplotlib numpy -i https://mirror.baidu.com/pypi/simple
            

    下面是手写数字识别任务的完整代码,如果想直接运行代码,可以拷贝下面的完整代码到一个Python文件中运行。

    import paddle
    import numpy as np
    from paddle.vision.transforms import Normalize
    transform = Normalize(mean=[127.5], std=[127.5], data_format='CHW')
    # 下载数据集并初始化 DataSet
    train_dataset = paddle.vision.datasets.MNIST(mode='train', transform
    
    
    
    
        
    =transform)
    test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
    # 模型组网并初始化网络
    lenet = paddle.vision.models.LeNet(num_classes=10)
    model = paddle.Model(lenet)
    # 模型训练的配置准备,准备损失函数,优化器和评价指标
    model.prepare(paddle.optimizer.Adam(parameters=model.parameters()), 
                  paddle.nn.CrossEntropyLoss(),
                  paddle.metric.Accuracy())
    # 模型训练
    model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)
    # 模型评估
    model.evaluate(test_dataset, batch_size=64, verbose=1)
    # 保存模型
    model.save('./output/mnist')
    # 加载模型
    model.load('output/mnist')
    # 从测试集中取出一张图片
    img, label = test_dataset[0]
    # 将图片shape从1*28*28变为1*1*28*28,增加一个batch维度,以匹配模型输入格式要求
    img_batch = np.expand_dims(img.astype('float32'), axis=0)
    # 执行推理并打印结果,此处predict_batch返回的是一个list,取出其中数据获得预测结果
    out = model.predict_batch(img_batch)[0]
    pred_label = out.argmax()
    print('true label: {}, pred label: {}'.format(label[0], pred_label))
    # 可视化图片
    from matplotlib import pyplot as plt
    plt.imshow(img[0])
              
    The loss value printed in the log is the current step, and the metric is the average value of previous steps.
    Epoch 1/5
    step 938/938 [==============================] - loss: 0.0519 - acc: 0.9344 - 14ms/step          
    Epoch 2/5
    step 938/938 [==============================] - loss: 0.0239 - acc: 0.9767 - 14ms/step          
    Epoch 3/5
    step 938/938 [==============================] - loss: 0.0416 - acc: 0.9811 - 14ms/step          
    Epoch 4/5
    step 938/938 [==============================] - loss: 0.0084 - acc: 0.9837 - 14ms/step          
    Epoch 5/5
    step 938/938 [==============================] - loss: 0.0838 - acc: 0.9860 - 14ms/step          
    Eval begin...
    step 157/157 [==============================] - loss: 1.7577e-04 - acc: 0.9844 - 6ms/step         
    Eval samples: 10000
    true label: 7, pred label: 7
            

    以上代码使用 MNIST 数据集训练并测试了 LeNet 模型,并最终成功推理出了一张手写数字图片的标签,该图片推理结果是 7 ( pred label: 7),真实标签也是7 (true label: 7)。

    简单地说,深度学习任务一般分为以下几个核心步骤:

  • 数据集定义与加载

  • 模型训练与评估

  • 接下来逐个步骤介绍,帮助你快速掌握使用飞桨框架实践深度学习任务的方法。

    3.1 数据集定义与加载

    飞桨在 paddle.vision.datasets 下内置了计算机视觉(Computer Vision,CV)领域常见的数据集,如 MNIST、Cifar10、Cifar100、FashionMNIST 和 VOC2012 等。在本任务中,先后加载了 MNIST 训练集(mode='train')和测试集(mode='test'),训练集用于训练模型,测试集用于评估模型效果。

    import paddle
    from paddle.vision.transforms import Normalize
    transform = Normalize(mean=[127.5], std=[127.5], data_format='CHW')
    # 下载数据集并初始化 DataSet
    train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
    test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
    # 打印数据集里图片数量
    print('{} images in train_dataset, {} images in test_dataset'.format(len(train_dataset), len(test_dataset)))
             

    飞桨除了内置了 CV 领域常见的数据集,还在 paddle.text 下内置了自然语言处理(Natural Language Processing,NLP)领域常见的数据集,并提供了自定义数据集与加载功能的 paddle.io.Datasetpaddle.io.DataLoader API,详细使用方法可参考『数据集定义与加载』 章节。

    另外在 paddle.vision.transforms 下提供了一些常用的图像变换操作,如对图像的翻转、裁剪、调整亮度等处理,可实现数据增强,以增加训练样本的多样性,提升模型的泛化能力。本任务在初始化 MNIST 数据集时通过 transform 字段传入了 Normalize 变换对图像进行归一化,对图像进行归一化可以加快模型训练的收敛速度。该功能的具体使用方法可参考『数据预处理』 章节。

    更多参考:

  • 数据集定义与加载

  • 数据预处理

  • 3.2 模型组网

    飞桨的模型组网有多种方式,既可以直接使用飞桨内置的模型,也可以自定义组网。

    『手写数字识别任务』比较简单,普通的神经网络就能达到很高的精度,在本任务中使用了飞桨内置的 LeNet 作为模型。飞桨在 paddle.vision.models 下内置了 CV 领域的一些经典模型,LeNet 就是其中之一,调用很方便,只需一行代码即可完成 LeNet 的网络构建和初始化。num_classes 字段中定义分类的类别数,因为需要对 0 ~ 9 的十类数字进行分类,所以设置为 10。

    另外通过 paddle.summary 可方便地打印网络的基础结构和参数信息。

    # 模型组网并初始化网络
    lenet = paddle.vision.models.LeNet(num_classes=10)
    # 可视化模型组网结构和参数
    paddle.summary(lenet,(1, 1, 28, 28))
               
    ---------------------------------------------------------------------------
     Layer (type)       Input Shape          Output Shape         Param #    
    ===========================================================================
       Conv2D-1       [[1, 1, 28, 28]]      [1, 6, 28, 28]          60       
        ReLU-1        [[1, 6, 28, 28]]      [1, 6, 28, 28]           0       
      MaxPool2D-1     [[1, 6, 28, 28]]      [1, 6, 14, 14]           0       
       Conv2D-2       [[1, 6, 14, 14]]     [1, 16, 10, 10]         2,416     
        ReLU-2       [[1, 16, 10, 10]]     [1, 16, 10, 10]           0       
      MaxPool2D-2    [[1, 16, 10, 10]]      [1, 16, 5, 5]            0       
       Linear-1          [[1, 400]]            [1, 120]           48,120     
       Linear-2          [[1, 120]]            [1, 84]            10,164     
       Linear-3          [[1, 84]]             [1, 10]              850      
    ===========================================================================
    Total params: 61,610
    Trainable params: 61,610
    Non-trainable params: 0
    ---------------------------------------------------------------------------
    Input size (MB): 0.00
    Forward/backward pass size (MB): 0.11
    Params size (MB): 0.24
    Estimated Total Size (MB): 0.35
    ---------------------------------------------------------------------------
             

    通过飞桨的 paddle.nn.Sequentialpaddle.nn.Layer API 可以更灵活方便的组建自定义的神经网络,详细使用方法可参考『模型组网』章节。

    更多参考:

    3.3 模型训练与评估

    3.3.1 模型训练

    模型训练需完成如下步骤:

  • 使用 paddle.Model 封装模型。 将网络结构组合成可快速使用 飞桨高层 API 进行训练、评估、推理的实例,方便后续操作。

  • 使用 paddle.Model.prepare 完成训练的配置准备工作。 包括损失函数、优化器和评价指标等。飞桨在 paddle.optimizer 下提供了优化器算法相关 API,在 paddle.nn Loss层 提供了损失函数相关 API,在 paddle.metric 下提供了评价指标相关 API。

  • 使用 paddle.Model.fit 配置循环参数并启动训练。 配置参数包括指定训练的数据源 train_dataset、训练的批大小 batch_size、训练轮数 epochs 等,执行后将自动完成模型的训练循环。

  • 因为是分类任务,这里损失函数使用常见的 CrossEntropyLoss (交叉熵损失函数),优化器使用 Adam,评价指标使用 Accuracy 来计算模型在训练集上的精度。

    # 封装模型,便于进行后续的训练、评估和推理
    model = paddle.Model(lenet)
    # 模型训练的配置准备,准备损失函数,优化器和评价指标
    model.prepare(paddle.optimizer.Adam(parameters=model.parameters()), 
                  paddle.nn.CrossEntropyLoss(),
                  paddle.metric.Accuracy())
    # 开始训练
    model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)
                
    The loss value printed in the log is the current step, and the metric is the average value of previous steps.
    Epoch 1/5
    step 938/938 [==============================] - loss: 0.0011 - acc: 0.9865 - 14ms/step          
    Epoch 2/5
    step 938/938 [==============================] - loss: 0.0045 - acc: 0.9885 - 14ms/step          
    Epoch 3/5
    step 938/938 [==============================] - loss: 0.0519 - acc: 0.9896 - 14ms/step          
    Epoch 4/5
    step 938/938 [==============================] - loss: 4.1989e-05 - acc: 0.9912 - 14ms/step      
    Epoch 5/5
    step 938/938 [==============================] - loss: 0.0671 - acc: 0.9918 - 15ms/step            
              

    从训练过程的打印日志中,可观察到损失函数值 loss 逐渐变小,精度 acc 逐渐上升的趋势,反映出不错的训练效果。

    3.3.2 模型评估

    模型训练完成之后,调用 paddle.Model.evaluate ,使用预先定义的测试数据集,来评估训练好的模型效果,评估完成后将输出模型在测试集上的损失函数值 loss 和精度 acc。

    # 进行模型评估
    model.evaluate(test_dataset, batch_size=64, verbose=1)
                
    Eval begin...
    step 157/157 [==============================] - loss: 5.7177e-04 - acc: 0.9859 - 6ms/step         
    Eval samples: 10000
              

    3.4.1 模型保存

    模型训练完成后,通常需要将训练好的模型参数和优化器等信息,持久化保存到参数文件中,便于后续执行推理验证。

    在飞桨中可通过调用 paddle.Model.save 保存模型。代码示例如下,其中 output 为模型保存的文件夹名称,minst 为保存的模型文件名称。

    # 保存模型,文件夹会自动创建
    model.save('./output/mnist')
              

    以上代码执行后会在output目录下保存两个文件,mnist.pdopt为优化器的参数,mnist.pdparams为模型的参数。

    output
    ├── mnist.pdopt     # 优化器的参数
    └── mnist.pdparams  # 模型的参数
              

    3.4.2 模型加载并执行推理

    执行模型推理时,可调用 paddle.Model.load 加载模型,然后即可通过 paddle.Model.predict_batch 执行推理操作。

    如下示例中,针对前面创建的 model 网络加载保存的参数文件 output/mnist,并选择测试集中的一张图片 test_dataset[0] 作为输入,执行推理并打印结果,可以看到推理的结果与可视化图片一致。

    # 加载模型
    model.load('output/mnist')
    # 从测试集中取出一张图片
    img, label = test_dataset[0]
    # 将图片shape从1*28*28变为1*1*28*28,增加一个batch维度,以匹配模型输入格式要求
    img_batch = np.expand_dims(img.astype('float32'), axis=0)
    # 执行推理并打印结果,此处predict_batch返回的是一个list,取出其中数据获得预测结果
    out = model.predict_batch(img_batch)[0]
    pred_label = out.argmax()
    print('true label: {}, pred label: {}'.format(label[0], pred_label))
    # 可视化图片
    from matplotlib import pyplot as plt
    plt.imshow(img[0])