Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

十行代码就能搞定深度学习?飞桨框架高层API,一起轻松玩转AI

向往深度学习技术,可是深度学习框架太难学怎么办?百度倾心打造飞桨框架高层 API,零基础也能轻松上手深度学习,一起来看看吧?另:文末有福利,一定要看完呦~

高层 API,What 

深度学习作为人工智能时代的核心技术,近年来无论学术、还是工业领域,均发挥着愈加重要的作用。然而,深度学习理论太难学,开发过程太复杂,又将许多人拒之于深度学习的门外。

为了简化深度学习的学习过程、降低深度学习的开发难度,百度飞桨框架历经近一年的打磨,不断地优化深度学习 API,并针对开发者的使用场景进行封装,在飞桨框架的最新版本中,推出了高低融合、科学统一的飞桨全新 API 体系。

飞桨框架将 API 分为两种,基础 API 和高层 API。用制作披萨举例,一般有两种方法:一种是我们准备好面粉、牛奶、火腿等食材,精心加工后,就能制作出美味的披萨;而第二种则是我们买商家预烤制的披萨饼,以及调好的馅料,直接加热就可以吃到披萨了。


那么这两种方法有什么区别呢?采用方法一,自己准备食材,可以随心所欲的搭配料理,制作酱料,从而满足我们的不同口味,但是,这更适合「老司机」,如果是新人朋友,很有可能翻车;而方法二,用商家预烤制的披萨饼与馅料,直接加热就可以非常快速的完成披萨的制作,而且味道会有保障;但是,相比于方法一,我们会少一些口味的选择。

用框架来类比,基础 API 对应方法一,高层 API 对应方法二。使用基础 API,我们可以随心所欲的搭建自己的深度学习模型,不会受到任何限制;而使用方法二,我们可以很快的实现模型,但是可能会少一些自主性。

但是,与制作披萨不同的是,飞桨框架可以做到真正的「鱼与熊掌」可以兼得。因为高层 API 本身不是一个独立的体系,它完全可以和基础 API 互相配合使用,做到高低融合,使用起来会更加便捷。使我们在开发过程中,既可以享受到基础 API 的强大,又可以兼顾高层 API 的快捷。

高层 API,All

飞桨框架高层 API 的全景图如下:


从图中可以看出,飞桨框架高层 API 由五个模块组成,分别是数据加载、模型组建、模型训练、模型可视化和高阶用法。针对不同的使用场景,飞桨框架提供了不同高层 API,从而降低开发难度,让每个人都能轻松上手深度学习。

我们先通过一个深度学习中经典的手写数字分类任务,来简单了解飞桨高层 API。然后再详细的介绍每个模块中所包含的 API。

import paddle
from paddle.vision.transforms import Compose, Normalize
from paddle.vision.datasets import MNIST
import paddle.nn as nn 

# 数据预处理,这里用到了归一化
transform = Compose([Normalize(mean=[127.5],
                               std=[127.5],
                               data_format='CHW')])

# 数据加载,在训练集上应用数据预处理的操作
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)

# 模型组网
mnist = nn.Sequential(
        nn.Flatten(),
        nn.Linear(784, 512),
        nn.ReLU(),    
        nn.Dropout(0.2),    
        nn.Linear(512, 10))

# 模型封装,用 Model 类封装
model = paddle.Model(mnist)

# 模型配置:为模型训练做准备,设置优化器,损失函数和精度计算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
              loss=nn.CrossEntropyLoss(),              
              metrics=paddle.metric.Accuracy())

# 模型训练,
model.fit(train_dataset,
          epochs=10,          
          batch_size=64,          
          verbose=1)

# 模型评估,
model.evaluate(test_dataset, verbose=1)

# 模型保存,
model.save('model_path')

从示例可以看出,在数据预处理、数据加载、模型组网、模型训练、模型评估、模型保存等场景,高层 API 均可以通过 1~3 行代码实现。相比传统方法动辄几十行的代码量,高层 API 只需要十来行代码,就能轻松完成一个 MNIST 分类器的实现。以极少的代码就能达到与基础 API 同样的效果,大幅降低了深度学习的学习门槛。

如果是初次学习深度学习框架,使用飞桨高层 API,可以「凡尔赛」说出「好烦哦,飞桨高层 API 怎么这么快就完成开发了,我还想多写几行代码呢!」

高层 API,How

