基于上一篇博客二元一次方程求解,上面的例子如果能完成,结合官网的资料和其他博主的资料,我相信你已经算入了个门了,后面能不能通过修改上面的例子进行解决更加复杂的问题呢?再看看下一个问题,如果有一个值,它受到 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 的值了。 目前这个代码也可以修改一下训练集的数量以及变量的数量,然后通过调梯度下降学习速率参数来进行训练