那么這兩種方法有什么區(qū)別呢?采用方法一,自己準(zhǔn)備食材,可以隨心所欲的搭配料理,制作醬料,從而滿足我們的不同口味,但是,這更適合「老司機(jī)」,如果是新人朋友,很有可能翻車;而方法二,用商家預(yù)烤制的披薩餅與餡料,直接加熱就可以非??焖俚耐瓿膳_的制作,而且味道會(huì)有保障;但是,相比于方法一,我們會(huì)少一些口味的選擇。
用框架來類比,基礎(chǔ) API 對(duì)應(yīng)方法一,高層 API 對(duì)應(yīng)方法二。使用基礎(chǔ) API,我們可以隨心所欲的搭建自己的深度學(xué)習(xí)模型,不會(huì)受到任何限制;而使用方法二,我們可以很快的實(shí)現(xiàn)模型,但是可能會(huì)少一些自主性。
但是,與制作披薩不同的是,飛槳框架可以做到真正的「魚與熊掌」可以兼得。因?yàn)楦邔?API 本身不是一個(gè)獨(dú)立的體系,它完全可以和基礎(chǔ) API 互相配合使用,做到高低融合,使用起來會(huì)更加便捷。使我們?cè)陂_發(fā)過程中,既可以享受到基礎(chǔ) API 的強(qiáng)大,又可以兼顧高層 API 的快捷。

高層 API,All

飛槳框架高層 API 的全景圖如下:

從圖中可以看出,飛槳框架高層 API 由五個(gè)模塊組成,分別是數(shù)據(jù)加載、模型組建、模型訓(xùn)練、模型可視化和高階用法。針對(duì)不同的使用場(chǎng)景,飛槳框架提供了不同高層 API,從而降低開發(fā)難度,讓每個(gè)人都能輕松上手深度學(xué)習(xí)。
我們先通過一個(gè)深度學(xué)習(xí)中經(jīng)典的手寫數(shù)字分類任務(wù),來簡(jiǎn)單了解飛槳高層 API。然后再詳細(xì)的介紹每個(gè)模塊中所包含的 API。

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

# 數(shù)據(jù)預(yù)處理,這里用到了歸一化
transform = Compose([Normalize(mean=[127.5],
std=[127.5],
data_format='CHW')])

# 數(shù)據(jù)加載,在訓(xùn)練集上應(yīng)用數(shù)據(jù)預(yù)處理的操作
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)

# 模型組網(wǎng)
mnist = nn.Sequential(
nn.Flatten(),
nn.Linear(784, 512),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(512, 10))

# 模型封裝,用 Model 類封裝
model = paddle.Model(mnist)

# 模型配置:為模型訓(xùn)練做準(zhǔn)備,設(shè)置優(yōu)化器,損失函數(shù)和精度計(jì)算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
loss=nn.CrossEntropyLoss(),
metrics=paddle.metric.Accuracy())

# 模型訓(xùn)練,
model.fit(train_dataset,
epochs=10,
batch_size=64,
verbose=1)

# 模型評(píng)估,
model.evaluate(test_dataset, verbose=1)

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

從示例可以看出,在數(shù)據(jù)預(yù)處理、數(shù)據(jù)加載、模型組網(wǎng)、模型訓(xùn)練、模型評(píng)估、模型保存等場(chǎng)景,高層 API 均可以通過 1~3 行代碼實(shí)現(xiàn)。相比傳統(tǒng)方法動(dòng)輒幾十行的代碼量,高層 API 只需要十來行代碼,就能輕松完成一個(gè) MNIST 分類器的實(shí)現(xiàn)。以極少的代碼就能達(dá)到與基礎(chǔ) API 同樣的效果,大幅降低了深度學(xué)習(xí)的學(xué)習(xí)門檻。
如果是初次學(xué)習(xí)深度學(xué)習(xí)框架,使用飛槳高層 API,可以「凡爾賽」說出「好煩哦,飛槳高層 API 怎么這么快就完成開發(fā)了,我還想多寫幾行代碼呢!」

高層 API,How

接下來以 CV 任務(wù)為例,簡(jiǎn)單介紹飛槳高層 API 在不同場(chǎng)景下的使用方法。
本示例的完整代碼可以在 AI Studio 上獲取,無需準(zhǔn)備任何軟硬件環(huán)境即可直接在線運(yùn)行代碼,相當(dāng)方便哦:https://aistudio.baidu.com/aistudio/projectdetail/1243085

一、數(shù)據(jù)預(yù)處理與數(shù)據(jù)加載