接下来以 CV 任务为例,简单介绍飞桨高层 API 在不同场景下的使用方法。

本示例的完整代码可以在 AI Studio 上获取,无需准备任何软硬件环境即可直接在线运行代码,相当方便哦:https://aistudio.baidu.com/aistudio/projectdetail/1243085

一、数据预处理与数据加载

对于数据加载,在一些典型的任务中,我们完全可以使用飞桨框架内置的数据集,完成数据的加载。飞桨框架将常用的数据集作为领域 API,集成在 paddle.vision.datasets 目录中,包含了 CV 领域中常见的 MNIST、Cifar、Flowers 等数据集。

而在数据预处理场景中,飞桨框架提供了 20 多种常见的图像预处理 API,方便我们快速实现数据增强,如实现图像的色调、对比度、饱和度、大小等各种数字图像处理的方法。图像预处理 API 集成在 paddle.vision.transforms 目录中,使用起来非常方便。只需要先创建一个数据预处理的 transform,在其中存入需要进行的数据预处理方法,然后在数据加载的过程中,将 transform 作为参数传入即可。

此外,如果我们需要加载自己的数据集,使用飞桨框架标准数据定义与数据加载 API paddle.io.Dataset 与 paddle.io.DataLoader,就可以「一键」完成数据集的定义与数据的加载。这里通过一个案例来展示如何利用 Dataset 定义数据集,示例如下:

from paddle.io import Dataset

class MyDataset(Dataset):
    """
    步骤一:继承 paddle.io.Dataset 类
    """    
    def __init__(self):        
    """
    步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
    """
    super(MyDataset, self).__init__()

        self.data = [
             ['traindata1', 'label1'],            
             ['traindata2', 'label2'],            
             ['traindata3', 'label3'],            
             ['traindata4', 'label4'],       
         ]

    def __getitem__(self, index):
    """
    步骤三:实现__getitem__方法,定义指定 index 时如何获取数据,并返回单条数据(训练数据,对应的标签)
    """        
    data = self.data[index][0]        
    label = self.data[index][1]

     return data, label

    def __len__(self):        
    """
    步骤四:实现__len__方法,返回数据集总数目
    """        
    return len(self.data)

# 测试定义的数据集
train_dataset = MyDataset()

print('=============train dataset=============')
for data, label in train_dataset:
    print(data, label)

只需要按照上述规范的四个步骤,我们就实现了一个自己的数据集。然后,将 train_dataset 作为参数,传入到 DataLoader 中,即可获得一个数据加载器,完成训练数据的加载。

【Tips:对于数据集的定义,飞桨框架同时支持 map-style 和 iterable-style 两种类型的数据集定义,只需要分别继承 paddle.io.Dataset 和 paddle.io.IterableDataset 即可。】

二、网络构建

在网络构建模块,飞桨高层 API 与基础 API 保持一致,统一使用 paddle.nn 下的 API 进行组网。paddle.nn 目录下包含了所有与模型组网相关的 API,如卷积相关的 Conv1D、Conv2D、Conv3D,循环神经网络相关的 RNN、LSTM、GRU 等。

对于组网方式,飞桨框架支持 Sequential 或 SubClass 进行模型组建。Sequential 可以帮助我们快速的组建线性的网络结构,而 SubClass 支持更丰富灵活的网络结构。我们可以根据实际的使用场景,来选择最合适的组网方式。如针对顺序的线性网络结构可以直接使用 Sequential ,而如果是一些比较复杂的网络结构,我们使用 SubClass 的方式来进行模型的组建,在 __init__ 构造函数中进行 Layer 的声明,在 forward 中使用声明的 Layer 变量进行前向计算。

下面就来分别看一下 Sequential 与 SubClass 的实例。

1、Sequential 

对于线性的网络模型,我们只需要按网络模型的结构顺序,一层一层的加到 Sequential  后面即可,具体实现如下:

# Sequential 形式组网
mnist = nn.Sequential(
    nn.Flatten(),    
    nn.Linear(784, 512),    
    nn.ReLU(),    
    nn.Dropout(0.2),    
    nn.Linear(512, 10)
)

2、SubClass

使用 SubClass 进行组网的实现如下:

