[Python人工智慧] 二.theano實現迴歸神經網路分析

Eastmount發表於2018-05-21

從本篇文章開始,作者正式開始研究Python深度學習、神經網路及人工智慧相關知識。前一篇文章主要講解神經網路基礎概念,同時講解Theano庫的安裝過程及基礎用法,這篇文章主要講解theano實現迴歸神經網路,主要是學習"莫煩大神" 網易雲視訊的線上筆記,後面隨著深入會講解具體的專案及應用。基礎性文章,希望對您有所幫助,也建議大家一步步跟著學習,同時文章中存在錯誤或不足之處,還請海涵~

"莫煩大神" 網易雲視訊地址:http://study.163.com/provider/1111519/course.html

同時推薦前面作者另外三個Python系列文章。

從2014年開始,作者主要寫了三個Python系列文章,分別是基礎知識、網路爬蟲和資料分析。

這裡寫圖片描述 這裡寫圖片描述 這裡寫圖片描述


一. 定義神經網路Layer類


如下圖所示,通過該神經網路識別動物貓或狗,共包括輸入層(Input Layer)、隱藏層3層(Hidden Layer)和輸出層(Output Layer)。其中每一個神經元都有一個激勵函式,被激勵的神經元傳遞的資訊最有價值,它也決定最後的輸出結果,經過海量資料的訓練,最終神經網路將可以用於識別貓或狗。

神經網路激勵函式參考:

http://deeplearning.net/software/theano/library/tensor/nnet/nnet.html
激勵函式相當於一個過濾器或激勵器,它把特有的資訊或特徵啟用,常見的啟用函式包括softplus、sigmoid、relu、softmax、elu、tanh等。對於隱藏層,我們可以使用relu、tanh、softplus等非線性關係;對於分類問題,我們可以使用sigmoid(值越小越接近於0,值越大越接近於1)、softmax函式,對每個類求概率,最後以最大的概率作為結果;對於迴歸問題,可以使用線性函式(linear function)來實驗。



神經網路首先需要新增神經層,將層(Layer)定義成類,通過類來新增神經層。神經層是相互連結,並且是全連線,從第一層輸入層傳入到隱藏層,最後傳輸至輸出層。假設接下來需要定義兩層內容:
    L1 = Layer(inputs, in_size=1, out_size=10, activation_function)
    引數包括輸入值,輸入節點數,輸出節點數和激勵函式
    L2 = Layer(L1.outputs, 10, 1, None)
    引數中L1的輸出作為輸入值,L1的輸出10個節點作為輸入節點,輸出節點1個,激勵函式為None。

定義類的程式碼如下,包括權重和bias,其中引數為隨機變數更有利於我們後面的更新,亂序更能促進神經網路的學習。

class Layer(object):
    def __init__(self, inputs, in_size, out_size, activation_function=None):
        #權重: 平均值為0 方差為1 行數為in_size  列數為out_size
        self.W = theano.shared(np.random.normal(0,1,(in_size,out_size)))
        #bias
        self.b = theano.shared(np.zeros((out_size,) ) + 0.1)
        #乘法加bias
        self.Wx_plus_b = T.dot(inputs, self.W) + self.b #dot乘法
        #激勵函式
        self.activation_function = activation_function

        #預設為None,否則進行啟用
        if activation_function is None: 
            self.outputs = self.Wx_plus_b
        else: 
            self.outputs = self.activation_function(self.Wx_plus_b)



二. 迴歸神經網路實現

接下來開始跟著莫煩大聲實現了第一個神經網路程式碼,步驟如下:

1.製造虛擬資料

通過numpy.linspace生成300個隨機點進行訓練,形成y=x^2-0.5的虛擬資料。程式碼如下:

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

class Layer(object):
    def __init__(self, inputs, in_size, out_size, activation_function=None):
        #權重: 平均值為0 方差為1 行數為in_size  列數為out_size
        self.W = theano.shared(np.random.normal(0,1,(in_size,out_size)))
        #bias
        self.b = theano.shared(np.zeros((out_size,) ) + 0.1)
        #乘法加bias
        self.Wx_plus_b = T.dot(inputs, self.W) + self.b #dot乘法
        #激勵函式
        self.activation_function = activation_function

        #預設為None,否則進行啟用
        if activation_function is None: 
            self.outputs = self.Wx_plus_b
        else: 
            self.outputs = self.activation_function(self.Wx_plus_b)

            
#迴歸神經網路 Regression
            
#1.製造虛擬資料
import matplotlib.pyplot as plt
#Make up some fake data
x_data = np.linspace(-1,1,300)[:, np.newaxis] #300個點進行訓練
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise   #y = x^2 - 0.5
#一元二次散點圖
plt.scatter(x_data, y_data)
plt.show()

生產的一元二次隨機散點圖如下圖所示:


圖1 散點圖結果


2.增加神經層

定義輸入x和y,注意其dtype型別為64位浮點型,整個程式碼前後型別需要保持一致。同時定義了L1層和L2層:
    L1 = Layer(x, 1, 10, T.nnet.relu)
    輸入為x,1維的data,神經元10個,relu非線性激勵函式
    L2 = Layer(L1.outputs, 10, 1, None)
    輸入為L1輸出值, L2的in_size為L1的神經元10,假設L2輸出為最終output

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

class Layer(object):
    def __init__(self, inputs, in_size, out_size, activation_function=None):
        #權重: 平均值為0 方差為1 行數為in_size  列數為out_size
        self.W = theano.shared(np.random.normal(0,1,(in_size,out_size)))
        #bias
        self.b = theano.shared(np.zeros((out_size,) ) + 0.1)
        #乘法加bias
        self.Wx_plus_b = T.dot(inputs, self.W) + self.b #dot乘法
        #激勵函式
        self.activation_function = activation_function

        #預設為None,否則進行啟用
        if activation_function is None: 
            self.outputs = self.Wx_plus_b
        else: 
            self.outputs = self.activation_function(self.Wx_plus_b)

            
#迴歸神經網路 Regression
            
#1.製造虛擬資料
import matplotlib.pyplot as plt
#Make up some fake data
x_data = np.linspace(-1,1,300)[:, np.newaxis] #300個點進行訓練
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise   #y = x^2 - 0.5
#一元二次散點圖
plt.scatter(x_data, y_data)
plt.show()

#2.定義輸入和神經元
#determine the inputs dytpe
x = T.dmatrix('x')  #d代表64位float型別
y = T.dmatrix('y')
#add layers
L1 = Layer(x, 1, 10, T.nnet.relu) 
L2 = Layer(L1.outputs, 10, 1, None)

3.計算誤差與梯度下降更新

定義cost變數計算誤差,即預測值與真實值的差別;再定義梯度下降變數,其誤差越大,降低趨勢越大,通過梯度下降讓預測值更接近真實值。程式碼中通過theano.function()函式更新神經網路的四個引數,計算公式如下啊:
L1.W, L1.W-learnging_rate*gW1:
(原始的權重-學習效率*下降幅度)並且更新為L1.W,通過該方法將L1.W、L1.b、L2.W、L2.b更新。

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

class Layer(object):
    def __init__(self, inputs, in_size, out_size, activation_function=None):
        #權重: 平均值為0 方差為1 行數為in_size  列數為out_size
        self.W = theano.shared(np.random.normal(0,1,(in_size,out_size)))
        #bias
        self.b = theano.shared(np.zeros((out_size,) ) + 0.1)
        #乘法加bias
        self.Wx_plus_b = T.dot(inputs, self.W) + self.b #dot乘法
        #激勵函式
        self.activation_function = activation_function

        #預設為None,否則進行啟用
        if activation_function is None: 
            self.outputs = self.Wx_plus_b
        else: 
            self.outputs = self.activation_function(self.Wx_plus_b)

            
#迴歸神經網路 Regression
            
#1.製造虛擬資料
import matplotlib.pyplot as plt
#Make up some fake data
x_data = np.linspace(-1,1,300)[:, np.newaxis] #300個點進行訓練
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise   #y = x^2 - 0.5
#一元二次散點圖
plt.scatter(x_data, y_data)
plt.show()

#2.定義輸入和神經元
#determine the inputs dytpe
x = T.dmatrix('x')  #d代表64位float型別
y = T.dmatrix('y')
#add layers
L1 = Layer(x, 1, 10, T.nnet.relu) 
L2 = Layer(L1.outputs, 10, 1, None)

#3.計算誤差與梯度下降更新
#誤差為預測值與真實值差別
cost = T.mean(T.square(L2.outputs - y)) #mean()求平均誤差
#compute the gradients
#梯度下降,讓預測值更接近真實值,誤差越大,降低趨勢越大
gW1, gb1, gW2, gb2 = T.grad(cost, [L1.W, L1.b, L2.W, L2.b]) #權重和bias
#apply gradient descent
#學習效率: 神經網路中learning_rate通常小於1的數字,0.05保證神經網路學習比較精細
learning_rate = 0.05