對(duì)于數(shù)據(jù)加載,在一些典型的任務(wù)中,我們完全可以使用飛槳框架內(nèi)置的數(shù)據(jù)集,完成數(shù)據(jù)的加載。飛槳框架將常用的數(shù)據(jù)集作為領(lǐng)域 API,集成在 paddle.vision.datasets 目錄中,包含了 CV 領(lǐng)域中常見的 MNIST、Cifar、Flowers 等數(shù)據(jù)集。
而在數(shù)據(jù)預(yù)處理場(chǎng)景中,飛槳框架提供了 20 多種常見的圖像預(yù)處理 API,方便我們快速實(shí)現(xiàn)數(shù)據(jù)增強(qiáng),如實(shí)現(xiàn)圖像的色調(diào)、對(duì)比度、飽和度、大小等各種數(shù)字圖像處理的方法。圖像預(yù)處理 API 集成在 paddle.vision.transforms 目錄中,使用起來非常方便。只需要先創(chuàng)建一個(gè)數(shù)據(jù)預(yù)處理的 transform,在其中存入需要進(jìn)行的數(shù)據(jù)預(yù)處理方法,然后在數(shù)據(jù)加載的過程中,將 transform 作為參數(shù)傳入即可。
此外,如果我們需要加載自己的數(shù)據(jù)集,使用飛槳框架標(biāo)準(zhǔn)數(shù)據(jù)定義與數(shù)據(jù)加載 API paddle.io.Dataset 與 paddle.io.DataLoader,就可以「一鍵」完成數(shù)據(jù)集的定義與數(shù)據(jù)的加載。這里通過一個(gè)案例來展示如何利用 Dataset 定義數(shù)據(jù)集,示例如下:

from paddle.io import Dataset

class MyDataset(Dataset):
"""
步驟一:繼承 paddle.io.Dataset 類
"""
def __init__(self):
"""
步驟二:實(shí)現(xiàn)構(gòu)造函數(shù),定義數(shù)據(jù)讀取方式,劃分訓(xùn)練和測(cè)試數(shù)據(jù)集
"""
super(MyDataset, self).__init__()

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

def __getitem__(self, index):
"""
步驟三:實(shí)現(xiàn)__getitem__方法,定義指定 index 時(shí)如何獲取數(shù)據(jù),并返回單條數(shù)據(jù)(訓(xùn)練數(shù)據(jù),對(duì)應(yīng)的標(biāo)簽)
"""
data = self.data[index][0]
label = self.data[index][1]

return data, label

def __len__(self):
"""
步驟四:實(shí)現(xiàn)__len__方法,返回?cái)?shù)據(jù)集總數(shù)目
"""
return len(self.data)

# 測(cè)試定義的數(shù)據(jù)集
train_dataset = MyDataset()

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

只需要按照上述規(guī)范的四個(gè)步驟,我們就實(shí)現(xiàn)了一個(gè)自己的數(shù)據(jù)集。然后,將 train_dataset 作為參數(shù),傳入到 DataLoader 中,即可獲得一個(gè)數(shù)據(jù)加載器,完成訓(xùn)練數(shù)據(jù)的加載。
【Tips:對(duì)于數(shù)據(jù)集的定義,飛槳框架同時(shí)支持 map-style 和 iterable-style 兩種類型的數(shù)據(jù)集定義,只需要分別繼承 paddle.io.Dataset 和 paddle.io.IterableDataset 即可?!?/strong>

二、網(wǎng)絡(luò)構(gòu)建

在網(wǎng)絡(luò)構(gòu)建模塊,飛槳高層 API 與基礎(chǔ) API 保持一致,統(tǒng)一使用 paddle.nn 下的 API 進(jìn)行組網(wǎng)。paddle.nn 目錄下包含了所有與模型組網(wǎng)相關(guān)的 API,如卷積相關(guān)的 Conv1D、Conv2D、Conv3D,循環(huán)神經(jīng)網(wǎng)絡(luò)相關(guān)的 RNN、LSTM、GRU 等。
對(duì)于組網(wǎng)方式,飛槳框架支持 Sequential 或 SubClass 進(jìn)行模型組建。Sequential 可以幫助我們快速的組建線性的網(wǎng)絡(luò)結(jié)構(gòu),而 SubClass 支持更豐富靈活的網(wǎng)絡(luò)結(jié)構(gòu)。我們可以根據(jù)實(shí)際的使用場(chǎng)景,來選擇最合適的組網(wǎng)方式。如針對(duì)順序的線性網(wǎng)絡(luò)結(jié)構(gòu)可以直接使用 Sequential ,而如果是一些比較復(fù)雜的網(wǎng)絡(luò)結(jié)構(gòu),我們使用 SubClass 的方式來進(jìn)行模型的組建,在 __init__ 構(gòu)造函數(shù)中進(jìn)行 Layer 的聲明,在 forward 中使用聲明的 Layer 變量進(jìn)行前向計(jì)算。
下面就來分別看一下 Sequential 與 SubClass 的實(shí)例。
1、Sequential?
對(duì)于線性的網(wǎng)絡(luò)模型,我們只需要按網(wǎng)絡(luò)模型的結(jié)構(gòu)順序,一層一層的加到 Sequential ?后面即可,具體實(shí)現(xiàn)如下:

# Sequential 形式組網(wǎng)
mnist = nn.Sequential(
nn.Flatten(),
nn.Linear(784, 512),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(512, 10)
)

2、SubClass
使用 SubClass 進(jìn)行組網(wǎng)的實(shí)現(xiàn)如下:

# SubClass 方式組網(wǎng)
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 組網(wǎng)的結(jié)果與 Sequential 組網(wǎng)的結(jié)果完全一致,可以明顯看出,使用 SubClass 組網(wǎng)會(huì)比使用 Sequential 更復(fù)雜一些。不過,這帶來的是網(wǎng)絡(luò)模型結(jié)構(gòu)的靈活性。我們可以設(shè)計(jì)不同的網(wǎng)絡(luò)模型結(jié)構(gòu)來應(yīng)對(duì)不同的場(chǎng)景。

3、飛槳框架內(nèi)置模型

除了自定義模型結(jié)構(gòu)外,飛槳框架還「貼心」的內(nèi)置了許多模型,真正的一行代碼實(shí)現(xiàn)深度學(xué)習(xí)模型。目前,飛槳框架內(nèi)置的模型都是 CV 領(lǐng)域領(lǐng)域的模型,都在 paddle.vision.models 目錄下,包含了常見的 vgg 系列、resnet 系列等模型。使用方式如下:

import paddle
from paddle.vision.models import resnet18

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

# 方式二: 作為主干網(wǎng)絡(luò)進(jìn)行二次開發(fā)
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

三、模型可視化

在我們完成模型的構(gòu)建后,有時(shí)還需要可視化模型的網(wǎng)絡(luò)結(jié)構(gòu)與參數(shù),只要我們用 Model 進(jìn)行模型的封裝后,然后調(diào)用 model.summary 即可實(shí)現(xiàn)網(wǎng)絡(luò)模型的可視化,具體如下:

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 不僅會(huì)給出每一層網(wǎng)絡(luò)的形狀,還會(huì)給出每層網(wǎng)絡(luò)的參數(shù)量與模型的總參數(shù)量,非常方便直觀的就可以看到模型的全部信息。

四、模型訓(xùn)練

1、使用高層 API 在全部數(shù)據(jù)集上進(jìn)行訓(xùn)練
過去常常困擾深度學(xué)習(xí)開發(fā)者的一個(gè)問題是,模型訓(xùn)練的代碼過于復(fù)雜,常常要寫好多步驟,才能使程序運(yùn)行起來,冗長的代碼使許多開發(fā)者望而卻步。
現(xiàn)在,飛槳高層 API 將訓(xùn)練、評(píng)估與預(yù)測(cè) API 都進(jìn)行了封裝,直接使用 Model.prepare()、Model.fit()、Model.evaluate()、Model.predict()就可以完成模型的訓(xùn)練、評(píng)估與預(yù)測(cè)。
對(duì)比傳統(tǒng)框架動(dòng)輒一大塊的訓(xùn)練代碼。使用飛槳高層 API,可以在 3-5 行內(nèi),完成模型的訓(xùn)練,極大的簡(jiǎn)化了開發(fā)的代碼量,對(duì)初學(xué)者開發(fā)者非常友好。具體代碼如下:

# 將網(wǎng)絡(luò)結(jié)構(gòu)用 Model 類封裝成為模型
model = paddle.Model(mnist)

# 為模型訓(xùn)練做準(zhǔn)備,設(shè)置優(yōu)化器,損失函數(shù)和精度計(jì)算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
loss=paddle.nn.CrossEntropyLoss(),
metrics=paddle.metric.Accuracy())

# 啟動(dòng)模型訓(xùn)練,指定訓(xùn)練數(shù)據(jù)集,設(shè)置訓(xùn)練輪次,設(shè)置每次數(shù)據(jù)集計(jì)算的批次大小,設(shè)置日志格式
model.fit(train_dataset,
epochs=10,
batch_size=64,
verbose=1)

# 啟動(dòng)模型評(píng)估,指定數(shù)據(jù)集,設(shè)置日志格式
model.evaluate(test_dataset, verbose=1)

