跳转至

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

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

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

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

评论