在回归中定义了损失函数或目标函数,其目的是找到使损失最小化的系数。声明一个损失函数需要将系数定义为变量,将数据集定义为占位标准线性回归符。可以有一个常学习率或变化的学习率和正则化常数。
1.标准线性回归
import tensorflow as tf
m=100 //样本数量
n=15 //特征数量
p=2 //类别数量
X=tf.placeholder(tf.float32,name='X')
Y=tf.placeholder(tf.float32,name='Y')
w0=tf.Variable(0.0)
w1=tf.Variable(0.0)
Y_hat=X*w1+w0
loss=tf.square(Y-Y_hat,name='loss')
在多元线性回归的情况下,输入变量不止一个,而输出变量仍为一个。现在可以定义占位符X的大小为 [m,n],其中 m 是样本数量,n 是特征数量
X=tf.placeholder(tf.float32,name='X',shape=[m,n])
Y=tf.placeholder(tf.float32,name='Y')
w0=tf.Variable(0.0)
w1=tf.Variable(tf.random_normal([n,1]))
Y_hat=tf.matmul(X,w1)+w0
loss=tf.reduce_mean(tf.square(Y-Y_hat,name='loss'))
2.逻辑回归
损失函数定义为交叉熵。输出 Y 的维数等于训练数据集中类别的数量,其中 P 为类别数量
X=tf.placeholder(tf.float32,name='X',shape=[m,n])
Y=tf.placeholder(tf.float32,name='Y',shape=[m,P])
w0=tf.Variable(tf.zeros([1,P]),name='bias')
w1=tf.Variable(tf.random_normal([n,1]),name='weights')
Y_hat=tf.matmul(X,w1)+w0
entropy=tf.nn.softmax_cross_entropy_with_logits(Y_hat,Y)
loss=tf.reduce_mean(entropy)
在 L1 正则化中,与所有系数的绝对值的和相关的附加惩罚项被添加到损失函数中。L1 正则化的正则化惩罚项如下:
代码如下:
lamda=tf.constant(0.8) #regularization parameter
regularization_param=lamda*tf.reduce_sum(tf.abs(w1))
loss+=regularization_param
L2 正则化提供了稀疏的解决方案。当输入特征的数量非常大时,非常有用。在这种情况下,惩罚项是所有系数的平方之和:代码如下:
lamda=tf.constant(0.8) #regularization parameter
regularization_param=lamda*tf.nn.l2_loss(w1)
loss+=regularization_param
为确保收敛,损失函数应为凸的。一个光滑的、可微分的凸损失函数可以提供更好的收敛性。随着学习的进行,损失函数的值应该下降,并最终变得稳定。
3.梯度下降算法:
调整系数(权重和偏置)使损失函数的梯度下降
- Vanilla 梯度下降:在 Vanilla 梯度下降(也称作批梯度下降)中,在每个循环中计算整个训练集的损失函数的梯度。该方法可能很慢并且难以处理非常大的数据集。该方法能保证收敛到凸损失函数的全局最小值,但对于非凸损失函数可能会稳定在局部极小值处。
- 随机梯度下降:在随机梯度下降中,一次提供一个训练样本用于更新权重和偏置,从而使损失函数的梯度减小,然后再转向下一个训练样本。整个过程重复了若干个循环。由于每次更新一次,所以它比 Vanilla 快,但由于频繁更新,所以损失函数值的方差会比较大。
- 小批量梯度下降:该方法结合了前两者的优点,利用一批训练样本来更新参数。
- 最简单的梯度下降优化器开始:
tf.train.GradiantDescentOptimizer(learning_rate)
必须为优化器给定要优化的函数。使用它的方法实现最小化。该方法计算梯度并将梯度应用于系数的学习。
optimizer=tf.train.GradiantDescentOptimizer(learning_rate=0.01)
train_step=optimizer.minimize(loss)
with tf.Session() as sess:
sess.run(train_step,feed_dict={X:X-data,Y:Y_data})
- 梯度下降中的另一个变化是增加了动量项。为此,使用优化器 tf.train.MomentumOptimizer()。它可以把 learning_rate 和 momentum 作为初始化参数:
optimizer=tf.train.MomentOptimizer(learning_rate=0.01,momentum=0.5).minimize(loss)
- 可以使用 tf.train.AdadeltaOptimizer() 来实现一个自适应的、单调递减的学习率,它使用两个初始化参数 learning_rate 和衰减因子 rho:
optimizer=tf.train.AdadeltaOptimizer(learning_rate=0.01,rho=0.95).minimize(loss)
- 另一种 TensorFlow 支持的常用优化器是 Adam 优化器。该方法利用梯度的一阶和二阶矩对不同的系数计算不同的自适应学习率:
optimizer=tf.train.AdamOPtimizer().minimize(loss)
4.举例:波士顿房价预测
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.utils import shuffle
//读取数据文件
df = pd.read_csv("data/boston.csv",header=0)
#获取df的值
df = df.values
#把df转换成np的数组格式
df = np.array(df)
#对特征数据{0到11}列 做(0-1)归一化
for i in range(12):
df[:,i] = (df[:,i]-df[:,i].min())/(df[:,i].max()-df[:,i].min())
#x_data为归一化后的前12列特征数据
x_data = df[:,:12]
#y_data为最后1列标签数据
y_data = df[:,12]
//模型定义
#定义特征数据和标签数据的占位符
#shape中None表示行的数量未知,在实际训练时决定一次带入多少行样本,从一个样本的随机SDG到批量SDG都可以
x = tf.placeholder(tf.float32,[None,12],name = "X") #12个特征数据(12列)
y = tf.placeholder(tf.float32,[None,1],name = "Y") #1个标签数据(1列)
#定义模型函数
with tf.name_scope("Model"):
w = tf.Variable(tf.random_normal([12,1],stddev=0.01),name="W")
b = tf.Variable(1.0,name="b")
def model(x,w,b):
return tf.matmul(x,w) + b
pred = model(x,w,b)
//模型训练
train_epochs = 50 #迭代轮次
learning_rate = 0.01 #学习率
with tf.name_scope("LossFunction"):
loss_function = tf.reduce_mean(tf.pow(y-pred,2))
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)
#声明会话
sess = tf.Session()
#定义初始化变量的操作
init = tf.global_variables_initializer()
#启动会话
sess.run(init)
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
#打乱数据顺序,防止按原次序假性训练输出
x_data,y_data = shuffle(x_data,y_data)
b0temp = b.eval(session=sess) #训练中当前变量b值
w0temp = w.eval(session=sess) #训练中当前权重w值
loss_average = loss_sum/len(y_data) #当前训练中的平均损失
print("epoch=",epoch+1,"loss=",loss_average,"b=",b0temp,"w=",w0temp)
//模型应用
n = np.random.randint(506) #随机确定一条来看看效果
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)