本篇博客承接本人上一篇关于逐步回归算法的引伸,本篇将开始整理梯度降低算法的相关知识。梯度降低,gradient descent(以后将简称GD),是一种经过迭代找最优的方式一步步找到损失函数最小值的算法,基本算法思路可总结为以下几点:python
(1) 随机设置一个初始值算法
(2) 计算损失函数的梯度dom
(3) 设置步长,步长的长短将会决定梯度降低的速度和准确度,以后会详细展开函数
(4) 将初值减去步长乘以梯度,更新初值,而后将这一过程不断迭代优化
仍是老规矩,先从二维平面场景开始,由易到难,步步深刻,先上图:lua
为了方便思考,咱们求解的是对上述函数图像的任意一个点来讲,沿着哪一个方向走可以使得该函数的y上升幅度最大,那么逆向思惟,该方向一旦求得,该方向的反方向不就是使得y降低速度最快的方向了吗?好,沿着这个思路继续,因为这个方向是咱们要求的,不妨设该方向与x轴的夹角为
,如今咱们沿着这个方向走
的距离,将该向量正交分解可知,它只有在水平方向上的份量才会提供使得函数值发生变化的效果,竖直方向上份量不产生任何效果,因而可得如下函数值变化量函数:spa
显然,当 为0,也就是水平正方向时,可以使得该函数值上升最快,也就是说水平负方向可以使得该函数值降低最快,至此,二维平面上的使得函数值降低最快的方向咱们就找到了:code
现将该问题拓展至三维空间上,由以前的证实可知,对于函数来讲,某向量在y轴上的份量不会提供使得函数值发生变化的效果,那么将此结论扩展,对于函数
来讲,某向量在z轴上的份量也不会提供使得函数值发生变化的效果,所以,咱们能够这样说,该问题的最终解必落在xoy平面内,而与z轴无关!现正式开始证实blog
设为xoy平面上的一个向量,该向量与x轴的夹角为
,则它在x轴和y轴上的份量为:get
x轴和y轴的变化共同引发了z轴方向上的变化,由此可得:
利用向量的思想,将上式表示成两个向量内积的结果,可得:
第一个向量其实就是向量,而第二个向量就是函数
在某点上的梯度
,所以上式最终就可转换成:
设上式中两个向量的夹角为α,根据向量内积公式,又可表示成:
该式中,当α为0时达到最大值,也就是说,与梯度相同的方向是使得函数值上升最快的方向,换句话来讲,与梯度相反的方向是使得函数值降低最快的方向!!!
结合上一篇博客中提到的高维空间下的SSE的计算,咱们直接引用以前的结论:
若采用梯度降低法求解最小值,只需沿着上式的方向进行试探便可
目前常见的求解梯度降低法的方式有三种,BGD,Batch Gradient Descent,批量梯度降低法,SGD,Stochastic Gradient Descent,随机梯度降低法,以及MBGD,Mini-Batch Gradient Descent,小批量梯度降低法。因为最为普通的批量梯度降低法是每次迭代都是对于全量的数据来讲的,若初值选的不巧就比较容易陷入一个局部(local)最优而不是全局(global)最优的解中去,所以出现了一个更为优化的算法来解决这个问题,那就是随机梯度降低法,在SGD中,每一个循环只随机选取一个样本进行迭代,所以对于BGD来讲,训练模型的速度明显快上了许多,但因为每次仅仅选用一个样本,样本量不够,所以不可以很快收敛到最优解,值得一提的是,因为该算法的随机性,在面对非凸函数时,能很好地避免陷入局部最优的状况,所以比BGD效果更好;而后这两种算法都比较极端,要么每次选择所有,要么每次只选一个,有没有一种折中的算法呢?答案是确定的,那就是MBGD,小批量梯度降低法,每次选择的样本量是在整体中进行一次抽样,通常以比例的方式抽取最佳。
虽然说在实际写代码的时候,步长是咱们本身设定的,但对于步长究竟选择多少合适,主要有两点考量。
1. 步长太小会致使一步步迭代到最优值的过程会很是长,不过结果会较为精确,须要注意的是,假若迭代次数不够,就会致使最终结果每每不是最优解
2. 步长过长虽然可使得迭代过程缩短,可是对于精度丢失会比较大,而且最终解颇有可能会在最有点两侧来回跳动,致使始终接近不了最优解
咱们使用python将这三种算法写进一个包中,功能是使用梯度降低法来纠结回归方程SSE的最小值,具体代码以下所示:
import numpy as np import pandas as pd class regression: def __init__(self, data, intercept = True): self.X = np.mat(data.iloc[:,:-1].values) self.Y = np.mat(data.iloc[:,-1].values).T self.data = data self.intercept = intercept def BGDfit(self, lam, iternum): #This function aims to use batch gradient descent algorithm to get the minimum value theta = np.mat(np.zeros((self.X.shape[1], 1))) for _ in range(iternum): grad = 2 / self.X.shape[0] * (self.X.T * (self.X * theta - self.Y)) theta -= lam * grad return np.ravel(theta) def SGDfit(self, lam, iternum): #This function aims to use stochastic gradient descent algorithm to get the minimum value theta = np.mat(np.zeros((self.X.shape[1], 1))) for _ in range(iternum): rnd_num = np.random.randint(self.X.shape[0]) grad = 2 / self.X.shape[0] * (self.X[rnd_num].T * (self.X[rnd_num] * theta - self.Y[rnd_num])) theta -= lam * grad return np.ravel(theta) def MBGDfit(self, lam, iternum): #This function aims to use mini-batch gradient descent algorithm to get the minimum value theta = np.mat(np.zeros((self.X.shape[1], 1))) temp_X = pd.DataFrame(self.X) for _ in range(iternum): X_index = temp_X.sample(frac = 0.1, replace = False).index X_mini = self.X[X_index, :] Y_mini = self.Y[X_index] grad = 2 / X_mini.shape[0] * (X_mini.T * (X_mini * theta - Y_mini)) theta -= lam * grad return np.ravel(theta) def evaluate(self, coef): #This function aims to calculate SSE and R2 in order to evaluate whether the model is accurate or not Y_pred = self.X * np.mat(coef).T SSE = np.power(np.ravel(self.Y) - np.ravel(Y_pred), 2).sum() SST = np.power(np.ravel(self.Y) - np.ravel(self.Y).mean(), 2).sum() R2 = 1 - SSE / SST return SSE, R2