跳转至

当梯度下降陷入局部最优解

应用梯度下降法时,损失函数的值不再发生变化并不一定是找到了全局最优解,可能是陷入了局部最优解。为当前参数加上一个微小扰动,可以帮助跳出局部最优解。

image-20221229225045209

梯度下降陷入局部最优解

问题背景

在应用梯度下降法求解最优参数时,除了设置最大迭代次数,还可以通过损失值的变化情况来判断是否可以终止迭代。

Python
def gradient_descent(self, x, y, alpha=0.5, c=0.5, beta_initial=None):
        """

        Args:
            x: 所有样本的特征
            y: 所有样本的标签
            alpha: 回溯线性搜索的参数
            c: 回溯线性搜索的参数
            beta_initial: 待优化的参数的初始值,默认为全零向量

        Returns:
            beta: 迭代后的最优参数

        """
        # 初始化损失函数值
        self.loss = []
        # 初始化待优化的参数
        if beta_initial is None:
            beta = np.zeros(x.shape[1])
        else:
            beta = beta_initial
        # 迭代求解
        for k in range(self.K):
            # 计算梯度
            gradient_beta = self.gradient(x, y, beta, self.lambda_)
            # 计算回溯线性搜索的步长
            t = 1
            while self.f(x, y, beta - t * gradient_beta, self.lambda_) > self.f(x, y, beta, self.lambda_) - alpha * t * gradient_beta.T.dot(gradient_beta):
                t = c * t
            # 更新参数
            beta = beta - t * gradient_beta
            # 记录损失函数的值
            self.loss.append(self.f(x, y, beta, self.lambda_))
            # 终止条件:至少迭代了 100 轮,且损失函数的值在最近 2 轮的迭代中变化小于 1e-6
            if k > 100 and abs(self.loss[-2] - self.loss[-1]) < 1e-6:
                break
        # 将参数值小于 1e-3 的置为 0
        beta[np.abs(beta) < 1e-3] = 0

        return beta

注意,上面的代码中,我设置了最大迭代次数为K=10000,同时也设置了终止条件:

Python
# 终止条件:至少迭代了 100 轮,且损失函数的值在最近 2 轮的迭代中变化小于 1e-6
if k > 100 and abs(self.loss[-2] - self.loss[-1]) < 1e-6:
    break

梯度下降法的收敛值与其他两种方法不一致

绘制损失函数值随迭代次数的变化情况,发现梯度下降法的收敛速度很快,仅 102 轮迭代便收敛。

随机梯度下降法、坐标下降法的损失函数几乎都收敛到同一位置,约\(0.365\),但梯度下降法的损失函数却约为\(0.4\)

image-20221229225045209

猜测梯度下降法可能陷入了局部最优解。

加入随机扰动,帮助跳出局部最优

不记得在哪里学到的这个方法(可能是吴恩达的机器学习视频,或是某次学术讲座)。在观察到损失函数值不发生变化时,可以对当前参数加上一个随机扰动项,帮助跳出局部最优。

我们需要修改之前终止迭代的代码:

Python
# 改变当前值的条件:至少迭代了 100 轮,且损失函数的值在最近 2 轮的迭代中变化小于 1e-6
if k > 100 and abs(self.loss[-2] - self.loss[-1]) < 1e-6:
    # 为每个分量加上噪音 N(0, 1e-2)
    beta = beta + np.random.normal(0, 1e-2, beta.shape)

image-20221229225745200

此时三种梯度下降的方法几乎都收敛到同一值,说明随机扰动帮助我们跳出了局部最优!

评论