使用TensorFlow实现线性回归预测需要使用到numpy,所以在实现线性回归预测之前,先介绍需要使用到的相关的numpy函数。
一、numpy相关函数介绍
介绍一个numpy的api查看网站http://devdocs.io/numpy~1.11/
np.random.rand()创建一个向量,参数决定产生向量的维数以及行和列的大小
一个参数的时候,产生的是一个行向量,参数的大小决定向量的列数
x = np.random.rand(3)
[0.81982865 0.82531022 0.44399218]
两个参数的时候,产生的是一个二维向量,参数的大小决定向量的行和列,第一个参数决定行数,第二个参数决定列数,下面的这个和上面的是不一样的,多了一对[]
x = np.random.rand(1,3)
[[0.67355041 0.17038178 0.80768854]]
三个参数的时候,产生的是一个三维向量,第一个参数决定的是二维向量的大小,第二个参数决定的是二维向量的行数,第三个参数决定的是二维向量的列数,以此类推rand函数有四个、五个参数....
x = np.random.rand(2,2,3)
[
[[0.20185301 0.29129893 0.91699936]
[0.80844255 0.24154308 0.65849662]]
[[0.53940148 0.83237024 0.7157533]
[0.07668698 0.95970214 0.00301952]]
]
np.float16()函数,半精度16位,5位指数(小数的整数),10位小数,还有一位符号位,整数部分超过位数就会出现inf
x = 12345.123456789
x1 = np.float16(x)
print(x1)# 12344.0
x = 123456.123456789
x1 = np.float16(x)
print(x1)#inf
下面你会看到一个很有趣的现象,细心的同学应该能发现小数的位数会随,整数的位数变化
a = 0.123456789
af = np.float16(a)
print(af)#0.12347
b = 1.23456789
bf = np.float16(b)
print(bf)#1.2344
c = 12.3456789
cf = np.float16(c)
print(cf)#12.344
d = 123.456789
df = np.float16(d)
print(df)#123.44
e = 1234.56789
ef = np.float16(e)
print(ef)#1235.0
还有一个有趣的现象,有numpy的rand函数产生的小数,再经过float16之后小数的位数居然没有发生变化
x = np.random.rand(1,1)
print(x)#[[ 0.20712529]]
xf = np.float16(x)
print(xf)#[[ 0.20715332]]
np.float32()函数,单精度32位,8位指数(小数的整数),23位小数
np.float64()函数,双精度64位,11位指数(小数的整数),52位小数
如果,想要深究为什么会有上面的情况,需要了解计算机小数的存储和python的相关设计,关于计算机小数的存储我推荐一篇博客
np.dot(a,b,out=None)函数,对于二维数组而言就是矩阵的乘法,对于一维数组而言就是相乘再求和,它也可以计算复数直接的乘法,也可以计算N维数组。
1、当a和b都是一维数组时,就是求数组之间的相乘之后再求和
x1 = [1,2,3]
x2 = [4,5,6]
y = np.dot(x1,x2)#1*4+2*5+3*6=32
print(y)#32
2、当a和b是二维数组的时,是矩阵之间的乘法,需要注意的是矩阵之间的乘法np.dot(x1,x2)时,矩阵x1的列数要和x2的行数相等,不然就会报错,如果x2 = [[4,5]]时,就会报ValueError: shapes (2,2) and (1,2) not aligned: 2 (dim 1) != 1 (dim 0),还需要注意的时候矩阵的左乘和右乘是有区别的,即np.dot(x1,x2) != np.dot(x2,x1),除非x1 == x2的时候,下面简单用一个图表示一下矩阵点乘的过程,可能画的不是很好看,意思就是这样(行乘列求和)
x1 = [[1,2],[3,4]]
x2 = [[4],[5]]
y = np.dot(x1,x2)
print(y)
'''
[[14]
[32]]
'''
3、当a和b是多维数组的时,x1和x2都是三维数组的时候,把x1和x2之间的乘法拆分成了四个二维矩阵之间的乘法就是,[[1,2],[3,4]]分别和[[2,3],[2,4]]和[[2,5],[2,6]]两个矩阵的乘法以及[[1,4],[1,5]]分别和[[2,3],[2,4]]和[[2,5],[2,6]]两个矩阵的乘法,将最后的结果进行整合就可以得到y,需要注意的是x1和x2的shape都是(2,2,2)而y的shape是(2,2,2,2)
x1 = [[[1,2],[1,3]],[[1,4],[1,5]]]
x2 = [[[2,3],[2,4]],[[2,5],[2,6]]]
y = np.dot(x1,x2)
print(y)
'''
[
[
[[ 6 11][ 6 17]]
[[ 8 15][ 8 23]]
]
[
[[10 19][10 29]]
[[12 23][12 35]]]
]
'''
当a和b是多维数组的时候,这种情况需要结合上面的结果才能看懂,不然就会一脸懵逼,根本不知道怎么算出来的。[0,1,1]参数的意思是,上面的y是一个四维素组,所以下面[0,1,1]里面参数的个数最大为4,[0,1,1]中第一个参数0代表的是第一个三维数组即
[ [[6 11][6 17]] [[8 15][8 23]] ],第二个参数1代表的是这个三维数组中的第二个二维数组[[8 15][8 23]],第三个参数的1代表的就是这个二维数组中的第二个一维数组[8 23]也就是最终的结果。
x1 = [[[1,2],[1,3]],[[1,4],[1,5]]]
x2 = [[[2,3],[2,4]],[[2,5],[2,6]]]
y = np.dot(x1,x2)[0,1,1]
print(y) #[ 8 23]
二、线性回归模型的实现
在使用TensorFlow实现一个线性模型之前,需要知道在使用机器学习来实现一个线性模型究竟是如何做到的?
其实,所谓的机器学习就是通过一堆大量的数据(数据相对于人的经验),从数据中寻找规律。线性函数y = w * x +b,对于线性模型就是通过数据的特征,来求出参数w和b,也许你会说这不是很简单嘛,给我两个点,不就能求出来了吗。对的,从数学的角度来说,这个答案的确无懈可击。但是,从工业生产的角度来说,并不是这样的,因为不可能保证所有的数据都满足同一个线性函数,更有甚者,你根本不能保证这些数据就一定是满足线性函数,有可能它们本来就是非线性的。所以,我们就不能这样来求参数w和b。在机器学习中,我们将对参数w和b的求解转换成了最优解的求解问题,就是保证我们求出来的模型计算出来的y和实际的y的差距是最小的,通过(1/2)*(实际的y-模型计算的y)^2之和最小,通常用的最优解求解方法是随机梯度下降,这里我就不详细介绍了,网上的相关资料也非常的多。
1、TensorFlow实现线性回归模型
import tensorflow as tf
if __name__ == "__main__":
#初始化线性模型参数w和b
w = tf.Variable([.0])
b = tf.Variable([.0])
#定义线性模型的输入
x = tf.placeholder(tf.float32)
#定义线性模型的表达式
liner_model = w * x + b
#初始化通过Variable方法定义的变量
init = tf.global_variables_initializer()
session = tf.Session()
session.run(init)
#定义线性模型的输出
y = tf.placeholder(tf.float32)
#定义线性模型的损失函数
squared_deltas = tf.square(liner_model - y)
#求模型损失值的和
loss = tf.reduce_sum(squared_deltas)
#定义使用梯度下降算法优化算法,设置下降的步长为0.01
optimizer = tf.train.GradientDescentOptimizer(0.01)
#最小化模型损失值的和
train = optimizer.minimize(loss)
#通过迭代来最小化损失值求参数w和b
for i in range(1000):
#每迭代一次都使损失值往最小的方向靠近
# w = w + 0.01*(liner_model-y)*x
# b = b + 0.01*(liner_model-y)
session.run(train,{x:[1,2,3,4],y:[0,-1,-2,-3]})
print(session.run([w,b]))
#[array([-0.99999768], dtype=float32), array([ 0.99999309], dtype=float32)]
通过输入的x:[1,2,3,4]和输出的y:[0,-1,-2,-3]我们可以计算出参数w和b的值应该为1和-1,通过TensorFlow最小化损失函数的方法求出来的w和b的值分别为-0.99999768和0.99999309,已经和真实模型的参数非常接近了。通过TensorFlow提供的,tf.assign(w,[-1.])方法来修改使用tf.Variable(w)定义变量的值。
2、通过TensorFlow提供的estimator来实现一个线性模型
estimator是TensorFlow一个比较高级的库,它能够简化机器学习的结构。它的使用主要包括三个部分,训练数据的循环、评价的循环、数据的管理,estimator已经定义好了许多的模块。
import tensorflow as tf
#通常使用numpy来加载、操作和预处理数据
import numpy as np
if __name__ == "__main__":
#声明线性模型的特征(x),x为线性模型的输入也就是模型的特征,它是一个一维的数据,所以shape=[1]
feature_columns = [tf.feature_column.numeric_column("x",shape=[1])]
#给estimator提供特征
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)
#通过numpy来定义训练数据和评价数据
x_train = np.array([1.,2.,3.,4.])
y_train = np.array([0.,-1.,-2.,-3.])
x_eval = np.array([2.,5.,8.,1.])
y_eval = np.array([-1.01,-4.1,-7,0.])
#设置数据的相关参数,{"x":x_train}为输入的数据,y_train为x对应的值,batch_size为迭代一次数据的大小,num_epochs迭代的次数
# shuffle为数据是否打乱
input_fn = tf.estimator.inputs.numpy_input_fn({"x":x_train},y_train,batch_size=4,num_epochs=None,shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn({"x":x_train},y_train,batch_size=4,num_epochs=1000,shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn({"x":x_eval},y_eval,batch_size=4,num_epochs=1000,shuffle=False)
#通过estimator来训练数据,steps为迭代的次数
estimator.train(input_fn=input_fn,steps=1000)
#评估模型的好坏,通过损失值(loss),约接近0表示越好
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics:%r" %train_metrics)
#train metrics:{'average_loss': 6.6502416e-08, 'loss': 2.6600966e-07, 'global_step': 1000}
print("eval metrics:%r"%eval_metrics)
#eval metrics:{'average_loss': 0.0025486231, 'loss': 0.010194493, 'global_step': 1000}
3、通过自定义一个estimator来训练一个线性模型
import tensorflow as tf
import numpy as np
#声明一个列表用来存储特征
def model_fn(features,labels,mode):
#构建一个线性模型和预测值
w = tf.get_variable("w",[1],dtype=tf.float64)
b = tf.get_variable("b",[1],dtype=tf.float64)
y = w * features['x'] + b
#计算损失值
loss = tf.reduce_sum(tf.square(y - labels))
#训练
global_step = tf.train.get_global_step()
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = tf.group(optimizer.minimize(loss),tf.assign_add(global_step,1))
return tf.estimator.EstimatorSpec(mode = mode,predictions=y,loss=loss,train_op=train)
if __name__ == "__main__":
#使用自定义的estimator
estimator = tf.estimator.Estimator(model_fn=model_fn)
#定义数据
x_train = np.array([1.,2.,3.,4.])
y_train = np.array([0.,-1.,-2.,-3.])
x_eval = np.array([2.,5.,8.,1.])
y_eval = np.array([-1.01,-4.1,-7,0.])
input_fn = tf.estimator.inputs.numpy_input_fn({"x":x_train},y_train,batch_size=4,num_epochs=None,shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn({"x":x_train},y_train,batch_size=4,num_epochs=1000,shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn({"x":x_eval},y_eval,batch_size=4,num_epochs=1000,shuffle=False)
#训练模型
estimator.train(input_fn=input_fn,steps=1000)
#评估模型
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("trian metrics:%r"%train_metrics)
#trian metrics:{'loss': 1.3258775e-11, 'global_step': 1000}
print("eval metrics:%r"%eval_metrics)
#eval metrics:{'loss': 0.010100389, 'global_step': 1000}