前言:飞桨框架2.0版本中推出了高层API,对飞桨API进行封装和升级,提高了飞桨的易学性。下面我来带大家了解一下飞桨的高层API。
什么是高层API
飞桨高层API是飞桨框架推出的快速实现深度学习模型的API,旨在帮助开发者更快更好的完成深度学习模型的学习和开发。
用框架来类比,飞桨框架基础API对应方法一,飞桨框架高层API对应方法二。使用基础API,我们可以随心所欲的搭建自己的深度学习模型,不会受到任何限制;而使用方法二,我们可以很快的实现模型,达到自己想要的效果,缺点是少了一些自主性。
这次升级并不是简单的优化,而是将所有的API变得更加体系化。高层API可以和基础API搭配使用,更加便捷。
目前的飞桨高层API由五个模块组成,分别是数据加载、模型组建、模型训练、模型可视化和高阶用法。我们将详细介绍每个模块所包含的API。
高层API详解
1、数据预处理与数据加载
对于数据预处理与数据加载,飞桨框架提供了很多API,如下:
1、飞桨框架内置数据集:paddle.vision.datasets置包含了许多CV领域相关的数据集,直接调用API即可使用;
2、飞桨框架数据预处理:paddle.vision.transforms飞桨框架对于图像预处理的方式,可以快速完成常见的图像预处理的方式,如调整色调、对比度,图像大小等;
3、 飞桨框架数据加载:paddle.io.Dataset与paddle.io.DataLoader飞桨框架标准数据加载方式,可以”一键”完成数据的批加载与异步加载;
1.1 飞桨框架内置数据集
飞桨将常见的数据集作为领域API对用户开放,我们可以输入代码看一看有哪些数据集:
print("飞桨框架CV领域内置数据集:" + str(paddle.vision.datasets.__all__))
飞桨提供的数据集包括计算机视觉中常见的数据集,完全满足我们在数据集方面的需求。
下面我给出一个数据集的加载实例方便理解:
train_dataset = paddle.vision.datasets.MNIST(mode='train')
test_dataset = paddle.vision.datasets.MNIST(mode='test')
#取其中一条数据观察
import numpy as np
import matplotlib.pyplot as plt
train_data0,train_label_0 = train_dataset[0][0],train_dataset[0][1]
train_data0 = np.array(train_data0).reshape([28,28])
plt.figure(figsize=(2,2))
plt.imshow(train_data0,cmap = plt.cm.binary)
print('train_data0 label is: ' + str(train_label_0))
1.2 飞桨框架预处理方法
飞桨框架提供了20多种数据集预处理的接口,方便开发者快速实现数据增强,目前都集中在 paddle.vision.transforms 目录下,具体包含的API可以借助这一行代码来查看一下:
print('视觉数据预处理方法:' + str(paddle.vision.transforms.__all__))
飞桨框架的预处理方法实现了图像的色调、对比度、饱和度、大小等各种数字图像处理的方法。而这些数据预处理方法非常方便,只需要先创建一个数据预处理的transform,在其中存入需要进行的数据预处理方法,然后在数据加载的过程中,将transform作为参数传入即可,具体如下:
#首先创建transform
from paddle.vision.transforms import Compose,ColorJitter
from paddle.vision.datasets import Cifar10
transfrom = Compose([ColorJitter()])# transform用于存储数据预处理的接口组合 ColorJitter()实现随机调整亮度、对比度和饱和度
#数据加载,在训练集上应用数据预处理的操作
train_dataset = Cifar10(mode='train',transform=transform)
test_dataset = Cifar10(mode='test')
随机处理和未处理的对比图可以借助如下代码看看:
index = 326
def show_img(img_array):
img_array = img_array.astype('float32')/255
plt.figure(figsize=(2,2))
plt.imshow(img_array,cmap=plt.cm.binary)
dataset_without_transform = Cifar10(mode='train')
show_img(np.array(dataset_without_transform[index][0]))
dataset_with_transform = Cifar10(mode='train',transform=ColorJitter(0.4,0.4,0.4,0.4))
show_img(np.array(dataset_with_transform[index][0]))
1.3 自定义数据集加载
有时候我们需要自己使用已有的相关数据定义数据集,这里我们通过一个案例来了解如何进行数据集的定义,飞桨为用户提供了paddle.io.Dataset基类,让用户通过类的集成来快速实现数据集定义。
from paddle.io import Dataset
class MyDataset(Dataset):
"""
步骤一:继承paddle.io.Dataset类
"""
def __init__(self, mode='train'):
"""
步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
"""
super(MyDataset, self).__init__()
# 下面的traindata1,label1之类的只是一个示例,不能直接用于DataLoader加载,大家可以改成自己的实际数据
if mode == 'train':
self.data = [
['traindata1', 'label1'],
['traindata2', 'label2'],
['traindata3', 'label3'],
['traindata4', 'label4'],
]
else:
self.data = [
['testdata1', 'label1'],
['testdata2', 'label2'],
['testdata3', 'label3'],
['testdata4', '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(mode='train')
val_dataset = MyDataset(mode='test')
print('=============train dataset=============')
for data, label in train_dataset:
print(data, label)
print('=============evaluation dataset=============')
for data, label in val_dataset:
print(data, label)
之后我们将train_dataset 与 val_dataset 作为参数,传入到DataLoader中,即可获得一个数据加载器,完成训练数据的加载。
2. 网络构建
飞桨高层API与基础API保持完全的一致,都使用paddle.nn下的API进行组网。这也是尽可能的减少需要暴露的概念,从而提升框架的易学性。飞桨框架 paddle.nn 目录下包含了所有与模型组网相关的API,如卷积相关的 Conv1D、Conv2D、Conv3D,循环神经网络相关的 RNN、LSTM、GRU 等。
对于组网方式,飞桨框架统一支持 Sequential 或 SubClass 的方式进行模型的组建。我们根据实际的使用场景,来选择最合适的组网方式。如针对顺序的线性网络结构我们可以直接使用 Sequential ,相比于 SubClass ,Sequential 可以快速的完成组网。 如果是一些比较复杂的网络结构,我们可以使用 SubClass 定义的方式来进行模型代码编写,在 init 构造函数中进行
Layer 的声明,在 forward 中使用声明的 Layer 变量进行前向计算。通过这种方式,我们可以组建更灵活的网络结构。
2.1 Sequential 组网方式
#Sequential组网
mnist = nn.Sequential(
nn.Flatten(),
nn.Linear(784,512),
nn.ReLU(),
nn.Dropout(0,2),
nn.Linear(512,10),
)
对于线性的网络模型,我们可以按网络模型的结构顺序,一层一层加到Sequential后面。
2.2 SubClass 组网方式
#SubClass组网
class Mnist(paddle.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 更复杂一些。不过,这带来的是网络模型结构的灵活性。
2.3 飞桨内置网络模型
除了自定义模型结构外,飞桨框架还”贴心”的内置了许多模型,真正的一行代码实现深度学习模型。在paddle.vision.models目录下,具体包含如下的模型:
print("视觉相关模型: " + str(paddle.vision.models.__all__))
#['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'VGG', 'vgg11', 'vgg13', 'vgg16', 'vgg19', 'MobileNetV1', 'mobilenet_v1', 'MobileNetV2', 'mobilenet_v2', 'LeNet']
使用起来也十分简单,只需要一行代码就能搭建好模型,如下:
#Lenet模型构建
lenet = paddle.vision.models.LeNet()
写完这行代码就完成了Lenet模型的构建,然后就可以开始下一步的模型训练了!
3. 模型训练
3.1 使用高层API在全部数据集上进行训练
过去模型训练的代码过于复杂,常常要写好多步骤,才能正确的使程序运行起来,冗长的代码使许多开发者望而却步。
现在,飞桨高层API将训练、评估与预测API都进行了封装,Model.prepare()、Model.fit()、Model.evaluate()、Model.predict()完成模型的训练、评估与预测!
对初学者用户非常友好!!!
#定义 数据集与模型
import paddle
import paddle.nn as nn
import paddle.vision.transforms as T
from paddle.vision.datasets import MNIST
#数据预处理,(随机调整亮度,对比度,饱和度)
transform = T.Normalize(mean=[127.5],std=[127.5])
#数据加载,在训练集中应用数据预处理
train_dataset = MNIST(mode='train', transform=transform)
test_dataset = MNIST(mode='test', transform=transform)
mnist = nn.Sequential(
nn.Flatten(),
nn.Linear(784, 512),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(512, 10)
)
#使用高层API进行训练
#将网络结构用Model类进行封装
model = paddle.Model(mnist)
#为模型训练做准备,设置优化器、损失函数、精度计算方式
model.prepare(optimizer = paddle.optimizer.Adam(parameters=model.parameters()),
loss = paddle.nn.CrossEntropyLoss(),
metrics = paddle.metric.Accuracy())
#启动模型训练,指定训练数据集dataset,设置训练批次epoch,设置每次数据集计算的批次大小batch_size,设置日志verbose
model.fit(train_dataset,
epochs=5,
batch_size=64,
verbose=1)
#启动模型评估。指定数据集和日志格式
evaluate_result = model.evaluate(test_dataset, verbose=1)
# 启动模型测试,指定测试集
predict_result = model.predict(test_dataset)
3.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, 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]])
3.3 对高层API(model.fit)进行拆解
由于飞桨高层API是对基础API的封装,所以我们也可以对其进行拆解,将高层API用基础API实现。拆解的步骤如下面的代码,这里我们只对fit,也就是训练过程进行拆解。
import paddle.nn.functional as F
# 加载数据
train_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=64, shuffle=True)
# 加载训练集 batch_size 设为 64
def train(model):
model.train()
epochs = 5
optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()) # 用Adam作为优化函数
for epoch in range(epochs):
for batch_id, data in enumerate(train_loader()):
x_data = data[0]
y_data = data[1]
predicts = model(x_data)
loss = F.cross_entropy(predicts, y_data) # 计算损失
acc = paddle.metric.accuracy(predicts, y_data) # 计算精度
loss.backward() # 反向传播
if batch_id % 500 == 0:
print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id, loss.numpy(), acc.numpy()))
optim.step() # 更新参数
optim.clear_grad() # 清除梯度
model = Mnist()
train(model)
4. 模型可视化
在我们完成模型的构建后,有时还需要可视化模型的网络结构与训练过程,来直观的了解深度学习模型与训练过程,方便我们更好地优化模型。飞桨框架高层API提供了一系列相关的API,来帮助我们可视化模型与训练过程,就让我们来看一下吧。
4.1 模型结构可视化
对于我们组网的模型,只要我们用Model进行模型的封装后,只需要调用 model.summary 即可实现网络模型的可视化。
import paddle
mnist = paddle.nn.Sequential(
paddle.nn.Flatten(),
paddle.nn.Linear(784, 512),
paddle.nn.ReLU(),
paddle.nn.Dropout(0.2),
paddle.nn.Linear(512, 10)
)
# 模型封装,用Model类封装
model = paddle.Model(mnist)
model.summary((1, 28, 28))
5.2 使用VisualDL完成训练过程可视化(重要)
VisualDL是飞桨可视化分析工具,以丰富的图表呈现训练参数变化趋势、模型结构、数据样本、直方图以及PR曲线等。可帮助用户更清晰直观地理解深度学习模型训练过程及模型结构,进而实现高效的模型优化。是飞桨模型可视化的大杀器。仅需一行代码就可以轻松使用VisualDL!
# 调用飞桨框架的VisualDL模块,保存信息到目录中。
callback = paddle.callbacks.VisualDL(log_dir='visualdl_log_dir')
# 模型配置:为模型训练做准备,设置优化器,损失函数和精度计算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
loss=nn.CrossEntropyLoss(),
metrics=paddle.metric.Accuracy())
model.fit(train_dataset,
epochs=5,
batch_size=32,
callbacks=callback,#这里添加一行代码
verbose=1)
在终端中输入命令,启动VisualDL控制面板
visualdl service upload --logdir ./visualdl_log
复制链接到浏览器中查看可视化结果
总结
上文以CV任务为例,介绍了飞桨框架高层API的使用指南。后续,飞桨框架还计划推出NLP领域专用的数据预处理模块,如对数据进行padding、获取数据集词表等;在组网方面,也会实现NLP领域中组网专用的API,如组网相关的sequence_mask,评估指标相关的BLEU等;最后,针对NLP领域中的神器transformer,我们也会对其进行特定的优化;