1. 程式人生 > >Tensorflow學習筆記 (基礎-第一篇)------ 搭建神經網路,總結搭建八股

Tensorflow學習筆記 (基礎-第一篇)------ 搭建神經網路,總結搭建八股

---- 內容                                                                                                                    

1、基本概念

2、神經網路的引數

3、神經網路的搭建 

4、反向傳播

5、搭建神經網路的八股

一、基本概念                                                                                                              

計算機中的神經元模型:

· 龐大的神經網路是基於神經元結構的,是輸入乘以權重,再求和,再過非線性函式的過程。

· 基於TensorFlow的NN(神經網路):用張量表示資料,用計算圖搭建神經網路,用會話執行計算圖,優化線上的權重(引數),得到想要的模型。

1、什麼是張量?

張量:張量就是多維陣列(列表),用“階”表示張量的維度。

--- 0階張量稱為標量,表示一個單獨的數:

S = 123        # S 表示標量

--- 1階張量稱為向量,表示一個一維陣列:

V = [1,2,3]     # V 表示一個向量

--- 2階張量稱為矩陣,表示一個二維陣列,可以有 i 行 j 列個元素,可用行號和列號共同索引到。

m=[[1, 2], [4, 5], [7, 8]]        # m 表示一個矩陣

判斷張量是幾階的,通過張量最左邊連續的方括號數,0個為0階,n個為n階,張量可以表示0階到n階陣列(列表)。

