1. 程式人生 > >Tensorflow筆記之搭建神經網路NN

Tensorflow筆記之搭建神經網路NN

目錄

一、基本概念:

1、基於Tensorflow的NN:   

2、張量:

3、資料型別:

4、計算圖:

5、會話(Session):

二、神經網路的引數

1、神經網路的引數:

2、神經網路的搭建

3、前向傳播(以全連線網路為例子)

4、反向傳播:目的就是優化模型引數

三、搭建神經網路的8股

四、實戰演練

1.匯入模組,生成資料集;

2.定義神經網路的輸入,引數和輸出,定義前向傳播過程。

3. 定義損失函式以及反向傳播演算法

4. 生成會話,訓練STEPS輪


 

一、基本概念:

1、基於Tensorflow的NN:   

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

2、張量:

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

1. 0階張量稱作標量,表示一個單獨的數;eg:  S=123

2. 1階張量稱作向量,表示一個一維陣列; eg: V=[1,2,3]

3. 2階張量稱作矩陣,表示一個二維陣列,它表示可以有i行j列個元素,每個元素可以用行號和列號共同索引得到;

    eg:  m=[[1,2,3],[4,5,6],[7,8,9]]

注意點:判斷張量是幾階的,就通過張量右邊的方括號數,0個事0階,n個事n階,張量可以表示0階到n階陣列(列表)

              eg:t=[[[...]]]為三階

3、資料型別:

在tensorflow的資料型別有tf.float32,tf.int32等等。

eg:我們實現tensorflow的加法:

import tensorflow as tf
a=tf.constant([1.0,2.0])
b=tf.constant([3.0,4.0])
result=a+b
print result

#輸入結果
(tf1.5) [email protected]:~/tf$ python zhang.py 
Tensor("add:0", shape=(2,), dtype=float32)
#意思為result是一個名稱為add:0的張量,
shape(2,)表示一維陣列的長度為2,dtpye=float32表示資料型別為#浮點型。

4、計算圖:

搭建神經網路的計算過程,是承載一個或者多個計算節點的一張圖,只搭建網路,不運算。

我們實現上述計算圖:

import tensorflow as tf
x=tf.constant([[1.0,2.0]])    #定義一個二階張量等於[[1.0,2.0]]
w=tf.constant([[3.0],[4.0]])  #定義一個二階張量
y=tf.matmul(x,w)              #實現xw矩陣的乘法
print y


#輸出結果
(tf1.5) [email protected]:~/tf$ python zhang.py 
Tensor("MatMul:0", shape=(1, 1), dtype=float32)

從這裡的顯示可以看出來:print的結果顯示y是一個張量,只搭建承載計算過程的計算圖,並沒有運算,如果我們想得到運算結果就要用到“會話Session()”了。

5、會話(Session):

執行計算圖中的節點運算

我們用with結構實現,語法如下:

with tf.Session() as sess:    #tensorflow中的類Session
    print sess.run(y)

對於剛剛所述計算圖,我們執行Session()會話可得到矩陣相乘結果:

import tensorflow as tf
x=tf.constant([[1.0,2.0]])   #定義一個二階張量等於[[1.0,2.0]]
w=tf.constant([[3.0],[4.0]]) #定義一個二階張量
y=tf.matmul(x,w)             #實現xw矩陣的乘法
print y

with tf.Session() as sess:
    print sess.run(y)        #執行會話並列印執行後的結果


#輸出結構:
(tf1.5) [email protected]:~/tf$ python zhang.py 
Tensor("MatMul:0", shape=(1, 1), dtype=float32)
[[11.]]

我們可以看到,執行Session()會話前只打印出y是個張量的提示,執行Session()會話後打印出了y的結果1.0*3.0 + 2.0*4.0 = 11.0

二、神經網路的引數

1、神經網路的引數:

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

tf.random_normal()            #生成正態分佈隨機數 
f.truncated_normal()          #生成去掉過大偏離點的正態分佈隨機數 truncate縮短
tf.random_uniform()           #生成均勻分佈隨機數 
tf.zeros                      #表示生成全0陣列
tf.ones                       #表示生成全1陣列
tf.fill                       #表示生成全定值陣列   
tf.constant                   #表示生成直接給定值的陣列
1、w=tf.Variable(tf.random_normal([2,3],stddev=2,mean=0,seed=1))
#表示生成正態分佈的隨機數,形成2行3列,標準差為2,均值為0,隨機種子是1.


2、w=tf.Variable(tf.truncated_normal([2,3],stddev=2,mean=0,seed=1))
#表示去掉偏離過大的正太分佈,也就是若果隨機出來的資料偏離平均值超過2個標準差,這個資料將重新生成。