#更新四個神經網路的引數
train = theano.function(
    inputs = [x,y],
    outputs = cost,
    updates = [(L1.W, L1.W-learning_rate*gW1),
               (L1.b, L1.b-learning_rate*gb1),
               (L2.W, L2.W-learning_rate*gW2),
               (L2.b, L2.b-learning_rate*gb2)
               ] 
    )
#(L1.W, L1.W-learnging_rate*gW1)
#(原始的權重-學習的效率*下降的幅度)更新為L1.W

4.預測結果

最後是預測結果,訓練時會給出x和y求cost,而預測時只給出輸入x,用來做預測。最後每隔50步輸出err,如果err不斷減小,說明神經網路在學到東西,因為預測值與真實值誤差在不斷減小。

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

class Layer(object):
    def __init__(self, inputs, in_size, out_size, activation_function=None):
        #權重: 平均值為0 方差為1 行數為in_size  列數為out_size
        self.W = theano.shared(np.random.normal(0,1,(in_size,out_size)))
        #bias
        self.b = theano.shared(np.zeros((out_size,) ) + 0.1)
        #乘法加bias
        self.Wx_plus_b = T.dot(inputs, self.W) + self.b #dot乘法
        #激勵函式
        self.activation_function = activation_function

        #預設為None,否則進行啟用
        if activation_function is None: 
            self.outputs = self.Wx_plus_b
        else: 
            self.outputs = self.activation_function(self.Wx_plus_b)

            
#迴歸神經網路 Regression
            
#1.製造虛擬資料
import matplotlib.pyplot as plt
#Make up some fake data
x_data = np.linspace(-1,1,300)[:, np.newaxis] #300個點進行訓練
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise   #y = x^2 - 0.5
#一元二次散點圖
plt.scatter(x_data, y_data)
plt.show()

#2.定義輸入和神經元
#determine the inputs dytpe
x = T.dmatrix('x')  #d代表64位float型別
y = T.dmatrix('y')
#add layers
L1 = Layer(x, 1, 10, T.nnet.relu) 
L2 = Layer(L1.outputs, 10, 1, None)

#3.計算誤差與梯度下降更新
#誤差為預測值與真實值差別
cost = T.mean(T.square(L2.outputs - y)) #mean()求平均誤差
#compute the gradients
#梯度下降,讓預測值更接近真實值,誤差越大,降低趨勢越大
gW1, gb1, gW2, gb2 = T.grad(cost, [L1.W, L1.b, L2.W, L2.b]) #權重和bias
#apply gradient descent
#學習效率: 神經網路中learning_rate通常小於1的數字,0.05保證神經網路學習比較精細
learning_rate = 0.05

#更新四個神經網路的引數
train = theano.function(
    inputs = [x,y],
    outputs = cost,
    updates = [(L1.W, L1.W-learning_rate*gW1),
               (L1.b, L1.b-learning_rate*gb1),
               (L2.W, L2.W-learning_rate*gW2),
               (L2.b, L2.b-learning_rate*gb2)
               ] 
    )
#(L1.W, L1.W-learnging_rate*gW1)
#(原始的權重-學習的效率*下降的幅度)更新為L1.W

#4.預測結果
#訓練時會給y求cost, 而預測輸入只給出x用來做預測
predict = theano.function(inputs=[x],  outputs=L2.outputs)

for i in range(1000):
    #training 把x_data和y_data放到函式x、y中
    err = train(x_data, y_data) #誤差

    #每隔50步輸出err, 如果err不斷減小說明神經網路在學到東西, 因為預測值與真實值誤差在不斷減小
    if i % 50 == 0: 
        print(err)

最後輸出誤差結果,可以看到在不斷減小,通過不斷更新權重和bias,神經網路在不斷學習。

2.079139917311914
0.019342171772016286
0.010080951605219858
0.007202397774306516
0.005702041299886045
0.004946926023254156
0.004565940080184372
0.0043433009094413985
0.00421325480276665
0.0041214880336559725
0.004046461715568916
0.003989685842213987
0.003934933552824453
0.003886586291155118
0.003843283475886867
0.0038068442317786316
0.0037721487639369986
0.0037432478192238835
0.003712756532212612
0.00368813308403329



