(2)tensorflow 再深入一點:多元一次方程求解
阿新 • • 發佈:2019-01-02
基於上一篇部落格二元一次方程求解,上面的例子如果能完成,結合官網的資料和其他博主的資料,我相信你已經算入了個門了,後面能不能通過修改上面的例子進行解決更加複雜的問題呢?再看看下一個問題,如果有一個值,它受到 N 個引數的影響,但是每個引數的權重我們並不清楚,我們希望能用剛剛學到的 TensorFlow 來解決這個問題。 首先建立一個模型,表示 N 組資料,具體點,先實現 5 個變數的求解,生成 10 個數據集,我們可以很容易聯想到使用大小為 [10,5]的矩陣表示 t_x,使用大小為 [5,1]的矩陣表示引數權重 t_w,使用大小為 [10,1]的矩陣表示結果 t_y,即 t_y = t_x * t_w。 當然,為了更加通用,變數的數量和資料集的數量可以使用常量來表示,矩陣的向量乘法在 numpy 庫中使用 dot 函式實現:
test_count = 10 #資料集數量
param_count = 5 #變數數
t_x = np.floor(1000 * np.random.random([test_count,param_count]),dtype=np.float32)
#要求的值
t_w = np.floor(1000 * np.random.random([param_count,1]),dtype=np.float32)
#根據公式 t_y = t_x * t_w 算出值 t_y
t_y = t_x.dot(t_w)
print t_x
print t_w
print t_y
與上面的例子一樣,我們以 TensorFlow 佔位符形式定義輸入訓練集 x 和 y,矩陣大小可以使用 shape 引數來定義:#x 是輸入量,對應 t_x,用於訓練輸入,在訓練過程中,由外部提供,因此是 placeholder 型別 x = tf.placeholder(tf.float32,shape=[test_count,param_count]) y = tf.placeholder(tf.float32,shape=[test_count,1])
以 TensorFlow 變數形式定義結果 w:
#w 是要求的各個引數的權重,是目標輸出,對應 t_w
w = tf.Variable(np.zeros(param_count,dtype=np.float32).reshape((param_count,1)), tf.float32)
定義 TensorFlow 計算結果 y、損失函式 loss 和訓練方法:
curr_y = tf.matmul(x, w) #實際輸出資料 loss = tf.reduce_sum(tf.square(t_y - curr_y)) #損失函式,實際輸出資料和訓練輸出資料的方差之和 optimizer = tf.train.GradientDescentOptimizer(0.0000001) train = optimizer.minimize(loss) #訓練的結果是使得損失函式最小
針對訓練次數的問題,我們可以優化一下之前的方式,設定當 loss 函式值低於一定值或者不再變化的時候停止,因為 loss 函式需要在 Session 中使用,它需要使用 TensorFlow 的常量表示:
LOSS_MIN_VALUE = tf.constant(1e-5) #達到此精度的時候結束訓練
模型已經建立完畢,開始訓練,我們使用變數 run_count 來記錄訓練的次數,以 last_loss 記錄上一次訓練的損失函式的值,初始值為 0。sess = tf.Session()
sess.run(tf.global_variables_initializer())
run_count = 0
last_loss = 0
訓練主迴圈,將當前的 loss 函式值儲存在 curr_loss 中,與上一次相比,如果相同,則退出訓練,另外如果 loss 函式低於設定的精度 LOSS_MIN_VALUE,也會退出訓練:
while True:
run_count = 1
sess.run(train, {x:t_x, y:t_y})
curr_loss,is_ok = sess.run([loss,loss < LOSS_MIN_VALUE],{x:t_x, y:t_y})
print "執行%d 次,loss=%s" % (run_count,curr_loss)
if last_loss == curr_loss:
break
last_loss = curr_loss
if is_ok:
break
最後列印結果,由於我們知道 t_w 的值是整數,因此將得到的結果四捨五入的值 fix_w 也打印出來,再看看 fix_w 與 t_w 的差距 fix_w_loss 是多少:curr_W, curr_loss = sess.run([w, loss], {x:t_x,y:t_y})
print("t_w: %snw: %snfix_w: %snloss: %snfix_w_loss:%s" % (t_w, curr_W, np.round(curr_W), curr_loss, np.sum(np.square(t_w - np.round(curr_W)))))
exit(0)
完整程式碼如下:
#!/usr/bin/python
#coding=utf-8
import tensorflow as tf
import numpy as np
tf.logging.set_verbosity(tf.logging.ERROR) #日誌級別設定成 ERROR,避免干擾
np.set_printoptions(threshold='nan') #列印內容不限制長度
test_count = 10 #資料集數量
param_count = 5 #變數數
t_x = np.floor(1000 * np.random.random([test_count,param_count]),dtype=np.float32)
#要求的值
t_w = np.floor(1000 * np.random.random([param_count,1]),dtype=np.float32)
#根據公式 t_y = t_x * t_w 算出值 t_y
t_y = t_x.dot(t_w)
print t_x
print t_w
print t_y
#x 是輸入量,對應 t_x,用於訓練輸入,在訓練過程中,由外部提供,因此是 placeholder 型別
x = tf.placeholder(tf.float32,shape=[test_count,param_count])
y = tf.placeholder(tf.float32,shape=[test_count,1])
#w 是要求的各個引數的權重,是目標輸出,對應 t_w
w = tf.Variable(np.zeros(param_count,dtype=np.float32).reshape((param_count,1)), tf.float32)
curr_y = tf.matmul(x, w) #實際輸出資料
loss = tf.reduce_sum(tf.square(t_y - curr_y)) #損失函式,實際輸出資料和訓練輸出資料的方差之和
optimizer = tf.train.GradientDescentOptimizer(0.00000001)
train = optimizer.minimize(loss) #訓練的結果是使得損失函式最小
LOSS_MIN_VALUE = tf.constant(1e-5) #達到此精度的時候結束訓練
sess = tf.Session()
sess.run(tf.global_variables_initializer())
run_count = 0
last_loss = 0
while True:
run_count = 1
sess.run(train, {x:t_x, y:t_y})
curr_loss,is_ok = sess.run([loss,loss < LOSS_MIN_VALUE],{x:t_x, y:t_y})
print "執行%d 次,loss=%s" % (run_count,curr_loss)
if last_loss == curr_loss:
break
last_loss = curr_loss
if is_ok:
break
curr_W, curr_loss = sess.run([w, loss], {x:t_x,y:t_y})
print("t_w: %snw: %snfix_w: %snloss: %snfix_w_loss:%s" % (t_w, curr_W, np.round(curr_W), curr_loss, np.sum(np.square(t_w - np.round(curr_W)))))
exit(0)
執行一下,仍然把頭尾的部分記錄下來,中間部分太多就省略掉:
$ python ./test1.py
[[ 842. 453. 586. 919. 91.]
[ 867. 600. 156. 993. 558.]
[ 795. 809. 146. 793. 118.]
[ 202. 184. 125. 132. 450.]
[ 214. 36. 436. 118. 290.]
[ 207. 916. 757. 647. 670.]
[ 679. 176. 872. 522. 927.]
[ 552. 602. 981. 563. 937.]
[ 31. 519. 718. 226. 178.]
[ 571. 464. 289. 141. 769.]]
[[ 42.]
[ 465.]
[ 890.]
[ 84.]
[ 488.]]
[[ 889153.]
[ 809970.]
[ 663711.]
[ 435982.]
[ 565200.]
[ 1489672.]
[ 1382662.]
[ 1680752.]
[ 987505.]
[ 884068.]]
執行 1 次,loss=3.30516e 13
執行 2 次,loss=1.02875e 14
執行 3 次,loss=3.22531e 14
執行 4 次,loss=1.01237e 15
執行 5 次,loss=3.17825e 15
執行 6 次,loss=9.97822e 15
執行 7 次,loss=3.13272e 16
執行 8 次,loss=9.83534e 16
執行 9 次,loss=3.08786e 17
執行 10 次,loss=9.69452e 17
執行 11 次,loss=3.04365e 18
執行 12 次,loss=9.55571e 18
執行 13 次,loss=3.00007e 19
執行 14 次,loss=9.41889e 19
執行 15 次,loss=2.95712e 20
...
執行 2821 次,loss=6839.32
執行 2822 次,loss=6780.68
執行 2823 次,loss=6767.86
執行 2824 次,loss=6735.09
執行 2825 次,loss=6709.06
執行 2826 次,loss=6662.66
執行 2827 次,loss=6637.81
執行 2828 次,loss=6637.81
t_w: [[ 117.]
[ 642.]
[ 662.]
[ 318.]
[ 771.]]
w: [[ 117.0872879 ]
[ 641.80706787]
[ 662.05078125]
[ 318.10388184]
[ 771.01501465]]
fix_w: [[ 117.]
[ 642.]
[ 662.]
[ 318.]
[ 771.]]
loss: 6637.81
fix_loss:0.0
可見,這次在執行了 2828 次之後,loss 函式從 3.30516e 13 降低到 6637.81 後不再變動,看起來有點大,但是實際上我們的 y 值也是非常大的,最後求得的結果與實際值有大約不到千分之一的差距,要縮小這個差距,可以通過減少梯度下降學習速率,同時增加訓練次數來解決,而 fix_w 的值已經等於 t_w 的值了。 目前這個程式碼也可以修改一下訓練集的數量以及變數的數量,然後通過調梯度下降學習速率引數來進行訓練