1. 程式人生 > >深度學習之TensorFlow 第三章基本開發步驟--以邏輯迴歸擬合二維資料為例

深度學習之TensorFlow 第三章基本開發步驟--以邏輯迴歸擬合二維資料為例

深度學習有四個步驟:

準備資料  搭建模型   迭代訓練   使用模型 

import tensorflow as tf
import numpy as np  #陣列
import matplotlib.pyplot as plt # matplotlib.pyplot 2D繪相簿 類似MATLAB的一種繪圖框架


plotdata = { "batchsize":[], "loss":[] }    #存放批次值和損失值
def moving_average(a, w=10):           
    if len(a) < w: 
        return a[:]    
    return [val if idx < w else sum(a[(idx-w):idx])/w for idx, val in enumerate(a)]


#生成模擬資料
train_X = np.linspace(-1, 1, 100) #train_X = np.linspace(-1, 1, 100) #生成-1~1之間的100個數作為x。
train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.3    #(a屬於[-1,1]之間的隨機數)

train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.3 # y=2x,但是加入了噪聲
#顯示模擬資料點
plt.plot(train_X, train_Y, 'ro', label='Original data')   #‘ro’代表紅色實心圈標記
plt.legend()  #顯示圖例label='Original data'
plt.show()


# 建立模型
# 佔位符
X = tf.placeholder("float")
Y = tf.placeholder("float")  #X代表輸入,Y代表對應的真實值,都是佔位符(佔住一個固定的位置等著再往裡面新增內容的符號)
# 模型引數
W = tf.Variable(tf.random_normal([1]), name="weight")
b = tf.Variable(tf.zeros([1]), name="bias")  #W和b是引數,W被初始化為[-1,1]的隨機數,形狀為一維的數字,b的初始化為0,形狀也是一維。

# 前向結構
z = tf.multiply(X, W)+ b

#反向優化
cost =tf.reduce_mean( tf.square(Y - z))
learning_rate = 0.01  #學習率代表調整引數的速度。這個值一般小於1。值越大,代表調整的速度越大,但不精確。
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) #GradientDescentOptimizer是封裝好的梯度下降演算法。

# 初始化變數
init = tf.global_variables_initializer()
# 訓練引數
training_epochs = 20  #迭代次數
display_step = 2

# 啟動session
with tf.Session() as sess:
    sess.run(init)

    # Fit all training data
    for epoch in range(training_epochs):
        for (x, y) in zip(train_X, train_Y):
            sess.run(optimizer, feed_dict={X: x, Y: y})   #外層放迴圈次數
通過sess.run來進行網路節點的運算,通過feed機制將真實資料灌到佔位符對應的位置(feed_dict={X: train_X, Y:train_Y})同時沒執行一次都會將網路結構中的節點打印出來

        #顯示訓練中的詳細資訊
        if epoch % display_step == 0:
            loss = sess.run(cost, feed_dict={X: train_X, Y:train_Y})
            print ("Epoch:", epoch+1, "cost=", loss,"W=", sess.run(W), "b=", sess.run(b))
            if not (loss == "NA" ):   #是個安全檢查,保證loss值有效才會將其用圖示顯示出來
                plotdata["batchsize"].append(epoch)
                plotdata["loss"].append(loss)

    print (" Finished!")
    print ("cost=", sess.run(cost, feed_dict={X: train_X, Y: train_Y}), "W=", sess.run(W), "b=", sess.run(b))
    #print ("cost:",cost.eval({X: train_X, Y: train_Y}))

    #圖形顯示
    plt.plot(train_X, train_Y, 'ro', label='Original data')
    plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label='Fitted line')
    plt.legend()
    plt.show()
    
    plotdata["avgloss"] = moving_average(plotdata["loss"])
    plt.figure(1)  #plt.figure(1)是新建一個名叫 Figure1的畫圖視窗
    plt.subplot(211)   #第一個畫板的第一個子圖
    plt.plot(plotdata["batchsize"], plotdata["avgloss"], 'b--')  #plt.plot(x,c)是在畫圖窗口裡具體繪製橫軸為x 縱軸為c的曲線     ‘b--’為藍色破折線

    plt.xlabel('Minibatch number')
    plt.ylabel('Loss')
    plt.title('Minibatch run vs. Training loss')
     
    plt.show()

    print ("x=0.2,z=", sess.run(z, feed_dict={X: 0.2}))

學習速率對於梯度下降演算法,這應該是一個最重要的超引數。如圖所示,如果學習速率設定得非常大,那麼訓練可能不會收斂,就直接發散了;如果設定的比較小,雖然可以收斂,但是訓練時間可能無法接受;如果設定的稍微高一些,訓練速度會很快,但是當接近最優點會發生震盪,甚至無法穩定。不同學習速率的選擇影響可能非常大。 理想的學習速率是:剛開始設定較大,有很快的收斂速度,然後慢慢衰減,保證穩定到達最優點。

                                      

下面記錄一下各種函式的作用,有助於學習記憶python庫和函式:

1.首先是linspace函式:numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) 

返回(start,stop)間的num個數,endpoint為真sample必然有終點,為否必然沒有終點,retstep表示一定步長,最後返回(sample,step)

2.np.random.randn : numpy.random.rand(d0, d1, ..., dn)

隨機產生維度為(d0,d1...,dn)的隨機數,從標準正態分佈中產生。

  但random.rand(d0,d1...,dn)產生數值取值範圍是[0,1)

3.tf.placeholder : tf.placeholder(dtype,shape = None , name = None)

佔位數,可以理解為變數,在需要的時候才去賦值

dtype 表示資料型別,例如tf.float32,tf.float64,shape表示陣列形狀,shape = None 表示一維數,還可以shape  =[3,4],shape = [None,4]表示行未定。返回Tensor型別。

4.tf.Variable.int()

tf.Variable.init(initial_value, trainable=True, collections=None, validate_shape=True, name=None)

  引數表引用相關資料:

initial_value

所有可以轉換為Tensor的型別

變數的初始值

trainable

bool

如果為True,會把它加入到GraphKeys.TRAINABLE_VARIABLES,才能對它使用Optimizer

collections

list

指定該圖變數的型別、預設為[GraphKeys.GLOBAL_VARIABLES]

validate_shape

bool

如果為False,則不進行型別和維度檢查

name

string

變數的名稱,如果沒有指定則系統會自動分配一個唯一的值

5.tf.random_normal() : tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)

程式碼中僅用到shape=[1],表示一維數

6.tf.reduce_mean(input_tensor, reduction_indices=None, keep_dims=False, name=None) 求平均值

input_tensor:待求值的tensor。

reduction_indices:在哪一維上求解。

7.tf.train.GrandientDescentOptimizer(learning_rate)

產生一個規定學習率的優化器:optmizier = tf.train.GrandientDescentOptimizer(learning_rate = 0.01)

  計算梯度並且直接作用於變數上:optimizer.minimize(cost , var_list = <list of variables>)

optimizer.run()

  計算出梯度:gradients = optimizer.compute_gradients(loss , <list of variables>)

  然後就可以根據自己的需要處理梯度了。

8.tf.global_variables_initializer()初始化所有Tensor變數的狀態

init = tf.global_variables_initializer()

with tf.Session() as sess:

sess.run(init)

9.def moving_average(a, w=10):    

if len(a) < w:      

  return a[:]        

return [val if idx < w else sum(a[(idx-w):idx])/w for idx, val in enumerate(a)]

滑動平均模型 用途:用於控制變數的更新幅度,使得模型在訓練初期引數更新較快,在接近最優值處引數更新較慢,幅度較小

方式:主要通過不斷更新衰減率來控制變數的更新幅度.

在訓練神經網路時,不斷保持和更新每個引數的滑動平均值,在驗證和測試時,引數的值使用其滑動平均值能有效提高神經網路的準確率。

第一個返回值是如果a向量的長度小於w的值,就輸出向量a中的所有值。

第二個返回值是如果向量a的長度大於w值,將索引小於長度w的值直接輸出,將索引大於w值的按照sum(a[(idx-w):idx])/w的方式進行計算輸出。

在python中enumerate的用法多用於在for迴圈中得到計數,

enumerate引數為可遍歷的變數,如 字串,列表等; 返回值為enumerate類。

舉個例子a=[a,b,c,d]

For idx,val in enumerate(a)   #idx為向量a的索引即下標

[0 a]    [1 b]    [2 c]    [3 d]

在python中enumerate的用法多用於在for迴圈中得到計數,

enumerate引數為可遍歷的變數,如 字串,列表等; 返回值為enumerate類。

tensorflow開發的基本步驟

1.定義輸入節點的方法 2.定義學習引數的變數 3.定義運算 4.優化函式,優化目標 5.初始化所有變數 6.迭代更新引數到最優解 7.測試模型8. 使用模型

模型內部的資料流向

1 正向 :資料從輸入開始,依次進行各節點定義的運算,一直運算到輸出,是模型最基本的資料流向。它直觀地表現了網路模型的結構,在模型的訓練、測試、使用場景中都會用到。這部分是必須要掌握的。

2 反向 :只有在訓練場景下會用到。這裡使用了一個叫做反向鏈式求導的方法,即先從正向的最後一個節點開始,計算此時結果值與真實值的誤差,這樣會形成一個用學習引數表示誤差的方程,然後對方程中的每個引數求導,得到其梯度修正值,同時反推出上一層的誤差,這樣就將該層節點的誤差按照正向的相反方向傳到上一層,並接著計算上一層的修正值,如此反覆下去一步一步地進行轉播,直到傳到正向的第一個節點。 這部分原理TensorFlow已經實現好了,簡單理解即可,應該把重點放在使用什麼方法來計算誤差,使用哪些梯度下降的優化方法,如何調節梯度下降中的引數(如學習率)問題上。

一個標準的模型結構分為輸入、中間節點、輸出三大部分,而如何讓這三部分連通起來學習規則並可進行計算,則是框架TensorFlow所做的事情。

TensorFlow將中間節點及節點間的運算關係(OPS)定義在自己內部的一個“圖”上,全通過一個“會話(session)”進行圖中OPS的具體運算。

可以這樣理解: “圖”是靜態的,無論做任何加、減、乘、除,它們只是將關係搭建在一起,不會有任何計算。 “會話”是動態的,只有啟動會話後才會將資料流向圖中,並按照圖中的關係運算。並將最終的結果從圖中流出。

TensorFlow用這種方式分離了計算的定義和執行,“圖”類似施工圖(blueprint),而會話更像施工地點。

構建一個完整的圖一般需要定義3種變數。 輸入節點:即網路的入口。 用於訓練的模型引數(也叫學習引數):是連線各個節點的路徑。 模型中的節點(OP):最複雜的就是OP。OP可以用來代表模型中的中間節點,也可以代表最終的輸出節點,是網路中的真正結構。