如何用Paddle Fluid API搭建簡單的神經網絡?這裡有一份編程指南

2020-12-16 機器之心Pro

PaddlePaddle 是百度自主研發,集深度學習核心框架、工具組件和服務平臺為一體的開源深度學習平臺。該平臺技術領先、功能完備。Paddle Fluid 是 PaddlePaddle 的核心框架,滿足模型開發、訓練、部署的全流程需求。本文將展示如何用 Paddle Fluid API 編程並搭建一個簡單的神經網絡。

本文將介紹:

Paddle Fluid 有哪些核心概念如何在 Paddle Fluid 中定義運算過程如何使用 executor 運行 Paddle Fluid 操作如何從邏輯層對實際問題建模如何調用 API(層,數據集,損失函數,優化方法等等)

使用 Tensor 表示數據

Paddle Fluid 和其它主流框架一樣,使用 Tensor 數據結構來承載數據。Tensor 可以簡單理解成一個多維數組,一般而言可以有任意多的維度。不同的 Tensor 可以具有自己的數據類型和形狀,同一 Tensor 中每個元素的數據類型是一樣的,Tensor 的形狀就是 Tensor 的維度。

下圖直觀地表示 1~6 維的 Tensor:

在 Paddle Fluid 中存在三種特殊的 Tensor:

1. 模型中的可學習參數

模型中的可學習參數(包括網絡權重、偏置等)生存期和整個訓練任務一樣長,會接受優化算法的更新,在 Paddle Fluid 中以 Variable 的子類 Parameter 表示。

在 Paddle Fluid 中可以通過 fluid.layers.create_parameter 來創建可學習參數:

w = fluid.layers.create_parameter(name="w",shape=[1],dtype='float32')

一般情況下,您不需要自己來創建網絡中的可學習參數,Paddle Fluid 為大部分常見的神經網絡基本計算模塊都提供了封裝。以最簡單的全連接模型為例,下面的代碼片段會直接為全連接層創建連接權值(W)和偏置(bias)兩個可學習參數,無需顯式地調用 Parameter 相關接口來創建。

import paddle.fluid as fluidy = fluid.layers.fc(input=x, size=128, bias_attr=True)

2. 輸入輸出 Tensor

整個神經網絡的輸入數據也是一個特殊的 Tensor,在這個 Tensor 中,一些維度的大小在定義模型時無法確定(通常包括:batch size,如果 mini-batch 之間數據可變,也會包括圖片的寬度和高度等),在定義模型時需要佔位。

Paddle Fluid 中使用 fluid.layers.data 來接收輸入數據,fluid.layers.data 需要提供輸入 Tensor 的形狀信息,當遇到無法確定的維度時,相應維度指定為 None 或 -1,如下面的代碼片段所示:

import paddle.fluid as fluid#定義x的維度為[3,None],其中我們只能確定x的第一的維度為3,第二個維度未知,要在程序執行過程中才能確定x = fluid.layers.data(name="x", shape=[3,None], dtype="int64")#batch size無需顯示指定,框架會自動補充第0維為batch size,並在運行時填充正確數值a = fluid.layers.data(name="a",shape=[3,4],dtype='int64')#若圖片的寬度和高度在運行時可變,將寬度和高度定義為None。#shape的三個維度含義分別是:channel、圖片的寬度、圖片的高度b = fluid.layers.data(name="image",shape=[3,None,None],dtype="float32")

其中,dtype="int64" 表示有符號 64 位整數數據類型,更多 Paddle Fluid 目前支持的數據類型請在官網查閱:http://paddlepaddle.org/documentation/docs/zh/1.4/user_guides/howto/prepare_data/feeding_data.html#fluid。

3. 常量 Tensor

Paddle Fluid 通過 fluid.layers.fill_constant 來實現常量 Tensor,用戶可以指定 Tensor 的形狀,數據類型和常量值。代碼實現如下所示:

import paddle.fluid as fluiddata = fluid.layers.fill_constant(shape=[1], value=0, dtype='int64')

需要注意的是,上述定義的 tensor 並不具有值,它們僅表示將要執行的操作,如您直接列印 data 將會得到描述該 data 的一段信息:

