Java教程

线性回归中的梯度爆炸

本文主要是介绍线性回归中的梯度爆炸,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

2021年秋季第四周周报内容


0. 前言

古人说: “ 温故而知新, 可以为师矣.” 刚好自己也有点时间, 就把几个月前敲过的代码又敲了一遍.  

1. nan? inf?

这是一个非常基础的一元线性回归代码, 照着西瓜书公式就可以直接敲出来的那种. 重新在网上找了一个数据集, 如图所示: 

虽然说分布有点散, 但是总归还是能找到一条线来拟合的嘛.

然后运行, 不对劲了. 结果给我输出这个:

theta1 is:  -1.1121132929727208e+169
theta0 is:  -2.1858247925415553e+167
loss is:  inf

再看图像...

这误差已经大得离谱, 已经是无穷大了.

接着, 我把这数据用另外一个代码跑了一下, 输出loss.

loss:  2782.553917241607
loss:  1.5311494984548842e+279
loss:  inf
loss:  nan
loss:  nan
loss:  nan
loss:  nan
loss:  nan
loss:  nan
loss:  nan

 nan : Not a number

并且还出现了 RuntimeWarning 的警告, 为啥损失会这么大, 突然我想到一个词: "梯度爆炸"

3. 梯度爆炸

什么是梯度爆炸?

梯度的衰减是有连续乘法导致的, 如果在连续乘法中出现一个非常大的值, 最后计算出的梯度就会很大, 就想当优化到断崖处时, 会获得一个很大的梯度值, 如果以这个梯度值进行更新, 那么这次迭代的步长就很大, 可能会一下子飞出了合理的区域.

意思就是说, 咱们的 theta 在迭代时, 一直在变大. 看看公式,

损失函数: \( J(w_0, \dots, w_n) \) 

梯度下降: \( w_j = w_j - \alpha * \frac{\partial}{\partial w_j} J \) 

写成矩阵形式: \(\mathbf{w} = [ w_0,\dots, w_n ]^{\mathrm{T}} = \mathbf{w} - \alpha * \frac 1m * (\mathbf{X}^{\mathrm{T}} ( \mathbf{X} \mathbf{w} - \mathbf{Y}) ) \)  

根据上面的解释, 影响的因素可能包含

1) 学习率 \( \alpha \)

2) 初始权重 \( \mathbf{w} \)

3) \( \mathbf{X} , \mathbf{Y} \) 

此处, 初始权重都设为 0. 

3.1 学习率

Test 1: \(\alpha = 0.01 , \rm{numiter} = 100. \)  \(\rm{numiter}\) indicates the number of iterations.

失败.

 Test 2: \(\alpha = 0.001 , \rm{numiter} = 100. \)

 失败.

 Test 3:  \(\alpha = 0.0001 , \rm{numiter} = 100. \)

 根据上图来看, 好像是下降成功了.

theta1 is:  1.4788027175308358
theta0 is:  0.03507497059234175
loss  is : 112.64709271657506

 

根据上图来看, 确实拟合出来了一条直线.

之后我又做了一系列的测试, 当学习率 \( \alpha \leq 0.0001 \)时, 调整迭代次数, 总归能够拟合出来一条直线. 误差大约为112.

 结论: 学习率\( \alpha \) 会影响梯度的下降, \(\mathbf{w}\)的更新.

 3.2 数据

数据的值太大会影响梯度下降吗?假设会的话, 那我就把它缩小. 下面就介绍两种常用的特征缩放方式.

1. Min-Max Normalization(min-max标准化)

$$x^*= \frac{x - min(x)} {max(x) - min(x)}$$

其实质是将数据映射到 [0, 1] 之间.

2. Standarddization(z-score标准化)

$$x^* = \frac{x - \mu} {\sigma}$$

其中 \( \mu \)为均值, \( \sigma \)为标准差, 实质是使数据符合标准正态分布.

我们采用第二种方法, 

def z_score(x):
    """
    feature scaling

    :param x: the feature need to scale
    :return: the feature after standardization
    """
    sum1 = 0
    sum2 = 0
    n = len(x)

    # calculate mu
    for i in range(n):
        sum1 += x[i]
    mu = sum1 / n

    # calculate sigma
    for i in range(n):
        sum2 += (x[i] - mu) ** 2
    sigma = (sum2 / n) ** 0.5

    x = (x - mu) / sigma
    return x

处理之后, 我们再做测试.

Test 4:  \(\alpha = 0.01 , \rm{numiter} = 100. \)

theta1 is:  11.123553842945782
theta0 is:  63.088960451274154
cost  is : 210.15286292756554

 

与Test 1相比, 它拟合出来了一条直线, 并且误差为210左右. 误差应该还可以减少, 增加迭代次数看看.

Test 5: \(\alpha = 0.01 , \rm{numiter} = 500. \)

theta1 is:  12.823781751169484
theta0 is:  72.73206667205297
cost  is : 110.25739302507955

 误差减小到了110.25 左右. 之后我又做了一系列测试, 最终误差维持在为110.25左右.

结论: 数据值的大小会影响线性回归中梯度的下降.

4. 特征缩放

关于特征缩放, 吴恩达教授是这样讲的:

未进行归一化:

 它会是这样一个狭长的函数. 在这样的损失函数上运行梯度下降法, 必须使用一个非常小的学习率. 并且如果初始位置设在这, 梯度下降法可能需要多次迭代.

相反地, 特征缩放后, 它会是一个更圆的球星轮廓, 那么无论从哪个位置开始, 梯度下降法都能够更直接地找到最小值, 并且可以使用较大步长.

 5. 小结

特征缩放优点:

(1)缩放后加快了梯度下降求最优解的速度.

(2)缩放有可能提高精度(归一化是让不同维度之间的特征在数值上有一定的比较性).

若出现梯度爆炸现象, 首先去看迭代式子!


你可能会觉得奇怪, 做个简单的线性回归怎么还会扯上梯度爆炸. 你若不信, 可以用sklearn.datasets 中的波士顿数据去做个线性回归, 前提是不对数据进行处理, 试一试能不能直接拟合出一个预测函数. 

当然, 若文章所述有误, 也欢迎批评指正!

参考:

机器学习-数据归一化方法

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于线性回归中的梯度爆炸的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!