一、神經網絡的實現過程
1、准備數據集,提取特征,作為輸入喂給神經網絡
2、搭建神經網絡結構,從輸入到輸出
3、大量特征數據喂給 NN,迭代優化 NN 參數
4、使用訓練好的模型預測和分類
二、前向傳播
前向傳播就是搭建模型的計算過程,可以針對一組輸入給出相應的輸出。
舉例:假如生產一批零件, 體積為 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, 這便實現了前向傳播過程。
再來推導圖中的代碼實現過程。
第一層:
(1)x是輸入為1*2的矩陣:用x表示輸入,是一個1行2列的矩陣,表示一次輸入一組特征,這組特征包含了體積和重量兩個元素。
(2)W前節點編號,后節點編號(層數)為待優化的參數:前面兩個節點,后面三個節點。所以w應該是個兩行三列的矩陣。表示為
注意:神經網絡共有幾層是指計算層, 輸入不算作計算層,所以 上圖中a 為第一層網絡,a 是一個一行三列矩陣。
第二層:
(1)參數要滿足前面三個節點,后面一個節點,所以W(2)是三行一列矩陣。表示為

我們把每層輸入乘以線上的權重w,這樣就可以用矩陣乘法輸出y了。
下面討論這其中的細節問題。
1、神經網絡的參數
顯然權重w是很重要的參數,我們剛開始設置w變量的時候,一般會先隨機生成這些參數,當然肯定是變量形式。
所以這里介紹一下 tf 常用的生成隨機數/數組的函數:
(1)tf.random_normal() 生成正態分布隨機數
w=tf.Variable(tf.random_normal([2,3],stddev=2, mean=0, seed=1)) # 表示生成正態分布隨機數,形狀兩行三列,標准差是2,均值是0,隨機種子是1
(2)tf.truncated_normal() 生成去掉過大偏離點的正態分布隨機數,也就是如果隨機生成的數據偏離平均值超過兩個標准差,這個數據將重新生成
w=tf.Variable(tf.Truncated_normal([2,3],stddev=2, mean=0, seed=1))
(3)tf.random_uniform() 生成均勻分布隨機數
w=tf.Variable(tf.random_uniform([2,3],minval=0,maxval=1,dtype=tf.float32,seed=1)) # 表示從一個均勻分布[minval maxval)中隨機采樣,產生的數是均勻分布的,注意定義域是左閉右開,即包含 minval,不包含 maxval。
以上這些函數,如果沒有特殊要求標准差、 均值、 隨機種子是可以不寫的。看具體使用情況。
(4)其它函數:tf.zeros 表示生成全 0 數組
tf.ones 表示生成全 1 數組
tf.fill 表示生成全定值數組
tf.constant 表示生成直接給定值的數組
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]
2、placeholder占位,輸入多組數據
不做贅述,直接在代碼里面注釋這樣的操作
細節討論完,下面就是用代碼實現前向傳播
1 # (1) 用placeholder 實現輸入定義(sess.run 中喂入一組數據)的情況,特征有體積和重量,數據為體積 0.7、重量 0.5 2 3 import tensorflow as tf 4 5 x = tf.placeholder(tf.float32,shape=(1,2)) # placeholder占位,首先要指定數據類型,然后可以指定形狀,因為我們現在只需要占一組數據,且有兩個特征值,所以shape為(1,2) 6 w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1)) # 生成權重 7 w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1)) 8 9 a = tf.matmul(x,w1) # 矩陣乘法op 10 y = tf.matmul(a,w2) 11 12 with tf.Session() as sess: 13 init = tf.global_variables_initializer() # 初始化以后就放在這里,不容易忘記 14 sess.run(init) 15 print("y is",sess.run(y,feed_dict={x:[[0.7,0.5]]})) # 以字典形式給feed_dict賦值,賦的是一個一行兩列的矩陣,注意張量的階數。這里只執行了y的op,因為執行了y也就執行了a這個op 16
運行顯示結果為:
y is: [[ 3.0904665]]
# (2) 用 placeholder 實現輸入定義(sess.run 中喂入多組數據)的情況 import tensorflow as tf #定義輸入和參數 x=tf.placeholder(tf.float32,shape=(None,2)) # 這里占位因為不知道要輸入多少組數據,但還是兩個特征,所以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 is:",sess.run(y,feed_dict={x:[[0.7,0.5], [0.2,0.3], [0.3,0.4], [0.4,0.5]]})) # 輸入數據,4行2列的矩陣
運行顯示結果為:
y is: [[ 3.0904665 ] [ 1.2236414 ] [ 1.72707319] [ 2.23050475]]
以上就是最簡單的神經網絡前向傳播過程。
三、后向傳播
反向傳播:訓練模型參數,以減小loss值為目的,使用優化方法,使得 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)
三種優化方法的區別:
![]()


學習率:決定每次參數更新的幅度。
優化器中都需要一個叫做學習率的參數,使用時,如果學習率選擇過大會出現震盪不收斂的情況(步子跨的太大),如果學習率選擇過小,會出現收斂速度慢的情況。我們可以選個比較小的值填入,比如 0.01、0.001。
Python代碼實現加上反向傳播的NN:
隨機產生 32 組生產出的零件的體積和重量,訓練 3000 輪,每 500 輪輸出一次損失函數。
1 import tensorflow as tf 2 import numpy as np 3 4 BATCH_SIZE = 8 # 一次輸入網絡的數據,稱為batch。一次不能喂太多數據 5 SEED = 23455 # 產生統一的隨機數 6 7 # 基於seed產生隨機數,這是根據隨機種子產生隨機數的一種常用方法,要熟練運用 8 rdm = np.random.RandomState(SEED) 9 # 隨機數返回32行2列的矩陣 表示32組 體積和重量 作為輸入數據集。因為這里沒用真實的數據集,所以這樣操作。 10 X = rdm.rand(32, 2) 11 # 從X這個32行2列的矩陣中 取出一行 判斷如果和小於1 給Y賦值1 如果和不小於1 給Y賦值0 (這里只是人為的定義),作為輸入數據集的標簽(正確答案) 12 Y_ = [[int(x0 + x1 < 1)] for (x0, x1) in X] 13 print("X:\n", X) 14 print("Y_:\n",Y_) 15 16 17 # 1定義神經網絡的輸入、參數和輸出,定義前向傳播過程。 18 x = tf.placeholder(tf.float32, shape=(None, 2)) 19 y_ = tf.placeholder(tf.float32, shape=(None, 1)) 20 21 w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) 22 w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) 23 24 a = tf.matmul(x, w1) 25 y = tf.matmul(a, w2) 26 27 # 2定義損失函數及反向傳播方法。 28 loss = tf.reduce_mean(tf.square(y - y_)) 29 train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss) # 三種優化方法選擇一個就可以 30 # train_step = tf.train.MomentumOptimizer(0.001,0.9).minimize(loss_mse) 31 # train_step = tf.train.AdamOptimizer(0.001).minimize(loss_mse) 32 33 # 3生成會話,訓練STEPS輪 34 with tf.Session() as sess: 35 init = tf.global_variables_initializer() 36 sess.run(init) 37 # 輸出目前(未經訓練)的參數取值。 38 print("w1:\n", sess.run(w1)) 39 print("w2:\n", sess.run(w2)) 40 print("\n") 41 42 # 訓練模型。 43 STEPS = 3000 44 for i in range(STEPS): #0-2999 45 start = (i * BATCH_SIZE) % 32 #i=0,start=0,end=8;i=1,start=8,end=16;i=2,start=16,end=24;i=3,start=24,end=32;i=4,start=0,end=8。也就是說每次訓練8組數據,一共訓練3000次。 46 end = start + BATCH_SIZE 47 sess.run(train_step, feed_dict={x: X[start:end], y_: Y_[start:end]}) 48 if i % 500 == 0: 49 total_loss = sess.run(loss, feed_dict={x: X, y_: Y_}) 50 print("After %d training step(s), loss on all data is %g"%(i,total_loss)) 51 52 # 輸出訓練后的參數取值。 53 print("\n") 54 print("w1:\n", sess.run(w1)) 55 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。
針對上面的代碼,做出如下思考。首先最終的目的是使得loss值減小,那么:
1、如果增大訓練次數,loss會不會繼續減小?如果減小,會不會一直在減小?
增大了訓練次數后,發現隨着次數增加,loss值確實會慢慢減小,但是減小的幅度越來越小,直至訓練了16500次之后,loss值保持不變。
after 3000 training step(s) ,loss on all data is 0.388336 after 3500 training step(s) ,loss on all data is 0.386855 after 4000 training step(s) ,loss on all data is 0.385863 after 4500 training step(s) ,loss on all data is 0.385186 after 5000 training step(s) ,loss on all data is 0.384719 after 5500 training step(s) ,loss on all data is 0.384391 after 6000 training step(s) ,loss on all data is 0.38416 after 6500 training step(s) ,loss on all data is 0.383995 after 7000 training step(s) ,loss on all data is 0.383877 after 7500 training step(s) ,loss on all data is 0.383791 after 8000 training step(s) ,loss on all data is 0.383729 after 8500 training step(s) ,loss on all data is 0.383684 after 9000 training step(s) ,loss on all data is 0.383652 after 9500 training step(s) ,loss on all data is 0.383628 after 10000 training step(s) ,loss on all data is 0.38361 after 10500 training step(s) ,loss on all data is 0.383597 after 11000 training step(s) ,loss on all data is 0.383587 after 11500 training step(s) ,loss on all data is 0.38358 after 12000 training step(s) ,loss on all data is 0.383575 after 12500 training step(s) ,loss on all data is 0.383571 after 13000 training step(s) ,loss on all data is 0.383568 after 13500 training step(s) ,loss on all data is 0.383566 after 14000 training step(s) ,loss on all data is 0.383565 after 14500 training step(s) ,loss on all data is 0.383564 after 15000 training step(s) ,loss on all data is 0.383563 after 15500 training step(s) ,loss on all data is 0.383562 after 16000 training step(s) ,loss on all data is 0.383562 after 16500 training step(s) ,loss on all data is 0.383561 after 17000 training step(s) ,loss on all data is 0.383561 after 17500 training step(s) ,loss on all data is 0.383561 after 18000 training step(s) ,loss on all data is 0.383561
2、既然上面的問題是這樣,那么隨機梯度下降算法的學習率對loss減小有着怎樣的影響?
我調整了學習率和訓練次數,得到這樣的規律,目前的學習率為0.001
當學習率為0.003時,5500次訓練,loss就可以下降到0.383561
當學習率為0.005時,3500次訓練,loss只能下降到0.383562
當學習率為0.007時,2500次訓練,loss只能下降到0.383563
當學習率為0.01時,2500次訓練,loss只能下降到0.383566
由此可以看出,當學習率增大時,優點是訓練次數較少,缺點是可能參數在最小值附近波動,不收斂
當學習率為0.0007時,23500次訓練,loss能下降到0.383561
當學習率為0.0003時,50000次訓練,loss才能下降到0.383563
顯然,學習率過小的缺點就是訓練次數太多
3、如果不用隨機梯度下降算法,換用其他的優化器,會產生什么樣的變化?
(1)換用Momentum優化器,可以發現,當學習率也為0.001時,2000次訓練,loss值就下降到了0.383561。
after 0 training step(s) ,loss on all data is 5.13118 after 500 training step(s) ,loss on all data is 0.384391 after 1000 training step(s) ,loss on all data is 0.383592 after 1500 training step(s) ,loss on all data is 0.383562 after 2000 training step(s) ,loss on all data is 0.383561 after 2500 training step(s) ,loss on all data is 0.383561 after 3000 training step(s) ,loss on all data is 0.383561
同樣的增加和減小學習率,得到的現象和上文分析的是一樣的。但是當學習率較大時,出現了loss值增大的現象
所以暫時可以得出這樣的結論:Momentum優化器的優點是可以快速收斂到最小值,相同的學習率,需要的訓練次數較少
(2)換用Adam優化器,可以發現,當學習率也為0.001時,3500次訓練,loss值下降到了0.383561
變化學習率,現象和Momentum差不多,也出現loss值增大的現象。
after 0 training step(s) ,loss on all data is 5.20999 after 500 training step(s) ,loss on all data is 0.617026 after 1000 training step(s) ,loss on all data is 0.392288 after 1500 training step(s) ,loss on all data is 0.386432 after 2000 training step(s) ,loss on all data is 0.384254 after 2500 training step(s) ,loss on all data is 0.383676 after 3000 training step(s) ,loss on all data is 0.383573 after 3500 training step(s) ,loss on all data is 0.383561 after 4000 training step(s) ,loss on all data is 0.383561 after 4500 training step(s) ,loss on all data is 0.383561
4、更改batch的值,會不會對結果有影響?
我把batch改為12,訓練了35000次,最后loss值是下降到了0.384388和0.384447,也就是說未收斂
改為15,訓練了50000次,最后還是下降到某幾個固定的值,仍然未收斂
可以看得出,batch值增大時,訓練次數增大,不收斂的可能性也增加。
將batch改為7和5,訓練了35000次,也是不收斂。
這地方就很納悶了,為啥8效果是最好的呢,這地方留點問題吧。以后再來看看
注:以上問題的結論只是暫時性的總結,由於目前水平有限,不知道結論正確與否。
四、搭建神經網絡的過程
通過以上的內容,我們可以梳理一下搭建簡單神經網絡的步驟:
(1)導入模塊,生成模擬數據集
import
常量定義
生成數據集
(2)前向傳播:定義輸入、參數和輸出
x= y_=
w1= w2=
a= y=
(3)后向傳播:定義損失函數、反向傳播方法
loss=
train_step=
(4)生成會話,訓練STEPS輪
with tf.Session as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
STEPS =
for i in range(STEPS):
start =
end =
sess.run(train_step, feed_dict={ })
以上是搭建簡單神經網絡的筆記
本人初學者,有任何錯誤歡迎指出,謝謝。
