c0d3n4m 发表于 2022-8-6 11:04

梯度下降

一、了解梯度下降优化算法
梯度下降优化算法作用:用来对原始模型的损失函数进行优化,以便寻找到最优的参数,使得损失函数的值最小。
梯度下降优化算法理解:梯度指向误差值增加最快的方向,导数为0(梯度为0向量)的点,就是优化问题的解。
损失函数值迭代公式: (a_{k+1},b_{k+1})=(a_{k+1}-\eta\frac{\partial L}{\partial a},b_{k+1}-\eta\frac{\partial L}{\partial b})
关于参数 \eta :我们已经知道,梯度对应的是下山的方向,而参数 \eta 对应的是步伐的长度。在学术上,我们称之为“学习率”(learning rate),是模型训练时的一个很重要的超参数,能直接影响算法的正确性和效率

[*]首先,学习率 \eta 不能太大。因此从数学角度上来说,一阶泰勒公式只是一个近似的公式,只有在学习率很小,也就是 \Delta a,\Delta b 很小时才成立。并且从直观上来说,如果学习率 \eta 太大,那么有可能会“迈过”最低点,从而发生“摇摆”的现象(不收敛),无法得到最低点
[*]其次,学习率 \eta 又不能太小。如果太小,会导致每次迭代时,参数几乎不变化,收敛学习速度变慢,使得算法的效率降低,需要很长时间才能达到最低点。
梯度算法缺点:在很多复杂函数中有很多极小值点,我们使用梯度下降法只能得到局部最优解,而不能得到全局最优解,对于梯度下降来说,初始点的位置,也是一个超参数。
解决方案:首先随机产生多个初始参数集,即多组;然后分别对每个初始参数集使用梯度下降法,直到函数值收敛于某个值;最后从这些值中找出最小值,这个找到的最小值被当作函数的最小值。当然这种方式不一定能找到全局最优解,但是起码能找到较好的。
二、手动实现梯度算法
python中有两种常见求导的方法,一种是使用Scipy库中的derivative方法,另一种就Sympy库中的diff方法。
三、线性回归中的梯度下降
最终得到梯度结果为: ▽J(\theta)=\frac{2}{m}X_{b}^{T}(x_{b}\theta-y)
代码演示
def fit_gd(self, X_train, y_train, eta=0.01, n_iters=1e4):
    """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型"""
    assert X_train.shape == y_train.shape, \
      "the size of X_train must be equal to the size of y_train"

    def J(theta, X_b, y):
      try:
            return np.sum((y - X_b.dot(theta)) ** 2) / len(y)
      except:
            return float('inf')
      
    def dJ(theta, X_b, y):
      return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)

    def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):

      theta = initial_theta
      cur_iter = 0

      while cur_iter < n_iters:
            gradient = dJ(theta, X_b, y)
            last_theta = theta
            theta = theta - eta * gradient
            if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
                break

            cur_iter += 1

      return theta

    X_b = np.hstack()
    initial_theta = np.zeros(X_b.shape)
    self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)

    self.intercept_ = self._theta
    self.coef_ = self._theta

    return self在本篇文章中,对多元线性回归的损失函数进行求导,其结果是 \frac{2}{m}(X_{b}\theta-y)^{T}X_{b}
然后使用向量化的方式编写代码,但是发现在真实数据中效果比较差,这是因为数据的规模不一样,因此在梯度下降之前需要使用归一化。
数据归一化:
from sklearn.preprocessing import StandardScaler

standardScaler = StandardScaler()
standardScaler.fit(X_train)
X_train_std = standardScaler.transform(X_train)
lin_reg3 = LinearRegression()
lin_reg3.fit_gd(X_train_std, y_train)
X_test_std = standardScaler.transform(X_test)
lin_reg2.score(X_test, y_test)四、随机梯度下降法SGD
批量梯度下降法,每一次计算过程,都要将样本中所有信息进行批量计算。但是显然如果样本量很大的话,计算梯度就比较耗时。基于这个问题,改进的方案就是随机梯度下降法。即每次迭代随机选取一个样本来对参数进行更新。使得训练速度加快。
对损失函数的进行求导,得到的结果为: 2(X_{b}^{(i)})^{T}(X_{b}^{(i)}-y^{(i)})
批量梯度下降法BGD(Batch Gradient Descent)。

[*]优点:全局最优解;易于并行实现;
[*]缺点:当样本数据很多时,计算量开销大,计算速度慢。
针对于上述缺点,其实有一种更好的方法:随机梯度下降法SGD(stochastic gradient descent),随机梯度下降是每次迭代使用一个样本来对参数进行更新。

[*]优点:计算速度快;
[*]缺点:收敛性能不好
五、总结
批量梯度下降法BGD(Batch Gradient Descent)。

[*]优点:全局最优解;易于并行实现;
[*]缺点:当样本数据很多时,计算量开销大,计算速度慢。
针对于上述缺点,其实有一种更好的方法:随机梯度下降法SGD(stochastic gradient descent),随机梯度下降是每次迭代使用一个样本来对参数进行更新。

[*]优点:计算速度快;
[*]缺点:收敛性能不好
页: [1]
查看完整版本: 梯度下降