從簡單的線性方程開始瞭解Paddle Fluid 的全連接層 FC

全連接層的數學表述可以參見Maples丶丶的《詳解神經網絡的前向傳播和反向傳播(從頭推導)》的“前向傳播”一節。

爲了容易理解,我還是從經典的波士頓房價談起。波士頓房價的詳細內容請參見https://www.paddlepaddle.org.cn/documentation/docs/zh/beginners_guide/basics/fit_a_line/README.cn.html

簡化一下,假設房價y與犯罪率x1、教育資源x2、建設時間x3、收入水平x4這四個因素線性相關:

則 y = a1*x1 + a2*x2 + a3*x3 + a4*x4 + b  

我通過建立 Paddle Fluid 的全連接層fc,就是根據大量的房價的調研數據,即把已知大量的 y 與 x1、x2、x3、x4對應關係的數據告訴FC,FC通過學習求出a1、a2、a3、a4、b。通過一段的學習後,即使給FC一組爲見過的x1、x2、x3、x4,FC也能預測出y。  

常量 b 由 fc 的 bias_attr 參數指定。爲了簡化,我使用了默認值None,表示該參數由 param_attr 參數決定。而 param_attr 也使用了默認值None,意味着a1、a2、a3、a4採用Xavier初始化方式以及偏置參數 b = 0。  

 

所謂全連接層是指每個輸入節點都與每個輸出節點相連。這裏只有一個輸出節點,所以 fc 的 size = 1,因不考慮非線性的激活函數,因而 fc 的 act = None。fc 函數的使用可寫爲如下格式:

y = paddle.fluid.layers.fc(input = x,size=1,act=None)      #語句1

上式中的參數input=x中的x是一個Tensor(對於複雜問題可以是多個Tensor),本例指有四個輸入節點(shape=4),每個輸入節點可以接受32bit的浮點數(dtype=float32)的Tensor。

我想給輸入端喂入的數據就是犯罪率x1、教育資源x2、建設時間x3、收入水平x4,假設x1=0.00632,x2=18,x3=2.31,x4=0.538

則在程序中可以如下定義數據:

input_data = numpy.array([[0.00632,18,2.31,0.538]]).astype('float32')    #語句2

我如果定義成numpy.array([0.00632,18,2.31,0.538]),則喂入數據時報錯。我想,這是因爲全連接層是爲了接收多組數據而設計的。我雖然只提供了一組數據,也不能shape=(4),而必須使得shape=(n,4)   n>=1。參見https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/layers_cn/fc_cn.html

但是這組數據不能直接喂入到全連接層的輸入節點,必須通過輸入層才能將數據輸入到神經網絡中。輸入層可以使用data算子創建,本例的輸入層在程序中可以如下定義,注意輸入層必須與輸入的數據完全匹配才行:

x = paddle.fluid.data(name='datax',shape=[-1,4],dtype='float32')  #語句3

其中語句3的x與語句1的input值保持一致。上句中的name='datax'是輸入層輸出的前綴標識。

注:老版本使用的是 paddle.fluid.layers.data,fluid1.6改爲 paddle.fluid.data後,Executor運行時檢查輸入數據的維度和數據類型。詳見

https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/data_cn.html

https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/layers_cn/data_cn.html

語句3和語句2就搭建了一個簡單的神經網絡,語句2準備了輸入數據。欲使網絡工作,還需要定義執行器:

cpu = paddle.fluid.core.CPUPlace()
exe = paddle.fluid.Executor(cpu)一致。
exe.run(paddle.fluid.default_startup_program())

下面就可以喂入數據,指定需要觀察的中間過程:

outs = exe.run( feed={'datax':input_data},   # datax與語句3的name值保持一致,input_data與語句2的input_data一致。 

                                fetch_list=[y])                            # 對全連接層的輸出值感興趣

這個例子的完整程序如下:

 

import paddle.fluid as fluid
import numpy