# 啟動(dòng)模型測(cè)試,指定測(cè)試集
Model.predict(test_dataset)

2、使用高層 API 在一個(gè)批次的數(shù)據(jù)集上訓(xùn)練、驗(yàn)證與測(cè)試
有時(shí)我們需要對(duì)數(shù)據(jù)按 batch 進(jìn)行取樣,然后完成模型的訓(xùn)練與驗(yàn)證,這時(shí),可以使用 train_batch、eval_batch、predict_batch 完成一個(gè)批次上的訓(xùn)練、驗(yàn)證與測(cè)試,具體如下:

# 模型封裝,用 Model 類封裝
model = paddle.Model(mnist)

# 模型配置:為模型訓(xùn)練做準(zhǔn)備,設(shè)置優(yōu)化器,損失函數(shù)和精度計(jì)算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
loss=nn.CrossEntropyLoss(),
metrics=paddle.metric.Accuracy())

# 構(gòu)建訓(xùn)練集數(shù)據(jù)加載器
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)

# 使用 train_batch 完成訓(xùn)練
for batch_id, data in enumerate(train_loader()):
model.train_batch([data[0]],[data[1]])

# 構(gòu)建測(cè)試集數(shù)據(jù)加載器
test_loader = paddle.io.DataLoader(test_dataset, places=paddle.CPUPlace(), batch_size=64, shuffle=True)

# 使用 eval_batch 完成驗(yàn)證
for batch_id, data in enumerate(test_loader()):
model.eval_batch([data[0]],[data[1]])

# 使用 predict_batch 完成預(yù)測(cè)
for batch_id, data in enumerate(test_loader()):
model.predict_batch([data[0]])

五、高階用法

除此之外,飛槳高層 API 還支持一些高階的玩法,如自定義 Loss、自定義 Metric、自定義 Callback 等等。
自定義 Loss 是指有時(shí)我們會(huì)遇到特定任務(wù)的 Loss 計(jì)算方式在框架既有的 Loss 接口中不存在,或算法不符合自己的需求,那么期望能夠自己來進(jìn)行 Loss 的自定義。
自定義 Metric 和自定義 Loss 的場(chǎng)景一樣,如果遇到一些想要做個(gè)性化實(shí)現(xiàn)的操作時(shí),我們也可以來通過框架完成自定義的評(píng)估計(jì)算方法。
自定義 Callback 則是可以幫助我們收集訓(xùn)練時(shí)的一些參數(shù)以及數(shù)據(jù),由于 Model.fit()封裝了訓(xùn)練過程,如果我們需要保存訓(xùn)練時(shí)的 loss、metric 等信息,則需要通過 callback 參數(shù)收集這部分信息。
更多更豐富的玩法,可以掃描關(guān)注文末的二維碼獲取~
高層 API,Next
上文以 CV 任務(wù)為例,介紹了飛槳框架高層 API 的使用指南。后續(xù),飛槳框架還計(jì)劃推出 NLP 領(lǐng)域?qū)S玫臄?shù)據(jù)預(yù)處理模塊,如對(duì)數(shù)據(jù)進(jìn)行 padding、獲取數(shù)據(jù)集詞表等;在組網(wǎng)方面,也會(huì)實(shí)現(xiàn) NLP 領(lǐng)域中組網(wǎng)專用的 API,如組網(wǎng)相關(guān)的 sequence_mask,評(píng)估指標(biāo)相關(guān)的 BLEU 等;最后,針對(duì) NLP 領(lǐng)域中的神器 transformer,我們也會(huì)對(duì)其進(jìn)行特定的優(yōu)化;待這些功能上線后,我們會(huì)第一時(shí)間告訴大家,敬請(qǐng)期待吧~
高層 API,Where
看完前面飛槳高層 API 的使用介紹,是不是有種躍躍欲試的沖動(dòng)呀?
體驗(yàn)方式一:在線體驗(yàn)
無需準(zhǔn)備任何軟硬件環(huán)境,直接訪問以下地址,即可在線跑代碼看效果:https://aistudio.baidu.com/aistudio/projectdetail/1243085
體驗(yàn)方式二:本地體驗(yàn)
如果你還想在自己本地電腦上體驗(yàn),那需要確保本地電腦上已成功安裝飛槳開源框架 2.0。
下面介紹飛槳開源框架 2.0 的安裝方法,可以參考下面的命令,直接使用 pip 安裝。安裝后,就可以開始使用高層 API 啦。

本文章轉(zhuǎn)載微信公眾號(hào)@機(jī)器之心

#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)