3、t=tf.random_uniform(shape=7,minval=0,maxmal=1,dtype=tf.int32,seed=1)
#表示生成一個均勻分佈【minval,maxval)中隨機取樣,注意定義域是左閉區有開,即是包含minval,不含#maxval

4、除了生成隨機數,還可以生成常量,tf.zeros([3,2],int32)表示生成3行2列的矩陣全為0;
tf.ones([3,2],int32)表示生成3行2列全為1的矩陣,
tf.fill([3,2],6)表示生成[[6,6],[6,6],[6,6]]\
tf.constant([3,2,1])表示生成[3,2,1]

注意:①隨機種子如果去掉每次生成的隨機數將不一致。

           ②如果沒有特殊要求標準差、均值、隨機種子是可以不寫的。 

2、神經網路的搭建

當我們知道張量,計算圖,會話和引數後,我們可以討論神經網路的實現過程啦。

1、神經網路的實現過程:

1. 準備資料集,提取特徵(eg:零件的體積和重量,還包括這組特徵所對應的標籤,如零件是合格還是不合格)作為輸入餵給神經網路(NN)

2. 搭建神經網路NN結構,從輸入到輸出(先搭建計算圖,再用會話執行)

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

3. 大量特徵資料餵給神經網路NN,迭代優化NN引數

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

4. 使用訓練好的模型預測和分類。

由此可見,基於神經網路的機器學習主要分為兩個過程,即訓練過程和使用過程。  訓練過程是第一步、第二步、第三步的迴圈迭代,使用過程是第四步,一旦引數優化完成就可以固定這些引數,實現特定應用了。

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

3、前向傳播(以全連線網路為例子)

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

舉例子:

假如生成一批零件,體積為x1,重量為x2,體積和重量就是我們選擇的特徵,把他們餵給神經網路,當體積和重量這組資料走過神經網路得到一個輸出。假如輸入的特徵值是:體積為0.7   重量為0.5

由搭建的神經網路可得,隱藏層節點a11=x1* w11+x2*w21=0.14+0.15=0.29,同理算得節點a12=0.32,a13=0.38,最終計算得到輸出層Y=-0.015,這便實現了前向傳播過程。

2. 推導過程

第一層:

  • X是輸入為1*2矩陣:用x表示輸入,是一個1行2列的矩陣,表示一次輸入一組特徵,這組特徵包含了體積和重量2個元素。

  • 為待優化的引數 :

        對於第一層的w節點前面有2個節點,後面有3個節點w應該是個2行3列的矩陣,我們這樣表示:

  • 神經網路共有幾層(或當前是第幾層網路)都是指的計算層,輸入不是計算層,所以a為第一層網路,a是一個一行三列矩陣。 我們可以這樣表示:

第二層:

  • 引數要滿足前面3個節點,後面一個節點,所以是一個3行1列的矩陣,我們可以這樣表

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

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

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

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

3. 前向傳播過程的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))

喂多組資料:

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的值
# 1、用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]]})

 #輸出結果: 

(tf1.5) [email protected]:~/tf$ python tf3_1.py 
y in tf3_3.py is :
[[3.0904665]]

# 2、用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]]})

執行結果:

(tf1.5) [email protected]:~/tf$ python tf3_1.py 
y in tf3_4.py is :
[[3.0904665]
 [1.2236414]
 [1.7270732]
 [2.2305048]]

4、反向傳播:目的就是優化模型引數

反向傳播:訓練模型引數,在所有引數上用梯度下降,使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)

# momentum優化器
train_step=tf.train.MomentumOptimizer(learning_rate,momentum).minimize(loss)

# adam優化器
train_step=tf.train.AdamOptimizer(learn_rate).minimizer(loss)
  • 三種優化方法區別如下: 

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

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

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

  • 學習率​​​​​​​

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

  • 進階(省略)可以參看我之前的深入理解BP演算法。

三、搭建神經網路的8股​​​​​​​

我們最後梳理出神經網路搭建的八股,神經網路的搭建課分四步完成:準備工作、前向傳播、反向傳播和迴圈迭代。

 

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輪輸出一次損失函式,下面這個我們通過原始碼進一步理解神經網路的實現過程:

1.匯入模組,生成資料集;

#coding:utf-8
# 0匯入模組,生成模擬資料集。
import tensorflow as tf
import numpy as np
BATCH_SIZE=8     #一次喂入神經網路多少組資料,不能太大,一次吃太多容易噎到
seed=23455