print data

輸出結果:

name: "fill_constant_0.tmp_0"type {type: LOD_TENSOR lod_tensor { tensor { data_type: INT64 dims: 1 } }}persistable: false

具體輸出數值將在 Executor 運行時得到,詳細過程會在後文展開描述。

數據傳入

Paddle Fluid 有特定的數據傳入方式:

您需要使用 fluid.layers.data 配置數據輸入層,並在 fluid.Executor 或 fluid.ParallelExecutor 中,使用 executor.run(feed=...) 傳入訓練數據。

具體的數據準備過程,您可以閱讀官網使用指南「準備數據」章節。

使用 Operator 表示對數據的操作

在 Paddle Fluid 中,所有對數據的操作都由 Operator 表示,您可以使用內置指令來描述它們的神經網絡。為了便於用戶使用,在 Python 端,Paddle Fluid 中的 Operator 被一步封裝入 paddle.fluid.layers,paddle.fluid.nets 等模塊。這是因為一些常見的對 Tensor 的操作可能是由更多基礎操作構成,為了提高使用的便利性,框架內部對基礎 Operator 進行了一些封裝,包括創建 Operator 依賴可學習參數,可學習參數的初始化細節等,減少用戶重複開發的成本。例如用戶可以利用 paddle.fluid.layers.elementwise_add() 實現兩個輸入 Tensor 的加法運算:

#定義網絡import paddle.fluid as fluida = fluid.layers.data(name="a",shape=[1],dtype='float32')b = fluid.layers.data(name="b",shape=[1],dtype='float32')result = fluid.layers.elementwise_add(a,b)#定義Exectorcpu = fluid.core.CPUPlace() #定義運算場所,這裡選擇在CPU下訓練exe = fluid.Executor(cpu) #創建執行器exe.run(fluid.default_startup_program()) #網絡參數初始化#準備數據import numpydata_1 = int(input("Please enter an integer: a="))data_2 = int(input("Please enter an integer: b="))x = numpy.array([[data_1]])y = numpy.array([[data_2]])#執行計算outs = exe.run(feed={'a':x,'b':y}, fetch_list=[result.name])#驗證結果print "%d+%d=%d" % (data_1,data_2,outs[0][0])

輸出結果:

a=7b=37+3=10

本次運行時,輸入 a=7,b=3,得到 outs=10。

您可以複製這段代碼在本地執行,根據指示輸入其它數值觀察計算結果。

如果想獲取網絡執行過程中的 a,b 的具體值,可以將希望查看的變量添加在 fetch_list 中。

...#執行計算outs = exe.run(feed={'a':x,'b':y}, fetch_list=[a,b,result.name])#查看輸出結果print outs

輸出結果:

[array([[7]]), array([[3]]), array([[10]])]

使用 Program 描述神經網絡模型

Paddle Fluid 不同於其它大部分深度學習框架,去掉了靜態計算圖的概念,代之以 Program 的形式動態描述計算過程。這種動態的計算描述方式兼具網絡結構修改的靈活性和模型搭建的便捷性,在保證性能的同時極大地提高了框架對模型的表達能力。

開發者的所有 Operator 都將寫入 Program,在 Paddle Fluid 內部將自動轉化為一種叫作 ProgramDesc 的描述語言,Program 的定義過程就像在寫一段通用程序,有開發經驗的用戶在使用 Paddle Fluid 時,會很自然的將自己的知識遷移過來。

其中,Paddle Fluid 通過提供順序、分支和循環三種執行結構的支持,讓用戶可以通過組合描述任意複雜的模型。

順序執行:

用戶可以使用順序執行的方式搭建網絡:

x = fluid.layers.data(name='x',shape=[13], dtype='float32')y_predict = fluid.layers.fc(input=x, size=1, act=None)y = fluid.layers.data(name='y', shape=[1], dtype='float32')cost = fluid.layers.square_error_cost(input=y_predict, label=y)

條件分支——switch、if else:

Paddle Fluid 中有 switch 和 if-else 類來實現條件選擇,用戶可以使用這一執行結構在學習率調節器中調整學習率或其它希望的操作:

lr = fluid.layers.tensor.create_global_var(shape=[1], value=0.0, dtype='float32', persistable=True, name="learning_rate")one_var = fluid.layers.fill_constant(shape=[1], dtype='float32', value=1.0)two_var = fluid.layers.fill_constant(shape=[1], dtype='float32', value=2.0)with fluid.layers.control_flow.Switch() as switch: with switch.case(global_step == zero_var): fluid.layers.tensor.assign(input=one_var, output=lr) with switch.default(): fluid.layers.tensor.assign(input=two_var, output=lr)

關於 Paddle Fluid 中 Program 的詳細設計思想,可以參考閱讀官網進階使用「設計思想」中更多 Fluid 中的控制流,可以參考閱讀 API 文檔。

使用 Executor 執行 Program

Paddle Fluid 的設計思想類似於高級程式語言 C++和 JAVA 等。程序的執行過程被分為編譯和執行兩個階段。用戶完成對 Program 的定義後,Executor 接受這段 Program 並轉化為 C++後端真正可執行的 FluidProgram,這一自動完成的過程叫做編譯。編譯過後需要 Executor 來執行這段編譯好的 FluidProgram。例如上文實現的加法運算,當構建好 Program 後,需要創建 Executor,進行初始化 Program 和訓練 Program:

#定義Exectorcpu = fluid.core.CPUPlace() #定義運算場所,這裡選擇在CPU下訓練exe = fluid.Executor(cpu) #創建執行器exe.run(fluid.default_startup_program()) #用來進行初始化的program#訓練Program,開始計算#feed以字典的形式定義了數據傳入網絡的順序#fetch_list定義了網絡的輸出outs = exe.run(feed={'a':x,'b':y}, fetch_list=[result.name])

代碼實例

您已經對 Paddle Fluid 核心概念有了初步認識了,不妨嘗試配置一個簡單的網絡吧。如果感興趣的話可以跟隨本部分,完成一個非常簡單的數據預測。

從邏輯層面明確了輸入數據格式、模型結構、損失函數以及優化算法後,需要使用 Paddle Fluid 提供的 API 及算子來實現模型邏輯。一個典型的模型主要包含 4 個部分,分別是:輸入數據格式定義,模型前向計算邏輯,損失函數以及優化算法。

1、問題描述

給定一組數據 <X,Y>,求解出函數 f,使得 y=f(x),其中 X,Y 均為一維張量。最終網絡可以依據輸入 x,準確預測出 y_predict。

2、定義數據

假設輸入數據 X=[1 2 3 4],Y=[2,4,6,8],在網絡中定義:

#定義X數值train_data=numpy.array([[1.0],[2.0],[3.0],[4.0]]).astype('float32')#定義期望預測的真實值y_truey_true = numpy.array([[2.0],[4.0],[6.0],[8.0]]).astype('float32')

3、搭建網絡(定義前向計算邏輯)

接下來需要定義預測值與輸入的關係,本次使用一個簡單的線性回歸函數進行預測:

#定義輸入數據類型x = fluid.layers.data(name="x",shape=[1],dtype='float32')#搭建全連接網絡y_predict = fluid.layers.fc(input=x,size=1,act=None)

這樣的網絡就可以進行預測了,雖然輸出結果只是一組隨機數,離預期結果仍相差甚遠:

#加載庫import paddle.fluid as fluidimport numpy#定義數據train_data=numpy.array([[1.0],[2.0],[3.0],[4.0]]).astype('float32')y_true = numpy.array([[2.0],[4.0],[6.0],[8.0]]).astype('float32')#定義預測函數x = fluid.layers.data(name="x",shape=[1],dtype='float32')y_predict = fluid.layers.fc(input=x,size=1,act=None)#參數初始化cpu = fluid.core.CPUPlace()exe = fluid.Executor(cpu)exe.run(fluid.default_startup_program())#開始訓練outs = exe.run(feed={'x':train_data}, fetch_list=[y_predict.name])#觀察結果print outs

輸出結果:

[array([[0.74079144],[1.4815829 ], [2.2223744 ], [2.9631658 ]], dtype=float32)]

4、添加損失函數