三. 迴歸神經網路視覺化

最後補充神經網路不斷學習的擬合圖形,從最早不合理的圖形到後面基本擬合,同時cost誤差也在不斷減小,說明神經網路的真實值和預測值在不斷更新接近,神經網路正常執行。結果如下:


圖2 第一次擬合結果


圖3 第二次擬合結果


圖4 最後一次擬合結果

完整程式碼及註釋如下所示:

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

class Layer(object):
    def __init__(self, inputs, in_size, out_size, activation_function=None):
        #權重: 平均值為0 方差為1 行數為in_size  列數為out_size
        self.W = theano.shared(np.random.normal(0,1,(in_size,out_size)))
        #bias
        self.b = theano.shared(np.zeros((out_size,) ) + 0.1)
        #乘法加bias
        self.Wx_plus_b = T.dot(inputs, self.W) + self.b #dot乘法
        #激勵函式
        self.activation_function = activation_function

        #預設為None,否則進行啟用
        if activation_function is None: 
            self.outputs = self.Wx_plus_b
        else: 
            self.outputs = self.activation_function(self.Wx_plus_b)

            
#迴歸神經網路 Regression
            
#1.製造虛擬資料
import matplotlib.pyplot as plt
#Make up some fake data
x_data = np.linspace(-1,1,300)[:, np.newaxis] #300個點進行訓練
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise   #y = x^2 - 0.5
#一元二次散點圖
plt.scatter(x_data, y_data)
plt.show()

#2.定義輸入和神經元
#determine the inputs dytpe
x = T.dmatrix('x')  #d代表64位float型別
y = T.dmatrix('y')
#add layers
L1 = Layer(x, 1, 10, T.nnet.relu) 
L2 = Layer(L1.outputs, 10, 1, None)

#3.計算誤差與梯度下降更新
#誤差為預測值與真實值差別
cost = T.mean(T.square(L2.outputs - y)) #mean()求平均誤差
#compute the gradients
#梯度下降,讓預測值更接近真實值,誤差越大,降低趨勢越大
gW1, gb1, gW2, gb2 = T.grad(cost, [L1.W, L1.b, L2.W, L2.b]) #權重和bias
#apply gradient descent
#學習效率: 神經網路中learning_rate通常小於1的數字,0.05保證神經網路學習比較精細
learning_rate = 0.05

#更新四個神經網路的引數
train = theano.function(
    inputs = [x,y],
    outputs = cost,
    updates = [(L1.W, L1.W-learning_rate*gW1),
               (L1.b, L1.b-learning_rate*gb1),
               (L2.W, L2.W-learning_rate*gW2),
               (L2.b, L2.b-learning_rate*gb2)
               ] 
    )
#(L1.W, L1.W-learnging_rate*gW1)
#(原始的權重-學習的效率*下降的幅度)更新為L1.W

#4.預測結果
#訓練時會給y求cost, 而預測輸入只給出x用來做預測
predict = theano.function(inputs=[x],  outputs=L2.outputs)


#視覺化分析

#plot the fake data
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data,y_data) #散點圖效果        

#輸入紅線並且連續不斷更新
plt.ion()
plt.show() #引數block=True: 只顯示這張圖,關掉圖後才執行後面程式

#每隔50步輸出err並繪製擬合曲線
#cost值不斷減小說明預測值與真實值誤差在不斷減小,擬合直線越來越接近
for i in range(1000):
    #誤差: training 把x_data和y_data放到函式x、y中
    err = train(x_data, y_data)
    pre = predict(x_data)

    #to visualize the result and improvement
    #檢視神經網路結果和擬合提升過程
    if i % 50 == 0: 

        #消除紅線, 否則每次的紅線繪製在一起
        #因為第一步沒有紅線, 故使用try忽略第一步
        try:
            ax.lines.remove(lines[0])
        except Exception:
            pass
        
        predicted_value = predict(x_data)
        #plot the prediction
        lines = ax.plot(x_data, predicted_value, 'r-', lw=5) #x和預測y lw線寬度
        plt.pause(1) #暫定1秒

        #輸出誤差
        print(err)
        #print(pre)

基礎性文章,希望對您有所幫助,推薦大家閱讀莫煩大神的學習視訊,也建議大家一步步跟著學習,同時文章中存在錯誤或不足之處,還請海涵~
(By:Eastmount 2018-05-21 下午4點
  http://blog.csdn.net/eastmount/ )



相關文章