#基於seed產生隨機數
rng=np.random.RandomState(seed)
#隨機數返回32行2列的矩陣,表示32組,體積和重量,作為輸入資料集。
X=rng.rand(32,2)

#從X這個32行2列的矩陣中,取出1行,判斷如果和小於1給Y賦值為1,如果和不小於1給Y賦值為0
#作為資料集的輸入標籤(正確答案)
Y=[[int(x0+x1<1)] for (x0,x1) in X] #先用for迴圈從列表中抽取1行,也就是x0和x1,再判斷x0+x1,
                                    #如果和小於1,就為真,把1賦值為y,否則把0賦值給y.
print"X:\n",X
print"Y:\n",Y

執行結果:

(tf1.5) [email protected]:~/tf$ python tf3_1.py 
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]]

2.定義神經網路的輸入,引數和輸出,定義前向傳播過程。

# 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)

3. 定義損失函式以及反向傳播演算法

# 2定義損失函式以及反向傳播演算法
loss=tf.reduce_mean(tf.square(y-y_))
train_step=tf.train.GradientDescentOptimizer(0.001).minimize(loss)
#train_step=tf.train.MomentumOptimizer(0.001).minimize(loss)
#train_step=tf.train.AdamOptimizer(0.001).minimize(loss)

4. 生成會話,訓練STEPS輪

# 3生成會話,訓練STEPS輪
with tf.Session() as sess:
    init_op=tf.global_variables_initialzer()
    sess.run(init_op)
    
    #輸出目前(沒有訓練)的引數值
    print"w1: \n",sess.run(w1)
    print"w2: \n",sess.run(w2)
    print"\n"

    #訓練模型
    STEPS=3000
    for in in range(STEPS):
        start=(i*BATCH_SIZE) % 32
        end=start+BATCH_SIZE
        sess.run(train_steps,feed_dict={x:X[start:end], y_:Y[start:end]}) #8組資料,執行優化
        if i% 500==0:
            total_loss=sess.run(loss,feed_dict={x:X,y_:Y})
            print"after %d training step(s), loss on all data is %g" %(i,total_loss) #損失

#輸出訓練後的引數取值
print"\n"
print"w1: \n",sess.run(w1)
print"w2: \n",sess.rum(w2)          

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

最後程式程式碼:

#coding:utf-8
#匯入模組,生成模擬資料集 
import tensorflow as tf 
import numpy as np
BATCH_SIZE=8			#一次喂入神經網路多少組資料,不能太大,吃多了會噎著的。
seed=23455

#基於seed產生隨機數
rng=np.random.RandomState(seed)	#為隨機數產生器的種子,裡面的數字一樣,則產生的隨機數相同。
#隨機數返回32行2列的矩陣,表示32組 體積和重量,作為資料輸入集
X=rng.rand(32,2)

#從32行2列的矩陣中,取出一行,判斷如果小於1 給Y賦值1,如果小於給Y賦值為0。
Y=[[int(x0+x1<1)] for (x0,x1) in X ]   #先用for迴圈從列表X中抽取一行,也就是x0,x1,在判斷x0,x1,如果之和小於1,就為真
                                       #會把1賦值給y,否則賦值為0
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=tf.reduce_mean(tf.square(y-y_))
train_step=tf.train.GradientDescentOptimizer(0.01).minimize(loss)


# 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"

	#訓練模型s
	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]})		##8組資料,執行優化
		if i%500==0:
			total_loss=sess.run(loss,feed_dict={x:X,y_:Y})
			print"after %d training step(s),loss on all data is %g" %(i,total_loss)	#損失
			
	#輸出訓練後的引數取值。優化後。
	print"\n"
	print"w1:\n",sess.run(w1)
	print"w2:\n",sess.run(w2)

 執行結果:

 

(tf1.5) [email protected]:~/tf$ python tf3_6.py 
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.8113182   1.4845988   0.06532937]
 [-2.4427042   0.0992484   0.5912243 ]]
w2:
[[-0.8113182 ]
 [ 1.4845988 ]
 [ 0.06532937]]


after 0 training step(s),loss on all data is 4.27092
after 500 training step(s),loss on all data is 0.384598
after 1000 training step(s),loss on all data is 0.383598
after 1500 training step(s),loss on all data is 0.383565
after 2000 training step(s),loss on all data is 0.383565
after 2500 training step(s),loss on all data is 0.383566


w1:
[[-0.67919636  0.80567193  0.094153  ]
 [-2.3313076  -0.10339051  0.5821425 ]]
w2:
[[-0.09453004]
 [ 0.7987898 ]
 [-0.04888064]]

這樣4步就可以實現神經網路啦。