1. 程式人生 > >(2)tensorflow 再深入一點:多元一次方程求解

(2)tensorflow 再深入一點:多元一次方程求解

基於上一篇部落格二元一次方程求解,上面的例子如果能完成,結合官網的資料和其他博主的資料,我相信你已經算入了個門了,後面能不能通過修改上面的例子進行解決更加複雜的問題呢?再看看下一個問題,如果有一個值,它受到 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 的值了。 目前這個程式碼也可以修改一下訓練集的數量以及變數的數量,然後通過調梯度下降學習速率引數來進行訓練