# SubClass 方式组网
class Mnist(nn.Layer):
    def __init__(self):    
        super(Mnist, self).__init__()

        self.flatten = nn.Flatten()
        self.linear_1 = nn.Linear(784, 512)        
        self.linear_2 = nn.Linear(512, 10)        
        self.relu = nn.ReLU()        
        self.dropout = nn.Dropout(0.2)

    def forward(self, inputs):
        y = self.flatten(inputs)        
        y = self.linear_1(y)        
        y = self.relu(y)        
        y = self.dropout(y)        
        y = self.linear_2(y)

        return y

上述的 SubClass 组网的结果与 Sequential 组网的结果完全一致,可以明显看出,使用 SubClass 组网会比使用 Sequential 更复杂一些。不过,这带来的是网络模型结构的灵活性。我们可以设计不同的网络模型结构来应对不同的场景。

3、飞桨框架内置模型

除了自定义模型结构外,飞桨框架还「贴心」的内置了许多模型,真正的一行代码实现深度学习模型。目前,飞桨框架内置的模型都是 CV 领域领域的模型,都在 paddle.vision.models 目录下,包含了常见的 vgg 系列、resnet 系列等模型。使用方式如下:

import paddle
from paddle.vision.models import resnet18

# 方式一: 一行代码直接使用 
resnetresnet = resnet18()

# 方式二: 作为主干网络进行二次开发
class FaceNet(paddle.nn.Layer):
    def __init__(self, num_keypoints=15, pretrained=False):
        super(FaceNet, self).__init__()

        self.backbone = resnet18(pretrained)        
        self.outLayer1 = paddle.nn.Linear(1000, 512)        
        self.outLayer2 = paddle.nn.Linear(512, num_keypoints*2)

    def forward(self, inputs):        
         out = self.backbone(inputs)        
         out = self.outLayer1(out)        
         out = self.outLayer2(out)        
         return out

三、模型可视化

在我们完成模型的构建后,有时还需要可视化模型的网络结构与参数,只要我们用 Model 进行模型的封装后,然后调用 model.summary 即可实现网络模型的可视化,具体如下:

mnist = nn.Sequential(
    nn.Flatten(),    
    nn.Linear(784, 512),    
    nn.ReLU(),    
    nn.Dropout(0.2),    
    nn.Linear(512, 10))

# 模型封装,用 Model 类封装
model = paddle.Model(mnist)
model.summary()

其输出如下:

---------------------------------------------------------------------------
 Layer (type)       Input Shape          Output Shape         Param #    
 ===========================================================================
   Flatten-795    [[32, 1, 28, 28]]        [32, 784]              0         
    Linear-5         [[32, 784]]           [32, 512]           401,920       
     ReLU-3          [[32, 512]]           [32, 512]              0        
    Dropout-3        [[32, 512]]           [32, 512]              0          
    Linear-6         [[32, 512]]            [32, 10]            5,130     
    ===========================================================================
    Total params: 407,050
    Trainable params: 407,050
    Non-trainable params: 0
---------------------------------------------------------------------------
Input size (MB): 0.10
Forward/backward pass size (MB): 0.57
Params size (MB): 1.55
Estimated Total Size (MB): 2.22
---------------------------------------------------------------------------
{'total_params': 407050, 'trainable_params': 407050}

Model.summary 不仅会给出每一层网络的形状,还会给出每层网络的参数量与模型的总参数量,非常方便直观的就可以看到模型的全部信息。

四、模型训练

1、使用高层 API 在全部数据集上进行训练

过去常常困扰深度学习开发者的一个问题是,模型训练的代码过于复杂,常常要写好多步骤,才能使程序运行起来,冗长的代码使许多开发者望而却步。

现在,飞桨高层 API 将训练、评估与预测 API 都进行了封装,直接使用 Model.prepare()、Model.fit()、Model.evaluate()、Model.predict()就可以完成模型的训练、评估与预测。

对比传统框架动辄一大块的训练代码。使用飞桨高层 API,可以在 3-5 行内,完成模型的训练,极大的简化了开发的代码量,对初学者开发者非常友好。具体代码如下:

# 将网络结构用 Model 类封装成为模型
model = paddle.Model(mnist)

# 为模型训练做准备,设置优化器,损失函数和精度计算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
              loss=paddle.nn.CrossEntropyLoss(),              
              metrics=paddle.metric.Accuracy())

# 启动模型训练,指定训练数据集,设置训练轮次,设置每次数据集计算的批次大小,设置日志格式
model.fit(train_dataset, 
         epochs=10,          
         batch_size=64,          
         verbose=1)

