原文鏈接:https://www.cnblogs.com/wanyu416/p/9009985.html
一、神經網絡的實現過程
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) 用placeholder 實現輸入定義(sess.run 中喂入一組數據)的情況,特徵有體積和重量,數據爲體積 0.7、重量 0.5
import tensorflow as tf
x = tf.placeholder(tf.float32,shape=(1,2)) # placeholder佔位,首先要指定數據類型,然後可以指定形狀,因爲我們現在只需要佔一組數據,且有兩個特徵值,所以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) # 矩陣乘法op
y = tf.matmul(a,w2)
with tf.Session() as sess:
init = tf.global_variables_initializer() # 初始化以後就放在這裏,不容易忘記
sess.run(init)
print("y is",sess.run(y,feed_dict={x:[[0.7,0.5]]})) # 以字典形式給feed_dict賦值,賦的是一個一行兩列的矩陣,注意張量的階數。這裏只執行了y的op,因爲執行了y也就執行了a這個op
運行顯示結果爲:
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 輪輸出一次損失函數。
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8 # 一次輸入網絡的數據,稱爲batch。一次不能喂太多數據
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 = tf.reduce_mean(tf.square(y - y_))
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss) # 三種優化方法選擇一個就可以
# 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 = tf.global_variables_initializer()
sess.run(init)
# 輸出目前(未經訓練)的參數取值。
print("w1:\n", sess.run(w1))
print("w2:\n", sess.run(w2))
print("\n")
# 訓練模型。
STEPS = 3000
for i in range(STEPS): #0-2999
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次。
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, 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))
運行顯示結果爲
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會不會繼續減小?如果減小,會不會一直在減小?
2、如果增大學習率,loss會不會繼續減小?如果減小,會不會一直在減小?
3、如果不用隨機梯度下降算法,換用其他的優化器,會產生什麼樣的變化?
4、更改batch的值,會不會對結果有影響?
四、搭建神經網絡的過程
通過以上的內容,我們可以梳理一下搭建簡單神經網絡的步驟:
(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={ })