Python随机梯度下降法(三)

        对梯度熟悉之后,我们寻找函数的最小值(或者尽可能小的值)的位置的过程中,都是以梯度做线索,这个就是上一篇说的梯度所具备的特点决定的。
        梯度法:通过不断地沿着梯度方向前进,逐渐减小函数值的过程,这个就是梯度法。梯度法是解决机器学习中最优化问题的常用方法,特别是在神经网络的学习中经常被使用,是一种常见的迭代法
根据目的求最小值还是最大值,梯度法的叫法有所不同,寻找最小值的梯度法称为梯度下降法(gradient descent method),寻找最大值的梯度法称为梯度上升法(gradient ascent method),两者可以通过反转损失函数的符号,变成相同的问题,一般来说,梯度法主要是指梯度下降法。

梯度法使用公式来表示(其中η读音为艾塔或伊塔):

x_{0}=x_{0}-\eta \frac{\alpha f}{\alpha x_{0}}\, \, \, ,\, \, \, x_{1}=x_{1}-\eta \frac{\alpha f}{\alpha x_{1}}

这个η表示更新量,是一个超参数,在神经网络学习中称为学习率(learning rate),学习率决定在一次学习中,应该学习多少,以及在多大程序上更新参数,这个值过大或过小,都无法抵达一个“好的位置”,所以这个参数一般是边测试边调试的一个人工参数,说了这么多,现在来实现这个梯度下降法: 

def gradient_descent(f,init_x,lr=0.01,step_num=100):
    '''
    梯度下降法,f是要优化的函数
    init_x是初始值、lr学习率(η)、step_num是梯度法的重复次数
    '''
    x=init_x
    for i in range(step_num):
        grad=numerical_gradient(f,x)
        x-=lr*grad
    return x

使用这个函数可以求函数的极小值,甚至还可能求到函数的最小值
我们使用这个函数,来求 f(x0,x1)=x0²+x1² 的最小值

def func(x):
    return x[0]**2+x[1]**2
x=np.array([-3.0,4.0])
print(gradient_descent(func,init_x=x,lr=0.1,step_num=100))
[ -6.11110793e-10,   8.14814391e-10]
已经非常接近[0,0],实际上其最小值就是(0,0),如果将lr调过大或过小,都无法得到好的结果
print(gradient_descent(func,init_x=np.array([-3,4.0]),lr=10,step_num=100))
[ -2.58983747e+13,  -1.29524862e+12]
print(gradient_descent(func,init_x=np.array([-3,4.0]),lr=1e-10,step_num=100))
[-2.99999994,  3.99999992]

将这个函数进行画图:
为了直观看到图形,把梯度法函数修改下,保存一份梯度的原始数据用来指向极小值,把每次的迭代使用一个点来标识!

def gradient_descent_history(f,init_x,lr=0.01,step_num=100):
    '''
    梯度下降法,另外保存一份梯度原始数据
    '''
    x=init_x
    x_history=[]
    for i in range(step_num):
        x_history.append(x.copy())#保存一份x的拷贝
        grad=numerical_gradient(f,x)
        x-=lr*grad
    return x,np.array(x_history)

import matplotlib.pylab as plt
init_x=np.array([-8.0,6.0])#起始位置
x,x_history=gradient_descent_history(func,init_x,0.1,20)
plt.grid()
plt.plot([-5,5],[0,0],'--g')#点(-5,0)到点(5,0)的绿虚线
plt.plot([0,0],[-5,5],'--r')#点(0-5)到点(0,5)的红虚线
#x_history[:,0]提取第一列的所有数据,同理x_history[:,1]提取第二列的
plt.plot(x_history[:,0], x_history[:,1], 'o')
plt.xlabel("X0")
plt.ylabel("X1")
plt.show()

下面的中心差分函数在前面文章出现过,放到这方便查阅:

def _numerical_gradient_no_batch(f,x):
    h=1e-4#0.0001
    grad=np.zeros_like(x)#生成x.shape一样的数组,用来保存偏导数
 
    for i in range(x.size):
        tmp=x[i]
 
        x[i]=float(tmp)+h
        fxh1=f(x)#f(x+h)
 
        x[i]=float(tmp)-h
        fxh2=f(x)#f(x-h)
 
        grad[i]=(fxh1-fxh2)/(2*h)#中心差分
        x[i]=tmp#还原值
    return grad
 
def numerical_gradient(f,X):
    '''
    中心差分求梯度
    '''
    if X.ndim==1:
        return _numerical_gradient_no_batch(f,X)
    else:
        grad=np.zeros_like(X)
        for i,x in enumerate(X):
            grad[i]=_numerical_gradient_no_batch(f,x)
        return grad
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅恪光潜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值