完成模型搭建後,如何評估預測結果的好壞呢?我們通常在設計的網絡中添加損失函數,以計算真實值與預測值的差。

在本例中,損失函數採用均方差函數:

cost = fluid.layers.square_error_cost(input=y_predict, label=y)avg_cost = fluid.layers.mean(cost)

輸出一輪計算後的預測值和損失函數:

#加載庫import paddle.fluid as fluidimport numpy#定義數據train_data=numpy.array([[1.0],[2.0],[3.0],[4.0]]).astype('float32')y_true = numpy.array([[2.0],[4.0],[6.0],[8.0]]).astype('float32')#定義網絡x = fluid.layers.data(name="x",shape=[1],dtype='float32')y = fluid.layers.data(name="y",shape=[1],dtype='float32')y_predict = fluid.layers.fc(input=x,size=1,act=None)#定義損失函數cost = fluid.layers.square_error_cost(input=y_predict,label=y)avg_cost = fluid.layers.mean(cost)#參數初始化cpu = fluid.core.CPUPlace()exe = fluid.Executor(cpu)exe.run(fluid.default_startup_program())#開始訓練outs = exe.run(feed={'x':train_data,'y':y_true}, fetch_list=[y_predict.name,avg_cost.name])#觀察結果print outs

輸出結果:

[array([[0.9010564],[1.8021128], [2.7031693], [3.6042256]], dtype=float32), array([9.057577], dtype=float32)]

可以看到第一輪計算後的損失函數為 9.0,仍有很大的下降空間。

5、網絡優化

確定損失函數後,可以通過前向計算得到損失值,然後通過鏈式求導法則得到參數的梯度值。

獲取梯度值後需要更新參數,最簡單的算法是隨機梯度下降法:w=wηg,由 fluid.optimizer.SGD 實現:

sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.01)

讓我們的網絡訓練 100 次,查看結果:

#加載庫import paddle.fluid as fluidimport numpy#定義數據train_data=numpy.array([[1.0],[2.0],[3.0],[4.0]]).astype('float32')y_true = numpy.array([[2.0],[4.0],[6.0],[8.0]]).astype('float32')#定義網絡x = fluid.layers.data(name="x",shape=[1],dtype='float32')y = fluid.layers.data(name="y",shape=[1],dtype='float32')y_predict = fluid.layers.fc(input=x,size=1,act=None)#定義損失函數cost = fluid.layers.square_error_cost(input=y_predict,label=y)avg_cost = fluid.layers.mean(cost)#定義優化方法sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.01)sgd_optimizer.minimize(avg_cost)#參數初始化cpu = fluid.core.CPUPlace()exe = fluid.Executor(cpu)exe.run(fluid.default_startup_program())##開始訓練,迭代100次for i in range(100):outs = exe.run( feed={'x':train_data,'y':y_true}, fetch_list=[y_predict.name,avg_cost.name])#觀察結果print outs

輸出結果:

[array([[2.2075021],[4.1005487], [5.9935956], [7.8866425]], dtype=float32), array([0.01651453], dtype=float32)]

可以看到 100 次迭代後,預測值已經非常接近真實值了,損失值也從初始值 9.05 下降到了 0.01。

至此,恭喜您!已經成功使用 PaddlePaddle 核心框架 Paddle Fluid 搭建了一個簡單網絡。如果您還想嘗試更多,可以從官網繼續閱讀相關的文檔及更多豐富的模型實例。

PaddlePaddle 項目地址:https://github.com/PaddlePaddlePaddlePaddle 官網使用指南地址:http://paddlepaddle.org/documentation/docs/zh/1.4/user_guides/index_cn.html?from=paddlenav

