线性回归问题TensorFlow实战
使用Tensorflow进行算法设计与训练的核心步骤
- 准备数据
- 构建模型
- 训练模型.
- 进行预测
上述步骤是我们使用Tensorflow进行算法设计与训练的核心步骤,贯穿于后面介绍的具体实战中。本章用一一个简单的例子来讲解这几个步骤。
线性方程
本例通过生成人工数据集。随机生成一个近似采样随机分布,使得,, 并加入- -个噪声,噪声的最大振幅为0.4
生成人工数据
#在Jupyter中,使用matplotIib显示图像需要设置为 inline 模式,
#否则不会现实图像
%matplotlib inline
import matplotlib. pyplot as plt
import numpy as np #载入numpy
import tensorflow as tf #载入Tensorflow
#设置随机数种子
np.random.seed (5) #产生相同的随机数
首先,生成输入数据。我们需要构造满足这个函数的x和y同时加入- -些不满足方程的噪声.
#直接采用np生成等差数列的方法,生成100个点, 每个点的取值在-1 ~1之间
x_data = np. linspace(-1, 1,100)
#y=2x+1+噪声,其中,噪声的维度与x _data一致
y_data=2*x_data +1.0 + np. random.randn(*x_data.shape) * 0.4
# np.random.randn(10)
# 返回10个根据标准正太分布获得的数据得到的一维数组
# #实参的前面加上*和**时,就意味着拆包。
#单个*表示将元组拆成- - 个个单独的实参
#本例中,np. random. randn (*x data. shape)和np. random. randn (100)功能相同
利用matplotlib
画出生成结果
#画出随机生成数据的散点图
plt.scatter(x_data, y_data)
#画出我们想要学习到的线性函数y=2x +1
构建模型
定义训练数据的占位符,x是特征值,y是标签值。
x = tf. placeholder("float",name ="x")
y = tf. placeholder("float",name ="y")
定义模型函数
def model(x,w,b):
return tf.multiply(x,w)+b
创建变量
Tensorflow变量的声明函数是tf. Variable;tf.Variable的作用是保存和更新参数;●变量的初始值可以是随机数、常数,或是通过其他变量的初始值计算得到。
#构建线性函数的斜率,变量w
w = tf. Variable(1.0, name="w0") #1.0初始值无所谓
#构建线性函数的截距,变量b
b = tf. Variable(0.0,name="b0" )
# pred是预测值,前向计算
pred = model(x, w,b)
训练模型
# 设置训练参数
#迭代次数(训练轮数)
train_epochs = 10
#学习率
learning_rate = 0.05 #设置0.01到0.1之间,根据以往的经验,设置为0.05
定义损失函数
损失函数用于描述预测值与真实值之间的误差,从而指导模型收敛方向;常见损失函数:均方差(Mean Square Error, MSE) 和交叉熵(cross- entropy)
L2损失函数
#采用均方差作为损失函数
loss_function = tf. reduce_mean(tf.square(y-pred))
定义优化器
定义优化器Optimizer,初始化一个GradientDescentOptimizer;设置学习率和优化目标:最小化损失。
#梯度下降优化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)
创建会话
#声明会话
sess = tf. Session()
#变量初始化
init = tf.global_variables_initializer()
sess.run(init)
迭代训练
模型训练阶段,设置迭代轮次,每次通过将样本逐个输入模型,进行梯度下降优化操作每轮迭代后,绘制出模型曲线
#开始训练,轮数为epoch,采用SGD随机梯度下降优化方法
for epoch in range (train_epochs) :
for xs,ys in zip(x_data, y_data) :
_,loss=sess.run([optimizer, loss_function], feed_dict={x: xs, y: ys})
b0temp=b.eval(session=sess)
wOtemp=w.eval(session=sess)
plt.plot (x_data, wOtemp * x_data + b0temp )# 画图
print("w: ",sess.run(w)) #w的值应在2的附近
print("b: ",sess.run(b)) #b的值应该在1的附近
#可视化
plt.scatter(x_data,y_data,label='Original data')
plt.plot(x_data,x_data * sess.run(w)+sess.run(b),\
label="Fitted line",color='r',linewidth=3)
plt.legend(loc=2)
进行预测
x_test=3.21
predict=sess.run(pred,feed_dict={x:x_test})
print("预测值: %f" % predict)
target=2*x_test+1.0
print("目标值: %f" % target)
以上是利用Tensorflow训练-个线性模型并进行预测的完整过程。通过逐渐降低损失值loss来训练参数w和b拟合y = 2x + 1中的系数2和1。
小结
(1)生成人工数据集及其可视化
(2)构建线性模型
(3)定义损失函数
(4)定义优化器、最小化损失函数
(5)训练结果的可视化
(6)利用学习到的模型进行预测.
显示损失值
#对kernel进行restart释放内存空间,对变量情况
#开始训练,轮数为epoch, 采用SGD随机梯度下降优化方法
display_step=10 #控制显示loss的粒度
step = 0 #记录训练步数
loss_list = [ ] #用于保存loss值的列表
for epoch in range(train_epochs):
for xs,ys in zip(x_data,y_data):
_,loss=sess.run([optimizer,loss_function],feed_dict={x:xs,y:ys})
##显示损失值loss
# display_ step:控制报告的粒度
#例如,如果display step 设为2,则将每训练2个样本输出- -次损失值
#与超参数不同,修改display_ step 不会更改模型所学习的规律
loss_list. append(loss)
step=step+1
if step % display_step==0:
print("Train Epoch:",'%02d' % (epoch+1),"Step :%03d" % (step),\
"loss=", '{:.9f}'.format(loss))
b0temp=b.eval(session=sess)
w0temp=w.eval(session=sess)
plt.plot(x_data,w0temp* x_data+b0temp )#画图
plt.plot(loss_list)
plt.plot(loss_list,'r+')
多元线性回归问题TensorFlow实践(波士顿房价预测)
波士顿房价数据
波士顿房价数据集包括506个样本,每个样本包括12个特征变量和该地区的平均房价。房价(单价)显然和多个特征变量相关,不是单变量线性回归(- 元线性回归)问题。选择多个特征变量来建立线性方程,这就是多变量线性回归(多 元线性回归)问题
下载泰坦尼克号上旅客的数据集
#下载泰坦尼克号上旅客的数据集
import urllib.request
import os
data_url="http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic3.xls"
data_file_path="titanic3.xls" #当前路径下的位置
if not os.path.isfile(data_file_path):
result=urllib.request.urlretrieve(data_url,data_file_path)
print('download:',result)
else:
print(data_file_path,'data file already esists.')
字段 | 字段说明 | 数据说明 |
pclass | 舱等 | 1头等;2二等;3三等 |
survival | 是否生存 | 0否;1是 |
name | 姓名 | |
sex | 性别 | Female女性;male男 |
age | 年龄 | |
sibsp | 兄弟姐妹或者配偶在船上的数量 | |
parch | 双亲或者子女也在船上的数量 | |
ticked | 船票号码 | |
fare | 船票费用 | |
cabin | 舱位号码 | |
embarked | 登船港口 | C=Cherbourg;A=queenstown;S=southampton |
使用Pandas进行数据处理
import numpy
import pandas as pd
#读取数据文件,结果为DataFrame格式
df_data = pd.read_excel(data_file_path)
##查看数据摘要
df_data.describe()
survival (是否生存)是标签字段,其他是候选特征字段
筛选提取需要的特征字段,去掉ticket, cabin等
#筛选提取需要的特征字段,去掉ticket, cabin等
selected_cols=['survived','name','pclass','sex','age','sibsp','fare','embarked']
selected_df_data=df_data[selected_cols]
survived是标签,name为区别暂时保留,其他的为特征
数据准备(相关操作)
波士顿房价
#获取df的值,返回二维列表
df=df.values
#把df转换成np的数组格式
df=np.array(df)
#x_data为前12列特征数据
x_data=df[:,:12]
#y_data为最后一列数据
y_data=df[:,12]
#df.shape 树蕨维数性质
from sklearn.datasets import load_boston
boston = load_boston()
df=boston.data
#数据集未曾归一化,结果可能导致异常
x_data=boston.data[:,:12]
#pd.DataFrame(x_data)
y_data=boston.target
#特征数据归一化
#对特征数据[0到11]列做(0-1)归一化
for i in range(12) :
df[:, i]=df[:, i]/(df[:, i].max()-df[:,i].min())
# x data为归一化后的前12列特征数据
x_data = df[:, :12]
# y_ data 为最后1列标签数据
y_data = df[:,12]
模型定义
定义训练数据占位符
#定义特征数据和标签数据的占位符
x = tf. placeholder(tf.float32,[None,12],name ="X") # 12个特征数据(12列)
x = tf. placeholder(tf.float32,[None,1],name ="Y") # 1个特征数据(1列)
#[None,12]数据结构:行不管,列一个
定义模型结构
#定义模型函数
##定义了一个命名空间
with tf.name_scope("Model"): #把内部相关的节点打包在一起
# w初始化值为shape=(12, 1)的标准差为0.01的随机数填充
w = tf. Variable(tf.random_normal([12,1],stddev=0.01),name="w")
# b初始化值为1.0
b = tf. Variable(1.0, name="b")
# w和x是矩阵相乘,用matmul,不能用mutiply或者*
#y=x1w1+x2w2+...+xnwn+b
def model(x, w,b):
return tf.matmul(x,w)+b
#init = tf.global_variables_initializer()
#预测计算操作,前向计算节点
pred=model(x,w,b)
模型训练
损失函数
#定义均方误差损失函数
with tf.name_scope("LossFunction"):
loss_function=tf.reduce_mean(tf.pow(y-pred,2))
#设置训练超参数
train_epochs=50
learning_rate=0.01
优化器
#创建优化器
optimizer=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)
常用优化器
tf.train.GradientDescentOptimizer
梯度下降算法优化器tf.train.GradientDescentOptimizer( learning_rate, use_locking=False, name='GradientDescent', )
tf.train.AdadeltaOptimizer
AdaDelta,是google提出的一种对于AdaOptimizer的改进,同样是一种自适应的优化器,在看上面ada优化器的时候我们会发现,当训练时间越来越长的时候,分母会越来越大因此导致所有的该变量都趋向于变为0,这样就会导致训练停止,可能导致没有充分的训练。为了解决这个问题,google提出了adadelta算法,加入了一个ρ参数,使得分母不仅仅在不断地积累,同时也乘参数使其不断的减小。tf.train.AdadeltaOptimizer( learning_rate=0.001, rho=0.95, epsilon=1e-08, use_locking=False, name='Adadelta', )
tf.train.AdagradOptimizer
自适应的梯度下降算法。其主要的思想是,如果一个可学习的参数已经梯度下降了很多,则减缓其下降的速度,反之如果一个参数和初始化相比没有下降很多,保证它有一个比较大的下降速度。和之前的对所有参数“一视同仁”的方法相比,该方法更加的“因材施教”。tf.train.AdagradOptimizer( learning_rate, initial_accumulator_value=0.1, use_locking=False, name='Adagrad', )
tf.train.MomentumOptimizer
这个函数是带动量的梯度下降,与之前的区别就是在一次梯度下降的计算时,同时考虑到上一次梯度下降的大小和方向,就好像梯度下降是有惯性一样tf.train.MomentumOptimizer( learning_rate, momentum, use_locking=False, name='Momentum', use_nesterov=False, )
tf.train.AdamOptimizer
全称是Adagrad双重平均算法(Dual Averaging algorithm)tf.train.AdamOptimizer( learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-08, use_locking=False, name='Adam', )
tf.train.FtrlOptimizer
tf.train.ProximalGradientDescentOptimizer
接近梯度下降方法,这个是tf取的名字,其实在文章中,作者简称该梯度下降算法为folos,之所以叫接近的梯度下降算法,是因为作者在原梯度下降算法的基础上加入了修正,进而解决了一些不可微的问题tf.train.ProximalGradientDescentOptimizer( learning_rate, l1_regularization_strength=0.0, l2_regularization_strength=0.0, use_locking=False, name='ProximalGradientDescent', )
tf.train.ProximalAdagradOptimizer
tf.train.RMSPropOptimizer
声明会话
sess=tf.Session()
init=tf.global_variables_initializer()
sess.run(init)
迭代训练ke
for epoch in range(train_epochs):
loss_sum=0.0
for xs,ys in zip(x_data,y_data):
xs=xs.reshape(1,12)
ys=ys.reshape(1, 1)
#feed数据必须和placeholder的shape一致
_,loss=sess.run([optimizer,loss_function],feed_dict={x:xs,y:ys})
loss_sum=loss_sum+loss
#打乱数据顺序
xvalues=random.shuffle(x_data)
yvalues=random.shuffle(y_data)
b0temp=b.eval(session=sess)
w0temp=w.eval(session=sess)
loss_average=loss_sum/len(y_data)
print('epoch',epoch+1,"loss=",loss_average,"b=",b0temp,"w=",w0temp)
可能会出现结果异常的原因:要考虑不同特征值取值范围大小的影响。
因为用归一化:
特征数据归一化
#对特征数据[0到11]列做(0-1)归一化
for i in range(12) :
df[:, i]=df[:, i]/(df[:, i].max()-df[:,i].min())
# x data为归一化后的前12列特征数据
x_data = df[:, :12]
# y_ data 为最后1列标签数据
y_data = df[:,12]
模型应用
模型一般应该用来预测新的样本的值。本例506条数据都用来训练了,暂时没有新的数据
n=348 #指定一条来看效果
#n=np.random.randint(506) #随机确定一条来看
print(n)
x_test=x_data[n]
x_test=x_test.reshape(1,12)
predict=sess.run(pred,feed_dict={x:x_test})
print("预测值: %f" %predict)
target=y_data[n]
print("标签值: %f" % target)
思考:该不该把全部的数据都参与训练?
可视化训练过程中的损失值