t=[ [ [… ] ] ]        # t為3階張量
張量總結表
維數 階數 名字 例子
0-D 0 標量(scalar) s=112
1-D 1 向量(vector) v=[1,2,3]
1-D 2 矩陣(matrix) m=[[1],[2],[3]]
n-D n 張量(tensor) t=[[[[[...(n個)

2、tensorflow的資料型別有tf.float32、tf.int32等。

用tensorflow實現加法:

import tensorflow as tf      # 引入模組
a = tf.constant([1.0, 2.0])  # 定義一個張量等於[1.0,2.0], tf.sonstant()表示常量
b = tf.constant([3.0, 4.0])  # 定義一個張量等於[3.0,4.0]
result = a+b                 # 實現 a 加 b 的加法
print(result)

結果:

Tensor(“add:0”, shape=(2, ), dtype=float32)
# 意思為 result 是一個名稱為 add:0 的張量,
#       shape=(2,)表示一維陣列長度為 2,
#       dtype=float32 表示資料型別為浮點型。

3、計算圖(Graph):搭建神經網路的計算過程,是承載一個或多個計算節點的一張圖,只搭建網路,不運算。

神經網路的基本模型是神經元,神經元的基本模型其實是數學中的乘、加運算。

有如上圖簡單的計算圖:

x1、 x2 表示輸入, w1、 w2 分別是 x1 到 y 和 x2 到 y 的權重(係數), 其代表的運算為:y=x1*w1+x2*w2。

該計算圖的程式碼實現為:

import tensorflow as tf          #引入模組
x = tf.constant([[1.0, 2.0]])    #定義一個 2 階張量等於[[1.0,2.0]]
w = tf.constant([[3.0], [4.0]])  #定義一個 2 階張量等於[[3.0],[4.0]]
y = tf.matmul(x, w)              #實現 xw 矩陣乘法
print(y)                         #打印出結果
# 列印的結果
Tensor(“matmul:0”, shape(1,1), dtype=float32)

可以看出,print(y)的結果為一個張量,即只搭建承載計算過程的計算圖,並沒有進行運算,若要進行計算,則需要用到"會話Session()"了。

4、會話(Session): 執行計算圖中的節點運算。

一般我們使用with結構來實現,其語法為:

with tf.Session() as sess:
    print(sess.run(y))

對3中的計算圖,執行Session()會話的完整程式碼,以及結果:

import tensorflow as tf          # 引入模組
x = tf.constant([[1.0, 2.0]])    # 定義一個 2 階張量等於[[1.0,2.0]]
w = tf.constant([[3.0], [4.0]])  # 定義一個 2 階張量等於[[3.0],[4.0]]
y = tf.matmul(x, w)              # 實現 xw 矩陣乘法
print(y)                         #打印出結果
with tf.Session() as sess:
    print(sess.run(y))           #執行會話並打印出執行後的結果
# 列印結果
Tensor(“matmul:0”, shape(1,1), dtype=float32)    # Session前為張量
[[11.]]                                          # 會話後得到結果

可以看到,執行 Session()會話前只打印出 y 是個張量的提示,執行 Session()會話後打印出了y的結果

1.0*3.0 + 2.0*4.0 = 11.0。

二、神經網路的引數                                                                                                       

· 神經網路的引數: 是指神經元線上的權重 w, 用變量表示, 一般會先隨機生成這些引數。生成引數的方法是讓 w 等於 tf.Variable,把生成的方式寫在括號裡。

神經網路中常用的生成隨機數/陣列的函式有:

tf.random_normal()      # 生成正態分佈隨機數
tf.truncated_normal()   # 生成去掉過大偏離點的正態分佈隨機數
tf.random_uniform()     # 生成均勻分佈隨機數
tf.zeros()              # 表示生成全 0 陣列
tf.ones()               # 表示生成全 1 陣列
tf.fill()               # 表示生成全定值陣列
tf.constant()           # 表示生成直接給定值的陣列

請看下面的例子:

# 生成正態分佈隨機數,形狀兩行三列, 標準差是 2, 均值是 0, 隨機種子是 1
w=tf.Variable(tf.random_normal([2,3],stddev=2, mean=0, seed=1))
# 去掉偏離過大的正態分佈, 也就是如果隨機出來的資料偏離平均值超過兩個標準差,這個資料將重新生成
w=tf.Variable(tf.Truncated_normal([2,3],stddev=2, mean=0, seed=1))
# 從一個均勻分佈[minval maxval)中隨機取樣,注意定義域是左閉右開,即包含 minval,不包含 maxval
w=random_uniform(shape=7,minval=0,maxval=1,dtype=tf.int32, seed=1)
# 除了生成隨機數, 還可以生成常量

tf.zeros([3,2],int32)  # 生成[[0,0],[0,0],[0,0]]
tf.ones([3,2],int32)   # 表示生成[[1,1],[1,1],[1,1]
tf.fill([3,2],6)       # 表示生成[[6,6],[6,6],[6,6]]
tf.constant([3,2,1])   # 表示生成[3,2,1]

注意: ①隨機種子如果去掉每次生成的隨機數將不一致。②如果沒有特殊要求標準差、 均值、 隨機種子是可以不寫的。

三、神經網路的搭建                                                                                                  

經過上面的學習,明白了張量、計算圖、會話和引數後,終於可以開始神經網路的實現過程了。

1、神經網路的實現過程

· (1) 準備資料集,提取特徵,作為輸入喂入給神經網路(Neural Network, NN)

· (2) 搭建NN結構,從輸入到輸出(先搭建計算圖,再用會話Session執行)

(NN前向傳播演算法 ==>  計算輸出)

· (3) 大量特徵資料餵給NN,迭代優化NN引數

(NN反向傳播演算法 ==> 優化引數,訓練模型)

· (4) 使用訓練好的模型預測和分類

由此可見 ,基於神經網路的機器學習主要分為兩個過程,即訓練練過程和使用過程。訓練過程是(1)到(3)步的迴圈迭代;使用過程是第(4)步,一旦 引數的優化完成就可以把這些引數記錄固定下來,實現特定的使用。

在很多的實際應用中,會先使用現有的成熟網路結構,喂入新的資料,訓練相應的模型,判斷是否能對喂入的從未見過的新資料作出正確響應,在適當更改網路結構,反覆迭代,讓機器自動訓練引數找出最優結構和引數,從而固定專用模型。

2、前向傳播

· 前向傳播就是搭建模型的計算過程, 讓模型具有推理能力, 可以針對一組輸入給出相應的輸出。

請看下面例子:

假如生產一批零件, 體積為 x1, 重量為 x2, 體積和重量就是我們選擇的特徵,把它們喂入神經網路, 當體積和重量這組資料走過神經網路後會得到一個輸出。

假如輸入的特徵值是:體積 0.7 重量 0.5。
 

 有如上搭建的神經網路可得,隱藏層節點 a11=x1*w11+x2*w21=0.7*0.2+0.5*0.3=0.29,同理可得 a12=0.32,a13=0.38,最終計算的輸出層 y=-0.015,而該過程就是實現前向傳播的課程。

其推導過程:

  • 第一層:

X 是輸入為1x2矩陣

用x表示輸入,是一個1行2列的矩陣,表示一次輸入一族特徵,包含了體積和體重兩個元素。

為待優化的引數

對於第一層的w前面有兩個節點,後面後三個節點w應該是兩行三列的矩陣:

神經網路共有幾層(或當前是第幾層網路)都是指的計算層, 輸入不是計算層,

所以a為第一層,這樣表示:

  • 第二層

 引數要滿足前面三個節點, 後面一個節點, 所以 W(2) 是三行一列矩陣。

 把每層輸入乘以線上的權重 w,這樣用矩陣乘法可以計算出輸出 y 了。

a = tf.matmul(X,W1)    # 得到第一層 a
y = tf.matmul(a,W2)    # 得到第二層 y

由於需要計算結果, 就要用 with 結構實現, 所有變數初始化過程、 計算過程都要 放 到 sess.run 函 數 中 。 對 於 變 量 初 始 化 , 我 們 在 sess.run 中 寫 入tf.global_variables_initializer 實現對所有變數初始化, 也就是賦初值。 對於計算圖中的運算, 我們直接把運算節點填入 sess.run 即可, 比如要計算輸出y, 直接寫 sess.run(y) 即可。
這裡必須注意的是,對於變數,必須要執行sess.run來初始化。

在實際應用中, 我們可以一次喂入一組或多組輸入, 讓神經網路計算輸出 y, 可以先用 tf.placeholder 給輸入佔位。 如果一次喂一組資料 shape 的第一維位置寫 1, 第二維位置看有幾個輸入特徵; 如果一次想喂多組資料, shape 的第一維位置可以寫 None 表示先空著, 第二維位置寫有幾個輸入特徵。 這樣在 feed_dict中可以喂入若干組體積重量了。

前向傳播過程的 tensorflow 描述:

變數初始化、計算圖節點運算都要用會話(with 結構)實現

with tf.Session() as sess:
    sess.run()

變數初始化:在 sess.run 函式中用 tf.global_variables_initializer()彙總所有待優化變數。

init_op = tf.global_variables_initializer()
sess.run(init_op)

計算圖節點運算:在 sess.run 函式中寫入待運算的節點

sess.run(y)

用 tf.placeholder 佔位,在 sess.run 函式中用 feed_dict 喂資料:

  • 喂一組資料:
x = tf.placeholder(tf.float32, shape=(1, 2))
sess.run(y, feed_dict={x: [[0.5,0.6]]})
  • 喂多組資料:
x = tf.placeholder(tf.float32, shape=(None, 2))
sess.run(y, feed_dict={x: [[0.1,0.2],[0.2,0.3],[0.3,0.4],[0.4,0.5]]})

 #這是一個實現神經網路前向傳播過程, 網路可以自動推理出輸出 y 的值。

# ①用 placeholder 實現輸入定義(sess.run 中喂入一組資料)的情況
#第一組喂體積 0.7、 重量 0.5

#coding:utf-8
import tensorflow as tf

#定義輸入和引數
x=tf.placeholder(tf.float32,shape=(1,2))
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

#定義前向傳播過程
a=tf.matmul(x,w1)
y=tf.matmul(a,w2)

#用會話計算結果
with tf.Session() as sess:
	init_op=tf.global_variables_initializer()
	sess.run(init_op)
	print(” y in tf3_3.py is:\n”,sess.run(y,feed_dict={x:[[0.7,0.5]]}))
# ②用 placeholder 實現輸入定義(sess.run 中喂入多組資料)的情況
# 第一組喂體積 0.7、重量 0.5, 第二組喂體積 0.2、重量 0.3,
# 第三組喂體積 0.3 、重量 0.4,第四組喂體積 0.4、重量 0.5.
# coding:utf-8

import tensorflow as tf

#定義輸入和引數
x=tf.placeholder(tf.float32,shape=(None,2))
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

#定義前向傳播過程
a=tf.matmul(x,w1)
y=tf.matmul(a,w2)

#用會話計算結果
with tf.Session() as sess:
	init_op=tf.global_variables_initializer()
	sess.run(init_op)
	print(”y in tf3_4.py is:\n”,sess.run(y,feed_dict={x:[[0.7,0.5],[0.2,0.3],[0.3,0.4], [0.4,0.5]]}))

四、反向傳播        

  • 反向傳播:訓練模型引數,在所有引數上用梯度下降,使 NN 模型在訓練資料上的損失函式最小。
  • 損失函式(loss): 計算得到的預測值 y 與已知答案 y_的差距。
    損失函式的計算有很多方法,均方誤差 MSE 是比較常用的方法之一。
  • 均方誤差 MSE: 求前向傳播計算結果與已知答案之差的平方再求平均
# 用 tensorflow 函式表示為:
loss_mse = tf.reduce_mean(tf.square(y_ - y))
  •  反向傳播訓練方法: 以減小 loss 值為優化目標,有梯度下降、 momentum 優化器、 adam 優化器等優化方法。
#這三種優化方法用 tensorflow 的函式可以表示為:

train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
train_step=tf.train.MomentumOptimizer(learning_rate, momentum).minimize(loss)
train_step=tf.train.AdamOptimizer(learning_rate).minimize(loss)

三種優化方法區別如下:

  1. tf.train.GradientDescentOptimizer()使用隨機梯度下降演算法,使引數沿著梯度的反方向,即總損失減小的方向移動,實現更新引數。

 引數更新公式:

 2、tf.train.MomentumOptimizer()在更新引數時,利用了超引數,引數更新公式是:

3、tf.train.AdamOptimizer()是利用自適應學習率的優化演算法, Adam 演算法和隨機梯度下降演算法不同。隨機梯度下降演算法保持單一的學習率更新所有的引數,學習率在訓練過程中並不會改變。而 Adam 演算法通過計算梯度的一階矩估計和二階矩估計而為不同的引數設計獨立的自適應性學習率。

  • 學習率: 決定每次引數更新的幅度。

優化器中都需要一個叫做學習率的引數, 使用時, 如果學習率選擇過大會出現震盪不收斂的情況,如果學習率選擇過小, 會出現收斂速度慢的情況。 可以選個比較小的值填入, 比如 0.01、 0.001。

五、搭建神經網路的八股

神經網路的搭建課分四步完成:準備工作、前向傳播、反向傳播和迴圈迭代。

  • 0.匯入模組,生成模擬資料集;
  1. import
  2. 常量定義
  3. 生成資料集
  • 1.前向傳播:定義輸入、引數和輸出
  • 2. 反向傳播:定義損失函式、反向傳播方法
  1. loss= (損失)
  2. train_step=(次數)
  • 3. 生成會話,訓練 STEPS 輪
with tf.session() as sess:
    Init_op=tf. global_variables_initializer()
    sess_run(init_op)
    STEPS=3000
    for i in range(STEPS):
    start=
    end=
    sess.run(train_step, feed_dict:)

看一個簡單的完整例子:

隨機產生 32 組生產出的零件的體積和重量,訓練 3000 輪,每 500 輪輸出一次損失函式。下面我們通過原始碼進一步理解神經網路的實現過程:

#coding:utf-8
#0匯入模組,生成模擬資料集。
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8
SEED = 23455

#基於seed產生隨機數
rdm = np.random.RandomState(SEED)
#隨機數返回32行2列的矩陣 表示32組 體積和重量 作為輸入資料集
X = rdm.rand(32,2)
#從X這個32行2列的矩陣中 取出一行 判斷如果和小於1 給Y賦值1 如果和不小於1 給Y賦值0 
#作為輸入資料集的標籤(正確答案) 
Y_ = [[int(x0 + x1 < 1)] for (x0, x1) in X]
print("X:\n",X)
print("Y_:\n",Y_)

#1定義神經網路的輸入、引數和輸出,定義前向傳播過程。
x = tf.placeholder(tf.float32, shape=(None, 2))
y_= tf.placeholder(tf.float32, shape=(None, 1))

w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))
w2= tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))

a = tf.matmul(x, w1)
y = tf.matmul(a, w2)

#2定義損失函式及反向傳播方法。
loss_mse = tf.reduce_mean(tf.square(y-y_)) 
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss_mse)
#train_step = tf.train.MomentumOptimizer(0.001,0.9).minimize(loss_mse)
#train_step = tf.train.AdamOptimizer(0.001).minimize(loss_mse)

