梯度下降
对于代价函数,或者我们可以推广到更一般的代价函数(系数更多),如
,如果要最小化代价函数
,那么我们可以用梯度下降法来解决,下面会以两个参数的代价函数为例对梯度下降法进行介绍:
- 给
的两个参数
和
赋两个初始值,这个值可以随意,但通常会选择将
和
均设为0。
- 不停地一点点改变
和
,使代价函数
越来越小,直到找到最小值。
以下图为例,我们初始设定的和
对应图中的某个点,我们将这个点记为起点1,现在从起点1出发,沿路径1收敛于局部的最低点,也就是局部最优解。如果我们的起点往右偏移一点得到起点2,那么第二个局部最优解应该是沿路径2收敛的最小值。同理,如果起点1往右偏移一点,也会得到不同的最优解。
下面我们来看看梯度下降算法的数学原理:
重复下面这行算法,不断更新参数,直到收敛于最小值,其中
表示赋值,
表示学习率(learning rate),这里表示梯度下降的快慢,
是导数项,先不用管,之后会进行详细解释
上面我们说到了要不断改变和
的值,那么如何改变呢,也是利用上面这一行算法,并且改变
和
的值是同步进行的,在每次循环中,我们只要保存
的值,赋值给
和
即可,如下:
好了,现在我们来解释一下导数项的含义,假如下图所示是
和
的图像,我们先看看
,假设
位于图中所示位置,对应点的正切值为正,那么
将不断减小,逐渐收敛于局部最低点,当正切为0时,
不再改变,此时找到了局部最优解。
同理我们看看的图像,假设
位于图中所示位置,对应点的正切值为负,那么
将不断增大,逐渐收敛于局部最低点,当正切为0时,
不再改变,此时找到了局部最优解。
现在我们再来讨论一下公式中的,
表示学习率,也叫步长,下面我们以
为例解释,可能有的同学会觉得如果
取值过小,
变化的越慢,会影响效率,如图1,但如果
取值过大,
每次变化的跨度很大,也可能很难找到局部最优,如图2,其实这些都不用担心,正确的梯度下降算法运行方式应该如图3,什么?越接近局部最优时步长
变小了?难道还要不断改变
的大小吗,其实不是
变小了,而是导数项
变小了,我们都知道在收敛于局部最优的过程中,正切值是不断收敛于0的,因此
整体是减小的,所以越趋近于局部最优,
的改变量自然会越来越小,并不用额外去改变
的大小。
ok,现在我们知道了这行算法的含义,那么要写出代码,我们还需要求出导数项
,才可以实现最小化代价函数
已知代价函数:
对代价函数求偏导:
因此对于和
分别有:
现在我们求得了偏导,将偏导代回原来的式子,得到如下算法,不断重复更新和
,直到收敛即可:
多元梯度下降法
例题:分析住房价格与所给特征值的关系
面积(平方英尺) | 房间数 | 层数 | 住房年龄(年) | 价格($1000) |
---|---|---|---|---|
2104 | 5 | 1 | 45 | 460 |
1416 | 3 | 2 | 40 | 232 |
1534 | 3 | 2 | 30 | 315 |
852 | 2 | 1 | 36 | 178 |
注:
- n表示特征值的个数,如这里的x有四个,故n=4
- m表示样本数目,一行为一个样本,m=4
表示第i个训练样本的输入特征值,如:
表示第i个训练样本中第j个特征量的值
在之前的回归假设中,我们假设的函数只有一个元,在多元问题中,这个假设不再适用,由于有四个特征值,我们可以假设成
现在利用矩阵来简化一下这个等式的表示方式,为了统一形式,看成
,令
即可,那么现在也就意味着第
个都有一个向量
,其中
,由于特征值x加多了一列,所以特征向量
是一个从0开始的
维向量
有了上面这两个矩阵,我们假设的函数就可以用矩阵进行表示了,如下:
现在,我们来看看多元梯度下降算法的运作形式:
首先,我们把参数看成维向量,则代价函数
然后重复以下这行算法,直到收敛于局部最优解:
这里的导数项,因此变成:
梯度下降运算(特征放缩法)
但一个问题含有多个特征值,如果能保证不同特征的取值在相近的范围内,梯度下降法就能更快地收敛,还是以上面的例题为例,表示面积,取值在02000平方英尺**之间,$x_2$表示房间数,**取值在05之间,现在特征值间的差距还是很大的,我们要尽量将特征值的范围约束在
的范围内,只需进行如下标准化在操作:
是平均值,
是标准差。
多元梯度下降学习率的选择
对于学习率的选择,我们可以先在梯度下降算法运行时绘制出代价函数和迭代次数的图来评估算法的运行是否正常,若算法运行正常,则图像呈现出来的是在每一步迭代之后
都在下降,最终趋于稳定,也就是梯度下降算法已经收敛,如下图:
如果学习率过大,会出现下图代价函数不收敛反而发散的情况,这时候需要减小学习率
其实只要学习率足够小,那么每次迭代之后代价函数都会下降,所以如果出现的曲线不是下降的,一般都认为是学习率过大。但学习率过小,收敛速率会很低。
所以在算法运行时,我们会尝试不同的学习率,比如然后对于这些不同的
值绘制
随迭代步数变化的曲线,然后选择使得
快速下降的一个
值。
多项式回归
有时候,我们要拟合的不是简单的直线,也可能是曲线,这时候就要选择多项式模型进行拟合,如下图表示房价与面积的关系,我们根据散点图的特征可选择一个三次函数去进行拟合,如,大致如图中红线所示,这里只是举个例子,还有很多其他多项式拟合模型也是适用的:
好了,现在拟合模型有了,接下来要做的就是将模型与我们的数据进行拟合,按照之前线性拟合的假设形式,我们可以写成:
特征值设置为:
通过上面一些简单的改变,我们就可以把多项式回归转换为了我们熟悉的线性回归,进行特征值放缩后再用梯度下降算法求解即可。
多元梯度下降代码
import numpy as np
from numpy import genfromtxt
import pandas as pd
import matplotlib.pyplot as plt
#读取数据(用的是例题数据)
data = pd.read_csv('C:\\Users\\Lenovo\\Desktop\\room.csv')
#特征值放缩
data = (data - data.mean()) / data.std()
# 增加一列1
data.insert(0, 'Ones', 1)
#数据处理
x_data = np.array(data.iloc[:, 0:-1]) #取不包含最后一列的所有数据,并转化为数组,不然不能进行下面的运算
y_data = np.array(data.iloc[:,-1]).reshape(4,1) #取最后一列数据
theta = np.array([0,0,0,0,0]).reshape(5,1) #θ参数初始化为0
#参数设置
alpha = 0.003#学习率
iternum = 1000 #最大迭代次数
m = 4 #样本数
#代价函数
def cost_function(theta,x_data,y_data):
inner = np.power((dot(x_data , theta) - y_data),2)#这里看成矩阵运算
return np.sum(inner) / (2 * m) #对数组求和除以2和样本数就是代价函数
#代价函数的偏导
def gradient_function(theta,x_data,y_data,m):
return (1/m) * dot(x_data.transpose(), (dot(x_data , theta) - y_data))#这是对代价函数求偏导后的结果
#核心算法,梯度下降
def gradient_desent(x_data, y_data, theta, alpha, m):
gradient = gradient_function(theta,x_data,y_data ,m)
cost = np.zeros(iternum)#保存下来用于绘制学习曲线
i = 0
while not all(abs(gradient) <= 0.0001): #若偏导小于0.0001,这时相当于0,也就是正切为零,找到局部最优解
if(i >=iternum): #到达最大迭代次数,也终止迭代
break
theta = theta - alpha * gradient #更新参数的值
cost[i] = cost_function(theta,x_data,y_data) #记录每次迭代后最小化代价函数的值
i = i+1 #记录迭代次数
gradient = gradient_function(theta,x_data,y_data ,m) #更新偏导
return theta,cost
theta_end1,cost = gradient_desent(x_data, y_data, theta, alpha, m)#调用函数,求解参数
#画出代价函数与迭代次数的学习曲线,看看梯度下降是否正常运行,选择合适的学习率
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iternum), cost, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()
正规方程
正规方程也叫最小二乘法,其实就是通过求导来确定代价函数的极小值。
我们假设一个代价函数,函数图像如下图:
我们只需要对代价函数求导并令其等于0,就能解出使得取最小值的
值
同样的,当是一个
维的参数向量时,对所有参数逐一求导即可:
但如果参数太多,这样遍历求解会很耗费时间,下面再看看其他方法,还是用上面的例子做引入
面积(平方英尺) | 房间数 | 层数 | 住房年龄(年) | 价格($1000) |
---|---|---|---|---|
2104 | 5 | 1 | 45 | 460 |
1416 | 3 | 2 | 40 | 232 |
1534 | 3 | 2 | 30 | 315 |
852 | 2 | 1 | 36 | 178 |
现在我们在数据集中额外加入,并令其等于1
面积(平方英尺) | 房间数 | 层数 | 住房年龄(年) | 价格($1000) | |
---|---|---|---|---|---|
1 | 2104 | 5 | 1 | 45 | 460 |
1 | 1416 | 3 | 2 | 40 | 232 |
1 | 1534 | 3 | 2 | 30 | 315 |
1 | 852 | 2 | 1 | 36 | 178 |
现在我们构建一个m×(n+1)的矩阵,和一个m维向量
:
因此有
但不是方阵,没有逆矩阵,不能直接求
,所以我们可以两边同时左乘
,变成:
现在是方阵了,也是可逆的,那么就可以求得
正规方程代码
数据的前期处理和梯度下降一样,这里就不重复写了
#正规方程
def normalEqn(x_data,y_data):
#核心算法
theta = np.linalg.inv(np.transpose(x_data)@x_data)@np.transpose(x_data)@y_data
return theta
final_end2 = normalEqn(x_data, y_data)
梯度下降与正规方程的选择
假设有m个训练样本和n个特征值
梯度下降 | 正规方程 | |
---|---|---|
缺点 | 需要选择学习率、需要多次迭代 | 若n很大,高维矩阵求逆会花费大量时间 |
所以当n较小时(例如以10000为界限),可选择正规方程,较大时可选择梯度下降
参考资料:
版权声明:本文为博主大拨鼠原创文章,版权归属原作者,如果侵权,请联系我们删除!
原文链接:https://blog.csdn.net/watermelon_c/article/details/122582951