梯度下降所带来的问题——迭代发散

815 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

对于梯度下降算法,我们知道α值过小时,每次下降的程度非常小,导致接近最小值的过程较长,而当α值过大时,就特别容易发散。

对于α值的设置需要十分小心。我通过拟合一元线性回归时,使用梯度下降算法不断最小化损失函数

J(θ0,θ1)=12mi=1m(hθ(x(i))y(i))2J(θ_0,θ_1)=\frac{1}{2m}\sum_{i=1}^m(h_θ(x^{(i)})−y^{(i)})^2

其中的偏导项是

J(θ0,θ1)θj=1mi=0m(hθ(xi)yi)xji\begin{aligned} \frac{\partial J(θ_0,θ_1)}{\partial\theta_j} = \frac1m\sum_{i=0}^m(h_\theta(x^i)-y^i)x^i_j \end{aligned}

最开始数据通过标准化方程直接求解得到的数据

Y=0.047x+7.03Y = 0.047x+7.03

之后尝试使用梯度下降算法求损失函数最小值,系数初值为0

α值设置为0.0001

所得到的最终值直接发散,函数走势如图 在这里插入图片描述

尝试减小α值为0.00001

此时并未发散,a = 0.082 b=0.17与期望值相差特别多,其走势如图 在这里插入图片描述

可见下降速度十分慢,迭代10000效果并不理想

将α值设为0.0006时结果为 a=0.078 b=0.99,走势如图 在这里插入图片描述

也许你会想,再加大一点α值,会收敛的更快,但是只加了0.00001

也就是α值为0.00007时,迭代发散了…… 在这里插入图片描述

当试着减少0.000001时,也就是α值为0.000069时,迭代并没有发散,但所带来的结果仅为 a = 0.07 b=1.12 与期望值0.04与7.03相差实在太多,而最小值下降的速度实在是太慢,10000次仅下降至最小值的一半(α=0.0000699 同样会发散 >_<) 在这里插入图片描述

只有将初值设置为[7,0]期望值附近时所得到的迭代速度才会更加迅速 在这里插入图片描述

尝试了多种解决方案后终于找到一个方式,将原始数据归一化

将数据归一化后得到的期望值为

Y=4.071X+14.022Y = 4.071X+14.022

而使用梯度下降算法时,最开始也是尝试比较小的α值,比如0.00006,0.00007,发现并为再次出现发散的情况,但收敛速度也是极慢,之后经过尝试直接将α值增大至0.01此时依旧没有发散,而且收敛效果非常好,结果为

Y=4.070X+14.021Y=4.070X+14.021

基本吻合期望值,函数下降趋势如图,下降效果十分明显 在这里插入图片描述

代码如下:

# coding=utf-8
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn import linear_model
df = pd.read_csv('adver.csv')
Y = df.iloc[:,3]
X = df.iloc[:,0]
# plt.scatter(x=X,y=Y)
# plt.show()
my = np.mean(Y)
mx = np.mean(X)
dx = (X-mx)/np.std(X)
dy=(Y-my)/np.std(Y)

ymat=np.mat(Y).T
bias= np.ones((X.size))
xmat= np.mat(dx).T
xmat=np.insert(xmat,0,values=bias,axis=1)
# 标准方程解法
xtx = xmat.T*xmat
w=[]
w=xtx.I*(xmat.T*ymat)
print(w)

# model=linear_model.LinearRegression()
# model.fit(xmat,ymat)
# print(model.coef_)
# print(model.intercept_)

def cossfun(x,y,theta):
    m = x.shape[0]
    hx = x*theta
    sqerrors = np.multiply((hx-y),(hx-y))
    J = 1/(2*m)*np.sum(sqerrors)
    return J
def gradientDescent(x,y,theta,alpha):
    m = y.shape[0]
    temp=[]
    j_his = []
    max_iters = 1000
   # epsion = 1e-6

    for i in range(max_iters):
        hx = x * theta
        # hx=x.dot(theta)
        cost = (hx-y)
        theta = theta - (alpha/m)*x.T.dot(cost)

        temp.append(theta)
        J=cossfun(x, y, theta)
        # if abs(j_his[-1:] - J) <= epsion:
        #     break
        j_his.append(J)

    return theta,j_his,temp

theta=np.mat([0,0]).T
theta, j_history, temp = gradientDescent(xmat,ymat,theta,0.01)
print(theta)

plt.plot(range(len(j_history)),j_history)
plt.show()