介绍
梯度下降法,又称最速下降法,是求解无约束最优化问题最常用的方法,它是一种迭代方法,每一步主要的操作是求解目标函数的梯度向量,将当前位置的负梯度方向作为搜索方向(因为在该方向上目标函数下降最快,这也是最速下降法名称的由来)。
直观解释
将函数比作一座山,我们站在某个山坡上,往四周看,从哪个方向向下走一小步,能够下降的最快。
同样,如果从任意一点出发,需要最快搜索到函数最大值,那么我们也应该从函数变化最快的方向搜索。
函数的梯度:函数变化最快的方向
梯度下降法特点:越接近目标值,步长越小,下降速度越慢。
直观上来看如下图所示:
如果函数为一元函数,梯度就是该函数的导数
如果是二元函数,梯度的表示方法
梯度下降数学表示:
:是函数关于w的导数
如果需要找的是函数极小点,那么应该从负梯度的方向寻找,该方法称之为梯度下降法。
例如:
批量梯度下降BGD(使用所有样本进行计算,慢但准确度好)
按照传统的思想,我们需要对上述损失函数中的每个求其偏导数,得到每个对应的梯度
这里表示第i个样本点的第j分量,即h(θ)中的
接下来由于我们要最小化损失函数,故按照每个参数的负梯度方向来更新每一个
这里的α表示每一步的步长 (步长适中,太小的话,可能导致迟迟走不到最低点,太大的话,会导致错过最低点)
优点:全局最优解;易于并行实现。
缺点:当样本数目很多时,训练过程会很慢,每次迭代需要耗费大量的时间,总体迭代次数多。
随机梯度下降SGD(样本多,但每次使用一个样本,准确度欠缺)
其中,
样本点 的损失函数
然后得到每个梯度,最后更新下一个梯度。
优点:训练速度快,每次迭代计算量不大
缺点:准确度下降;不易于并行实现;总体迭代次数比较多。
算法收敛判断方法
参数ΘT的变化距离为0,或者说变化距离小于某一阈值(ΘT中每个参数的变化绝对值都小于一个阈值)。为减少计算复杂度,该方法更为推荐使用。
J(Θ)不再变化,或者说变化程度小于某一阈值。计算复杂度较高,但是如果为了精确程度,那么该方法更为推荐使用。
小批的梯度下降
这种方法把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性。另一方面因为批的样本数与整个数据集相比小了很多,计算量也不是很大。
梯度下降算法代码(借来的)
import numpy as np
import matplotlib.pyplot as plt
def create_sample_set():
"""
生成样本数据集
:return:
"""
x = np.arange(0, 100, 1)
y = x * 11.8 - np.random.standard_normal(100) * 100
return x, y
def loss(weight, x, y):
"""
损失函数使用均方误差
:param weight:权重
:param x:
:param y:
:return:
"""
return (x * weight - y).T * (x * weight - y)
def gradient(weight, x, y):
"""
基于损失函数求关于w的导数
:param weight:
:param x:
:param y:
:return:
"""
return x.T * (x * weight - y)
def gradient_descent(x, y, max_iter=10, learning_rate=0.001):
"""
梯度下降求解
:param x:
:param y:
:param max_iter:
:param learning_rate:
:return:
"""
m, n = np.shape(x)
weight = np.mat(np.ones((n, 1)))
loss_arr = []
weight_arr = np.zeros((max_iter,n))
for i in range(max_iter):
g = gradient(weight, x, y)
weight = weight - learning_rate * g
error = loss(weight, x, y).T.tolist()[0][0]
loss_arr.append(error)
weight_arr[i, :] = weight.T
print("迭代 {} 损失:{},weight参数:{}".format(i + 1, error, weight.T.tolist()))
return weight,loss_arr,weight_arr
if __name__ == '__main__':
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
features, labels = create_sample_set()
X = np.ones((2, 100))
X[1] = np.mat(features)
X = X.T
Y = labels.reshape(100, 1)
weights,loss_array,weights_array = gradient_descent(X, Y, learning_rate=0.000001)
# 绘制曲线
fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax1.set_title("样本数据分布" )
ax1.scatter(features, labels)
ax2 = fig.add_subplot(2, 2, 2)
ax2.set_title("梯度下降拟合效果" )
ax2.scatter(features, labels)
ax2.plot(features, (X * weights).T.tolist()[0])
ax3 = fig.add_subplot(2, 2, 3)
ax3.set_title("随着迭代次数增加loss走势")
ax3.plot(range(len(loss_array)), loss_array)
ax4 = fig.add_subplot(2, 2, 4)
ax4.set_title("随着迭代数增加学习的参数逐渐稳定")
ax4.plot(np.array(weights_array))
plt.show()
运行结果: