梯度下降算法 - Python实现
Posted LOGAN_XIONG
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了梯度下降算法 - Python实现相关的知识,希望对你有一定的参考价值。
- 算法介绍:
梯度下降算法是一种利用一次导数信息求取目标函数极值的方法,也是目前应用最为广泛的局部优化算法之一。其具有实现简单、容易迁移、收敛速度较快的特征。在求解过程中,从预设的种子点开始,根据梯度信息逐步迭代更新,使得种子点逐渐向目标函数的极小值点移动,最终到达目标函数的极小值点。
注意,沿梯度正向移动,将获取目标函数局部极大值(梯度上升算法);沿梯度反向移动,将获取目标函数局部极小值(梯度下降算法)。 - 迭代公式:
设向量$\\vec g_k$表示目标函数在种子点$\\vec x_k$处的梯度(即一次导数)。此时,根据梯度信息的指导,可以使得种子点更加接近该向量方向的极值点(注意,目标函数真实的极值点是全方向的)。
求取极小值,沿梯度反方向移动(即梯度下降):
\\begin{equation}\\label{eq_1}
\\vec x_{k+1} = \\vec x_k - {\\lambda}_k \\vec s_k
\\end{equation}
求取极大值,沿梯度正方向移动(即梯度上升):
\\begin{equation}\\label{eq_2}
\\vec x_{k+1} = \\vec x_k + {\\lambda}_k \\vec s_k
\\end{equation}
其中,$\\vec s_k = \\frac{\\vec g_k}{\\left| \\vec g_k \\right|}$代表归一化梯度,${\\lambda}_k$代表种子点沿梯度方向移动的步长幅度参数。
很显然,对幅度参数${\\lambda}_k$的设置也属于算法的一部分。最常见的有两种方法:1)线性搜寻法;2)可调步长法。
线性搜寻法中,在种子点的梯度方向上搜寻到极值点附近的步长幅度参数${\\lambda}_k$,然后移动种子点至该方向的极值点处。继续计算种子点新的梯度方向,并在该方向上移动。直到种子点到达全方向的极值点处,迭代即可终止。
可调步长法中,通常先将${\\lambda}_k$设为1。然后依据上面的迭代公式(式$\\ref{eq_1}$或式$\\ref{eq_2}$),预先计算下一步可能的$x_{k+1}$。如果$x_{k+1}$满足接近极值点的要求,则将种子点由$x_k$移至$x_{k+1}$,并增加${\\lambda}_k$值为原先的$1.2$倍;否则,不移动种子点,并将${\\lambda}_k$值减小为原先的$0.5$倍。如此反复迭代计算,逐步移动种子点并改变${\\lambda}_k$值至找到极值点为止。由于${\\lambda}_k$值随下一步的预计算情况逐步作出调整,因此笔者也将其称为动态调整技术。
从节省计算资源的角度考虑,以下笔者将采用动态调整技术完成对梯度下降算法的示例,仅供参考! - Python代码实现:
1 import matplotlib.pyplot as plt 2 import numpy 3 4 5 class GD(object): 6 7 def __init__(self, seed=None, precision=1.E-6): 8 self.seed = GD.get_seed(seed) # 梯度下降算法的种子点 9 self.prec = precision # 梯度下降算法的计算精度 10 11 self.path = list() # 记录种子点的路径及相应的目标函数值 12 self.solve() # 求解主体 13 self.display() # 数据可视化展示 14 15 def solve(self): 16 x_curr = self.seed 17 val_curr = GD.func(*x_curr) 18 self.path.append((x_curr, val_curr)) 19 20 omega = 1 21 while omega > self.prec: 22 x_delta = omega * GD.get_grad(*x_curr) 23 x_next = x_curr - x_delta # 沿梯度反向迭代 24 val_next = GD.func(*x_next) 25 26 if numpy.abs(val_next - val_curr) < self.prec: 27 break 28 29 if val_next < val_curr: 30 x_curr = x_next 31 val_curr = val_next 32 omega *= 1.2 33 self.path.append((x_curr, val_curr)) 34 else: 35 omega *= 0.5 36 37 def display(self): 38 print(\'Iteration steps: {}\'.format(len(self.path))) 39 print(\'Seed: ({})\'.format(\', \'.join(str(item) for item in self.path[0][0]))) 40 print(\'Solution: ({})\'.format(\', \'.join(str(item) for item in self.path[-1][0]))) 41 42 fig = plt.figure(figsize=(10, 4)) 43 44 ax1 = plt.subplot(1, 2, 1) 45 ax2 = plt.subplot(1, 2, 2) 46 47 ax1.plot(numpy.array(range(len(self.path))) + 1, numpy.array(list(item[1] for item in self.path)), \'k.\') 48 ax1.plot(1, self.path[0][1], \'go\', label=\'starting point\') 49 ax1.plot(len(self.path), self.path[-1][1], \'r*\', label=\'solution\') 50 ax1.set(xlabel=\'$iterCnt$\', ylabel=\'$iterVal$\') 51 ax1.legend() 52 53 x = numpy.linspace(-100, 100, 500) 54 y = numpy.linspace(-100, 100, 500) 55 x, y = numpy.meshgrid(x, y) 56 z = GD.func(x, y) 57 ax2.contour(x, y, z, levels=36) 58 59 x2 = numpy.array(list(item[0][0] for item in self.path)) 60 y2 = numpy.array(list(item[0][1] for item in self.path)) 61 ax2.plot(x2, y2, \'k--\', linewidth=2) 62 ax2.plot(x2[0], y2[0], \'go\', label=\'starting point\') 63 ax2.plot(x2[-1], y2[-1], \'r*\', label=\'solution\') 64 65 ax2.set(xlabel=\'$x$\', ylabel=\'$y$\') 66 ax2.legend() 67 68 fig.tight_layout() 69 fig.savefig(\'test_plot.png\', dpi=500) 70 71 plt.show() 72 plt.close() 73 74 # 内部种子生成函数 75 @staticmethod 76 def get_seed(seed): 77 if seed is not None: 78 return numpy.array(seed) 79 return numpy.random.uniform(-100, 100, 2) 80 81 # 目标函数 82 @staticmethod 83 def func(x, y): 84 return 5 * x ** 2 + 2 * y ** 2 + 3 * x - 10 * y + 4 85 86 # 目标函数的归一化梯度 87 @staticmethod 88 def get_grad(x, y): 89 grad_ori = numpy.array([10 * x + 3, 4 * y - 10]) 90 length = numpy.linalg.norm(grad_ori) 91 if length == 0: 92 return numpy.zeros(2) 93 return grad_ori / length 94 95 96 if __name__ == \'__main__\': 97 GD()
笔者所用示例函数为:
\\begin{equation}
f(x, y) = 5x^2 + 2y^2 + 3x - 10y + 4
\\end{equation} - 结果展示:
以上是关于梯度下降算法 - Python实现的主要内容,如果未能解决你的问题,请参考以下文章
python逻辑回归(logistic regression LR) 底层代码实现 BGD梯度下降算法 softmax多分类