#3生成會話,訓練STEPS輪
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    # 輸出目前(未經訓練)的引數取值。
    print("w1:\n", sess.run(w1))
    print("w2:\n", sess.run(w2))
    print("\n")
    
    # 訓練模型。
    STEPS = 3000
    for i in range(STEPS):
        start = (i*BATCH_SIZE) % 32
        end = start + BATCH_SIZE
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y_[start:end]})
        if i % 500 == 0:
            total_loss = sess.run(loss_mse, feed_dict={x: X, y_: Y_})
            print("After %d training step(s), loss_mse on all data is %g" % (i, total_loss))
    
    # 輸出訓練後的引數取值。
    print("\n")
    print("w1:\n", sess.run(w1))
    print("w2:\n", sess.run(w2))

列印結果:

X:
[[ 0.83494319  0.11482951]
 [ 0.66899751  0.46594987]
 [ 0.60181666  0.58838408]
 [ 0.31836656  0.20502072]
 [ 0.87043944  0.02679395]
 [ 0.41539811  0.43938369]
 [ 0.68635684  0.24833404]
 [ 0.97315228  0.68541849]
 [ 0.03081617  0.89479913]
 [ 0.24665715  0.28584862]
 [ 0.31375667  0.47718349]
 [ 0.56689254  0.77079148]
 [ 0.7321604   0.35828963]
 [ 0.15724842  0.94294584]
 [ 0.34933722  0.84634483]
 [ 0.50304053  0.81299619]
 [ 0.23869886  0.9895604 ]
 [ 0.4636501   0.32531094]
 [ 0.36510487  0.97365522]
 [ 0.73350238  0.83833013]
 [ 0.61810158  0.12580353]
 [ 0.59274817  0.18779828]
 [ 0.87150299  0.34679501]
 [ 0.25883219  0.50002932]
 [ 0.75690948  0.83429824]
 [ 0.29316649  0.05646578]
 [ 0.10409134  0.88235166]
 [ 0.06727785  0.57784761]
 [ 0.38492705  0.48384792]
 [ 0.69234428  0.19687348]
 [ 0.42783492  0.73416985]
 [ 0.09696069  0.04883936]]