# 启动模型评估,指定数据集,设置日志格式
model.evaluate(test_dataset, verbose=1)

# 启动模型测试,指定测试集 
Model.predict(test_dataset)

2、使用高层 API 在一个批次的数据集上训练、验证与测试

有时我们需要对数据按 batch 进行取样,然后完成模型的训练与验证,这时,可以使用 train_batch、eval_batch、predict_batch 完成一个批次上的训练、验证与测试,具体如下:

# 模型封装,用 Model 类封装
model = paddle.Model(mnist)

# 模型配置:为模型训练做准备,设置优化器,损失函数和精度计算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
              loss=nn.CrossEntropyLoss(),              
              metrics=paddle.metric.Accuracy())

# 构建训练集数据加载器
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)

# 使用 train_batch 完成训练
for batch_id, data in enumerate(train_loader()):
    model.train_batch([data[0]],[data[1]])

# 构建测试集数据加载器
test_loader = paddle.io.DataLoader(test_dataset, places=paddle.CPUPlace(), batch_size=64, shuffle=True)

# 使用 eval_batch 完成验证
for batch_id, data in enumerate(test_loader()):
    model.eval_batch([data[0]],[data[1]])

# 使用 predict_batch 完成预测
for batch_id, data in enumerate(test_loader()):
    model.predict_batch([data[0]])

五、高阶用法

除此之外,飞桨高层 API 还支持一些高阶的玩法,如自定义 Loss、自定义 Metric、自定义 Callback 等等。

自定义 Loss 是指有时我们会遇到特定任务的 Loss 计算方式在框架既有的 Loss 接口中不存在,或算法不符合自己的需求,那么期望能够自己来进行 Loss 的自定义。

自定义 Metric 和自定义 Loss 的场景一样,如果遇到一些想要做个性化实现的操作时,我们也可以来通过框架完成自定义的评估计算方法。

自定义 Callback 则是可以帮助我们收集训练时的一些参数以及数据,由于 Model.fit()封装了训练过程,如果我们需要保存训练时的 loss、metric 等信息,则需要通过 callback 参数收集这部分信息。

更多更丰富的玩法,可以扫描关注文末的二维码获取~

高层 API,Next

上文以 CV 任务为例,介绍了飞桨框架高层 API 的使用指南。后续,飞桨框架还计划推出 NLP 领域专用的数据预处理模块,如对数据进行 padding、获取数据集词表等;在组网方面,也会实现 NLP 领域中组网专用的 API,如组网相关的 sequence_mask,评估指标相关的 BLEU 等;最后,针对 NLP 领域中的神器 transformer,我们也会对其进行特定的优化;待这些功能上线后,我们会第一时间告诉大家,敬请期待吧~

高层 API,Where

看完前面飞桨高层 API 的使用介绍,是不是有种跃跃欲试的冲动呀?

体验方式一:在线体验

无需准备任何软硬件环境,直接访问以下地址,即可在线跑代码看效果:https://aistudio.baidu.com/aistudio/projectdetail/1243085

体验方式二:本地体验

如果你还想在自己本地电脑上体验,那需要确保本地电脑上已成功安装飞桨开源框架 2.0。

下面介绍飞桨开源框架 2.0 的安装方法,可以参考下面的命令,直接使用 pip 安装。安装后,就可以开始使用高层 API 啦。

# CPU 版
$ pip3 install paddlepaddle==2.0.0rc0 -i https://mirror.baidu.com/pypi/simple
# GPU 版
$ pip3 install paddlepaddle_gpu==2.0.0rc0 -i https://mirror.baidu.com/pypi/simple

高层 API,You

福利时间:百度飞桨开源框架近期针对高层 API 会推出一系列教程——《跟着雨哥学 AI》,该课程由多位资深飞桨工程师精心打造,诚意满满。对于刚上手深度学习的人来说,这就是最佳的学习材料。不管是自学,还是用于开发,都是极有帮助的。教程链接如下:https://aistudio.baidu.com/aistudio/personalcenter/thirdview/564527
工程百度百度飞桨深度学习框架
相关数据
Dropout技术

神经网络训练中防止过拟合的一种技术

损失函数技术

在数学优化,统计学,计量经济学,决策理论,机器学习和计算神经科学等领域,损失函数或成本函数是将一或多个变量的一个事件或值映射为可以直观地表示某种与之相关“成本”的实数的函数。

暂无评论
暂无评论~