#準備原始數據
input_data=numpy.array([[0.00632,18,2.31,0.538]]).astype('float32')
#print(input_data.shape) # 查看原始數據的shape

#定義輸入層
#以下2條語句都可以用。任選其中一條
x=fluid.data(name="datax",shape=[-1,4],dtype='float32')  # 喂入的數據組數不確定 
# x=fluid.data(name="datax",shape=[1,4],dtype='float32') # 只喂入一組數據

#定義全連接層
y=fluid.layers.fc(input=x,size=1,act=None)

#定義執行器:cpu版
cpu = fluid.core.CPUPlace()
exe = fluid.Executor(cpu)
exe.run(fluid.default_startup_program()) # 運行默認的啓動程序

# 運行並打印結果
out = exe.run(feed={'datax':input_data},fetch_list=[x,y]) 
print(out)
 

某次的運行結果(因爲有學習能力,所以每次的結果不同)如下:

那麼a1、a2、a3、a4到底等於多少呢?那是機器學習自己調整的模型參數,我看不到。我只關心給一組x1、x2、x3、x4後,y是多少。

爲了達到實用效果,我還要對這個FC進行考覈,把考覈的結果通知FC,FC就會不斷進步了。這牽涉到誤差計算和優化方法,相關的學習筆記我會另外再寫。

最後,選取 fluid1.5 上的一個官方代碼實例,作爲本篇的結尾。

#!/usr/bin/python
#_*_ coding: utf-8 _*_

'''
官網上的一個fluid 配置網絡的代碼示例,略作改編
https://www.paddlepaddle.org.cn/documentation/docs/zh/1.5/beginners_guide/programming_guide/programming_guide.html#id2
CSY 2019-2-30

'''

#加載庫
import paddle.fluid as fluid
import numpy

'''
已知:
當x=1時,y=2;
當x=2時,y=4;
當x=3時,y=6;
當x=4時,y=8;
'''
#定義X數值
train_data=numpy.array([[1.0],[2.0],[3.0],[4.0]]).astype('float32')
#定義期望預測的真實值y_true
# y_true = numpy.array([[2.0],[4.0],[6.0],[8.0]]).astype('float32') # 用於損失函數,暫忽略

#定義輸入層
x = fluid.data(name="x",shape=[-1,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) # 一組隨機數字,與 y_true 相差甚遠

運行結果如下:

最後,附上官方的相關解釋:

關於paddle.fluid.data
paddle.fluid.data()是一個OP(算子),作用就是創建一個全局變量,可供計算圖中的算子訪問,可作爲佔位符用於數據輸入。
name 是paddle.fluid.data()創建的全局變量的名字,是輸入層輸出的前綴標識。   
shape 聲明瞭paddle.fluid.data()創建的全局變量的維度信息。  
shape中的None 表示不確定該維的元素數量,待程序執行中確定。  
shape中的-1 只能在shape的最前面,表示可以適應任何 batch size  
dtype 是paddle.fluid.data()創建的全局變量的數據類型,支持 bool,float16,float32,float64,int8,int16,int32,int64。  
用戶 feed 的數據必須與 paddle.fluid.data() 創建的變量具有相同的 shape  
雖然feed的數據,其類型是unsigned Byte,但softmax 迴歸是要進行浮點運算的,所以數據類型都轉換成了float32

關於paddle.fluid.layers.fc
paddle.fluid.layers.fc()是一個OP,作用就是建立一個全連接層。爲每個輸入的Tensor創建一個權重變量,即一個從每個輸入單元到每個輸出單元的全連接權重矩陣。  
FC層將每個輸入Tensor和其對應的權重(weights)相乘得到shape爲 [M,size] 輸出Tensor,其中 M 爲batch_size大小。如果有多個輸入Tensor,則多個shape爲 [M,size] 的Tensor計算結果會被累加起來,作爲最終輸出。

發佈了36 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章