相關焦點

  • 從零學Paddle系列-1 Paddle框架CNN相關API詳解
    上面的API都屬於paddle.fluid.dygraph的 下面我們介紹細粒度更高的API系列paddle.fluid.layerspaddle.fluid.layerselement_wise_add(sub/mul/div/max等等)這是對應元素操作系列,包含加減乘除 你可以使用這個api,也可以直接使用運算符+ - ,paddle
  • PaddlePaddle 2.0.0 Beta 發布,API 體系升級,命令式編程完善
    此外,推理庫的C++接口也做了升級優化,推理庫對量化模型的支持以及推理性能都有了全面增強。訓練框架基礎API兼容性說明 Paddle 2.x版本推薦用戶使用位於paddle根目錄下的API,同時在paddle.fluid目錄下保留了所有的Paddle 1.x版本的API。
  • 手把手教你PaddlePaddle 做詞向量模型 SkipGram實戰
    目前流行的方法有大約三種:• 特徵工程:這類方法依賴於手工特徵,例如 tf-idf 同時考慮詞頻和詞的稀缺度;• 統計方法:統計上常常通過矩陣分解(如 SVD、EVD)來建模大規模文檔集合;• 神經網絡:目前非常流行通過神經網絡端到端的建模語言模型,
  • 基於PaddlePaddle的詞向量實戰 | 深度學習基礎任務教程系列(二)
    詞向量模型可以是概率模型、共生矩陣(co-occurrence matrix)模型或神經元網絡模型。在用神經網絡模型求詞向量之前,傳統的做法是統計一個詞語的共生矩陣X,在對X做矩陣分解,得到了所有詞的詞向量。但是傳統的方法有三大問題:1)由於很多詞沒有出現,導致矩陣極其稀疏;2)矩陣非常大,維度太高;3)需要手動去掉停用詞(如although, a,...)
  • 520禮包 | 情感分析算法從原理到PaddlePaddle實戰全解
    循環神經網絡(RNN)循環神經網絡是一種能對序列數據進行精確建模的有力工具。實際上,循環神經網絡的理論計算能力是圖靈完備的[4]。如,可以把一個循環神經網絡的隱層輸出連接至下一個循環神經網絡的輸入構建深層(deep or stacked)循環神經網絡,或者提取最後一個時刻的隱層狀態作為句子表示進而使用分類模型等等。長短期記憶網絡(LSTM)對於較長的序列數據,循環神經網絡的訓練過程中容易出現梯度消失或爆炸現象[6]。
  • PaddlePaddle實戰 | 情感分析算法從原理到實戰全解
    另外,我們也可使用窗口大小不同的卷積核來處理句子,圖1表示卷積神經網絡文本分類模型,不同顏色表示不同大小的卷積核操作。對於一般的短文本分類問題,上文所述的簡單的文本卷積網絡即可達到很高的正確率[1]。若想得到更抽象更高級的文本特徵表示,可以構建深層文本卷積神經網絡[2,3]。循環神經網絡(RNN)循環神經網絡是一種能對序列數據進行精確建模的有力工具。
  • 全面支持三大主流環境 |百度PaddlePaddle新增Windows環境支持
    PaddlePaddle在功能完備的基礎上,也儘量秉承易學易用的特點,在Windows的安裝方面,體現了一鍵式的特點,大部分情況下,只需要一條簡單的命令就可以完成安裝。用戶在使用的過程中可能會面對安裝和編譯方面的問題,下面就從這兩個方面來分別說明。
  • 用飛槳做自然語言處理:神經網絡語言模型應用實例 - 量子位
    但這種方法會有一個很大的問題,那就是前面提到的維度災難,而這裡要實現的神經網絡語言模型(Neural Network Language Model),便是用神經網絡構建語言模型,通過學習分布式詞表示(即詞向量)的方式解決了這個問題。
  • 基礎入門,怎樣用PaddlePaddle優雅地寫VGG與ResNet
    一般來說,圖像分類通過手工提取特徵或特徵學習方法對整個圖像進行全部描述,然後使用分類器判別物體類別,因此如何提取圖像的特徵至關重要。基於深度學習的圖像分類方法,可以通過有監督或無監督的方式學習層次化的特徵描述,從而取代了手工設計或選擇圖像特徵的工作。
  • 基於飛槳PaddlePaddle的語義角色標註任務全解析
    循環神經網絡(Recurrent Neural Network)是一種對序列建模的重要模型,在自然語言處理任務中有著廣泛地應用。不同於前饋神經網絡(Feed-forward Neural Network),RNN 能夠處理輸入之間前後關聯的問題。
  • 我用Paddle Lite在樹莓派3b+上從零開始搭建「實時表情識別」項目
    從模型訓練到部署,飛槳都有成熟的配套工具和流程,大大降低了項目開發的時間成本。最終效果如何?怎麼做的呢?且看接下來的詳細分解。其中訓練模型的數據是Kaggle ICML2013 fer2013人臉表情識別數據集,總數據量35866。將csv數據轉圖片後分別保存在不同類別的文件夾即可用來訓練模型。項目選取happy、normal、surprised和angry四種類別辨識度較高的數據。
  • 用PaddlePaddle 和 Tensorflow 實現經典 CNN 網絡 GoogLeNet
    (本系列所有代碼均在 github:https://github.com/huxiaoman7/PaddlePaddle_code)關於深度網絡的一些思考  在本系列最開始的幾篇文章我們講到了卷積神經網絡,設計的網絡結構也非常簡單,屬於淺層神經網絡,如三層的卷積神經網絡等,但是在層數比較少的時候,有時候效果往往並沒有那麼好,在實驗過程中發現,當我們嘗試增加網絡的層數
  • 乘風破浪的Paddle之LSTM
    自然語言處理(NLP)主要是研究實現人與計算機之間用自然語言進行有效通信的各種理論和方法。基於神經網絡的深度學習技術具有強大的表達能力、端到端解決問題的能力,因而在NLP任務的應用上越來越廣泛和有效。長短期記憶網絡是一種時間循環神經網絡,是為了解決一般的RNN存在的長期依賴問題而專門設計出來的,所有的RNN都具有一種重複神經網絡模塊的鏈式形式。
  • 【深度學習系列】用PaddlePaddle和Tensorflow實現經典CNN網絡GoogLeNet
    GoogLeNet是由google的Christian Szegedy等人在2014年的論文《Going Deeper with Convolutions》提出,其最大的亮點是提出一種叫Inception的結構,以此為基礎構建GoogLeNet,並在當年的ImageNet分類和檢測任務中獲得第一ps:GoogLeNet的取名是為了向YannLeCun的LeNet系列致敬。
  • 教程| 如何用百度深度學習框架PaddlePaddle做數據預處理
    舉個例子,手寫數字識別裡的輸入圖片是 28*28 的像素,Paddle 的神經網絡的輸入應該是一個 784 維的稠密向量。( table4_path ), buf_size = 100 ),500 )如果新發現了一個特徵,想嘗試這個特徵對模型提高準確率有沒有用,可以再單獨把這個特徵數據提取出來,再增加一個 reader,用 reader decorator 組合起來,shuffle 後放入模型裡跑就行了。
  • PaddlePaddle升級解讀 | PaddleHub輕鬆完成遷移學習
    我們以run命令為例,介紹如何通過命令行工具進行預測。Run命令用於執行Module的預測,這裡分別舉一個NLP和CV的例子。對於NLP任務:輸入數據通過--input_text指定。以百度LAC模型(中文詞法分析)為例,可以通過以下命令實現單行文本分析。
  • PaddlePaddle入門:從對話系統中的情感分析談起
    3.3.2 模型搭建paddle中一個模型的搭建需要完成從數據到輸出整個網絡的定義。本文所選的三種模型均可以由神經網絡模型來表示,只是在隱層(hidden layer)以及全連接層(full connected layer)有所區別而已。
  • Python視頻教程網課編程零基礎入門數據分析網絡爬蟲全套Python...
    (1套課程) 數據分析與挖掘(8套課程) 辦公自動化(3套課程) 機器學習與人工智慧(7套課程) 開發實戰篇(4套課程) 量化投資(2套課程) 網絡爬蟲(6套課程) 資料庫操作(1套課程) python高級編程(6套課程) 注:零基礎全能篇中,針對windows和liunx系統均有兩套課程可供選擇學習
  • 教程 | 如何用百度深度學習框架PaddlePaddle做數據預處理
    我們知道,基本的方法一般有兩種:在 PaddlePaddle 中我們可以有三種模式來讀取數據:分別是 reader、reader creator 和 reader decorator, 這三者有什麼區別呢?reader:從本地、網絡、分布式文件系統 HDFS 等讀取數據,也可隨機生成數據,並返回一個或多個數據項。