Y_:
[[1], [0], [0], [1], [1], [1], [1], [0], [1], [1], [1], [0], [0], [0], [0], [0], [0], [1], [0], [0], [1], [1], [0], [1], [0], [1], [1], [1], [1], [1], [0], [1]]
w1:
[[-0.81131822  1.48459876  0.06532937]
 [-2.4427042   0.0992484   0.59122431]]
w2:
[[-0.81131822]
 [ 1.48459876]
 [ 0.06532937]]


After 0 training step(s), loss_mse on all data is 5.13118
After 500 training step(s), loss_mse on all data is 0.429111
After 1000 training step(s), loss_mse on all data is 0.409789
After 1500 training step(s), loss_mse on all data is 0.399923
After 2000 training step(s), loss_mse on all data is 0.394146
After 2500 training step(s), loss_mse on all data is 0.390597


w1:
[[-0.70006633  0.9136318   0.08953571]
 [-2.3402493  -0.14641267  0.58823055]]
w2:
[[-0.06024267]
 [ 0.91956186]
 [-0.0682071 ]]

由神經網路的實現結果,我們可以看出,總共訓練 3000 輪, 每輪從 X 的資料集和 Y 的標籤中抽取相對應的從 start 開始到 end 結束個特徵值和標籤, 喂入神經網路, 用 sess.run 求出 loss, 每 500 輪列印一次 loss 值。經過 3000 輪後, 我們打印出最終訓練好的引數 w1、 w2。

這樣四步就可以實現神經網路的搭建了。