NO.2:自學tensorflow之路------BP神經網絡編程

引言git

  在上一篇博客中,介紹了各類Python的第三方庫的安裝,本週將要使用Tensorflow完成第一個神經網絡,BP神經網絡的編寫。因爲以前已經介紹過了BP神經網絡的內部結構,本文將直接介紹Tensorflow編程經常使用的一些方法。算法

正文編程

神經網絡的內容數組

  通常,一個神經網絡程序包含如下幾部份內容。網絡

  1.數據表達和特徵提取。對於一個非深度學習神經網絡,主要影響其模型準確度的因素就是數據表達和特徵提取。一樣的一組數據,在歐式空間和非歐空間,就會有着不一樣的分佈。有時候換一種思考問題的思路就會使得問題變得簡單。因此選擇合適的數據表達能夠極大的下降解決問題的難度。一樣,在機器學習中,特徵的提取也不是一種簡單的事。在一些複雜問題上,要經過人工的方式設計有效的特徵集合,須要不少的時間和精力,有時甚至須要整個領域數十年的研究投入。例如,PCA獨立成分分析就是特徵提取中經常使用的手段之一。可是不少狀況下,人爲都很難提取出合適的特徵。dom

  因爲不一樣問題下,能夠提取不一樣的特徵向量,這裏將不作具體介紹。事實上深度學習解決的核心問題之一就是自動地將簡單的特徵組合成更加複雜的特徵,並使用這些組合特徵解決問題。機器學習

  2.定義神經網絡的結構。由神經網絡發展的歷史可知,不一樣結構的神經網絡在不一樣的問題下獲得的效果不一樣。所以分析問題,選擇與問題合適的神經網絡結構也一樣重要。ide

  3.訓練神經網絡的參數。使用訓練數據集訓練神經網絡。主要是利用神經網絡輸出偏差反向傳播修正神經網絡中的參數,甚至結構。反向傳播過程當中,步長選擇對神經網絡的訓練有着重要的影響,在此基礎上產生了多種訓練方法。將在後面介紹。函數

  4.使用訓練好的神經網絡預測未知數據。訓練神經網絡的目的就是對未知數據預測。學習

  具體過程能夠由以下流程圖表示:

BP神經網絡

   這裏將按照流程圖,詳細構造BP神經網絡。

  1.數據預處理

  這裏將使用自造的數據模擬實際數據,經過對自造的數據仿真,驗證BP神經網絡的擬合能力。模型將使用一個單輸入單輸出一階慣性傳遞函數模型。模型結構以下所示:

  爲了很好的激勵出模型的特性,X將用隨機數來表示。具體制造模型,例子:

  導入第三方庫,後面將再也不展現。

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

  導入完成後就須要生成輸入與輸出的數據了。因爲現實中各類數據之間的單位不一樣,直接使用時,因爲數量級的問題每每會致使神經網絡建模出現一些奇怪的問題。因此建模數據是須要歸一化的。而這裏爲了方便,將直接生成0~1的數據。例子:

#生成輸入輸出數據
input_size = 1#輸入變量個數
output_size = 1#輸出變量個數
data_size = 2000#樣本個數
k,T,x_state = 0.5,200,0#比例增益,時間常數,初始狀態

x_data = np.random.rand(data_size,input_size)#輸入數據0~1之間
y_data = np.zeros((data_size,output_size))#初始化輸出數據
t_conv = np.e**(-1/T)#零階保持器,採樣週期1s

for i in range(data_size):
    x_state = t_conv*x_state + k*(1-t_conv)*x_data[i]
    y_data[i] = x_state

  這裏使用零階保持的方法,將傳遞函數離散化後生成了共2000點的數據。這樣就完成了數據預處理。

  2.神經網絡結構

  因爲已經肯定要使用BP神經網絡爲傳遞函數建模。因此直接按照一層隱含層的BP神經網絡創建結構就能夠了。而在創建前,須要學習Tensorflow中張量的相關操做。

  首先,在Tensorflow中定義張量的方法是。例子:

a = tf.constant([1,2,3])
print(a)

  從運行結果能夠發現,Tensorflow中的張量與numpy中的向量不一樣,張量中包含着名字,維度,和類型三種屬性。張量是創建在計算圖上的,經過使用會話,就能夠計算不一樣的數據。具體計算圖將在以後Tensorflow可視化中介紹,這裏暫時就能夠理解爲一個函數。Tensorflow中還含有不一樣的隨機數常數生成函數,能夠幫助創建神經網絡中的權值和閾值。例子:

tf.random_normal()#正太分佈,可設置平均值、標準差、取值類型
tf.truncated_normal()#正態分佈,但隨機值偏離平均值2個標準差之內
tf.random_uniform()#平均分佈,可設置最小值、最大值、取值類型
tf.random_gamma()#gamma分佈,可設置形狀參數,尺度參數,取值類型

tf.zeros()#產生全0數組
tf.ones()#產生全1數組
tf.fill()#產生所有爲給定數字的數組

  特殊的,當不指導輸入數據的長度時,能夠用一個佔位來定義。例子:

a = tf.placeholder(tf.float32,[None,1])

  定義好節點之後,就須要進行計算,經常使用的計算中加減乘除與以前相同,下面將介紹一些不一樣的。例子:

a = tf.Variable(tf.ones((1,3)))
b = tf.Variable(tf.ones((3,1)))

c = tf.matmul(a,b)#向量乘法
d = tf.nn.relu(c)#激活函數ReLU
e = tf.nn.sigmoid(c)#激活函數sigmoid
f = tf.nn.tanh(c)#激活函數tanh

  依靠以上內容,就能夠創建BP神經網絡的結構。例子:

#神經網絡結構
batch_size = 50#訓練batch的大小
hide_size = 5#隱藏神經元個數

#預留每一個batch中輸入與輸出的空間
x = tf.placeholder(tf.float32,shape = (None,input_size))#None隨batch大小變化
y_pred = tf.placeholder(tf.float32,shape = (None,output_size))

w_hidden = tf.Variable(tf.random_normal([input_size,hide_size],stddev = 1,seed = 1))
b_hidden = tf.Variable(tf.zeros([1,hide_size],dtype = tf.float32))
w_output = tf.Variable(tf.random_normal([hide_size,output_size],stddev = 1,seed = 1))

#定義前向傳播過程
h = tf.nn.tanh(tf.matmul(x,w_hidden)+b_hidden)
y = tf.nn.sigmoid(tf.matmul(h,w_output))

  以後反向傳播Tensorflow能夠自動進行,咱們只須要定義損失函數和反向計算算法就能夠了。神經網絡模型的效果以及優化的目標是經過損失函數來定義的。這就是使用Tensorflow的優點。根據不一樣的用途,損失函數有着不一樣的定義方法。對於分類問題,可使用交叉熵來定義。交叉熵的計算公式以下:

 

 

  編程例子:

cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-10,1.0)))#定義值與真實值間的交叉熵

  這裏tf.clip_by_value能夠將一個張量中的數值限制在一個範圍內,避免運算錯誤。因爲交叉熵常常與softmax迴歸一塊兒使用,Tensorflow將它們進行了封裝。例子:

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(y,y_)

  與分類問題不一樣,本次例子解決的是迴歸問題。對於具體數值的預測,應該使用MSE均方偏差做爲損失函數。例子:

cross_entropy = tf.reduce_mean(tf.square(y_ - y))#定義損失函數

  而且,損失函數還能夠本身定義,這裏再也不具體詳述。

  3.訓練神經網絡

  訓練神經網絡時,要用到Tensorflow中另外一個重要的內容,會話。會話擁有Tensorflow程序運行時的全部資源,而且能夠對其進行管理。會話的打開與關閉與文件的讀取相似。例子:

#方法1
sess=tf.Session()#建立會話
sess.run()#運行會話——類比打開文件
#具體會話執行內容
sess.close#關閉會話——類比關閉文件

#方法2
with tf.Session() as sess:
    sess.run()
#經過縮進自動關閉

  在使用sess.run( )運行計算圖時,咱們能夠傳入fetches,用於取回某些操做或tensor的輸出內容。fetches能夠是list,tuple,namedtuple,dict中的任意一個。例子:

x = tf.constant([1])
y = tf.constant([2])
a = x+y

with tf.Session() as sess:
     z = sess.run(a)
     print(z)

  一樣在使用sess.run( )運行計算圖時,咱們能夠傳入feed,用於臨時替代計算圖中任意op操做的輸入張量。例子:

x = numpy.array([2])
y = numpy.array([3])

input1 = tf.placeholder(tf.int32)
input2 = tf.placeholder(tf.int32)
output = input1+input2

with tf.Session() as sess:
    print(sess.run(output, feed_dict = {input1:x, input2:y}))

   4.訓練集,測試集。

  通常狀況下須要將數據分爲2類,一部分用來訓練模型,一部分用來測試模型。這樣就完成了最簡單的BP神經網絡的創建。

做業

使用普通BP神經網絡擬合傳遞函數

#-*- coding:utf-8 -*-
#BP neural network
#Author:Kai Z

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

#生成輸入輸出數據
input_size = 1#輸入變量個數
output_size = 1#輸出變量個數
data_size = 2000#樣本個數

x_data = np.random.rand(data_size,input_size)#輸入數據0~1之間
y_data = np.zeros((data_size,output_size))#初始化輸出數據

k,T,x_state = 0.5,200,0
t_conv = np.e**(-1/T)#零階保持器,採樣週期1s

for i in range(data_size):
    x_state = t_conv*x_state + k*(1-t_conv)*x_data[i]
    y_data[i] = x_state

#神經網絡結構
batch_size = 50#訓練batch的大小
hide_size = 5#隱藏神經元個數

#預留每一個batch中輸入與輸出的空間
x = tf.placeholder(tf.float32,shape = (None,input_size))#None隨batch大小變化
y = tf.placeholder(tf.float32,shape = (None,output_size))

w_hidden = tf.Variable(tf.random_normal([input_size,hide_size],stddev = 1,seed = 1))
b_hidden = tf.Variable(tf.zeros([1,hide_size],dtype = tf.float32))
w_output = tf.Variable(tf.random_normal([hide_size,output_size],stddev = 1,seed = 1))

#定義前向傳播過程
h = tf.nn.tanh(tf.matmul(x,w_hidden)+b_hidden)
y_pred = tf.nn.sigmoid(tf.matmul(h,w_output))

#反向損失函數
learning_rate = 2e-3#學習速率
cross_entropy = tf.reduce_mean(tf.square(y_pred - y))#定義損失函數
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)#定義反向傳播優化方法

#建立會話
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)#初始化變量

    #設定訓練次數
    STEPS = 10000#訓練次數
    for i in range(STEPS):
        #選取訓練batch
        start = max((i * batch_size) % 1000,20)
        end = min(start + batch_size,1000)#取前1000點訓練

        #計算
        sess.run(train_step,feed_dict = {x:x_data[start:end],y:y_data[start:end]})

        #顯示偏差
        if i % 100 == 0:
            total_cross_entropy = sess.run(cross_entropy,feed_dict = {x:x_data[1000:1500],y:y_data[1000:1500]})#1000~1500測試
            print('訓練%d次後,偏差爲%f'%(i,total_cross_entropy))
            if total_cross_entropy <= 1e-3:
                break
    else:
        print('未達到訓練目標')
        exit()
    #保存結果
    saver = tf.train.Saver()
    file_path = 'D:/Study/Project/Hobby/Python/03 Study/02 Learn/test'
    save_path = saver.save(sess,file_path)
    predict = sess.run(y_pred,feed_dict={x:x_data})
predict = predict.ravel()#轉換爲向量
orange = y_data.ravel()
#創建時間軸
t = np.arange(2000)
plt.plot(t,predict)
plt.plot(t,orange)
plt.show()

後記

  能夠看出,普通BP神經網絡對動態傳遞函數的擬合效果並非很好。這是因爲神經網絡是靜態的,而傳遞函數是動態的。要想辨識動態系統,也得使用動態的神經網絡。如最簡單的NARX神經網絡。或者更復雜的RNN。以後將進行RNN的實現。

相關文章
相關標籤/搜索