该篇文章的代码和思路参考了https://www.cnblogs.com/noluye/p/11108513.html#commentform
我对代码部分做了一些修改和完善
1,梯度下降时函数的收敛条件通常与梯度相关,而与自变量和函数值无关。可以设置当梯度的绝对值小于一个特定的值时,停止收敛;
2,通过梯度值来判断收敛与否实际上非常自然,因为当越接近与最小值时,梯度的绝对值会越小,(在最小值时为零),通过自变量和函数值来判断收敛与否看起来可行,实际上操作起来难度比较大,因为根本不知道函数的最小值是多少,否则就不会去寻找了。而在最小值或极小值点,梯度值是确定的,所以一般用梯度来判断是否收收敛。
下面是一维自变量情况的代码示例和运行结果
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Created on
@author: gaolei82@jd.com
"""
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
一维问题的梯度下降法示例
"""
def func_1d(x):
"""
目标函数
:param x: 自变量,标量
:return: 因变量,标量
"""
return x ** 2 + 1
def grad_1d(x):
"""
目标函数的梯度
:param x: 自变量,标量
:return: 因变量,标量
"""
return x * 2
def gradient_descent_1d(grad, cur_x=0.1, learning_rate=0.01, precision=0.0001, max_iters=10000):
"""
一维问题的梯度下降法
:param grad: 目标函数的梯度
:param cur_x: 当前 x 值,通过参数可以提供初始值
:param learning_rate: 学习率,也相当于设置的步长
:param precision: 设置收敛精度
:param max_iters: 最大迭代次数
:return: 局部最小值 x*
"""
for i in range(max_iters):
grad_cur = grad(cur_x)
if abs(grad_cur) < precision:
break # 当梯度趋近为 0 时,视为收敛,收敛
cur_x = cur_x - grad_cur * learning_rate #如果不符合收敛条件,就继续循环迭代
print("第", i, "次迭代:x 值为 ", cur_x,"函数值为:", func_1d(cur_x),"梯度值为:", grad_cur)
print("局部最小值 x =", cur_x)
return cur_x
if __name__ == '__main__':
gradient_descent_1d(grad_1d, cur_x=10, learning_rate=0.2, precision=0.000001, max_iters=10000)
第 0 次迭代:x 值为 6.0 函数值为: 37.0 梯度值为: 20
第 1 次迭代:x 值为 3.5999999999999996 函数值为: 13.959999999999997 梯度值为: 12.0
第 2 次迭代:x 值为 2.1599999999999997 函数值为: 5.665599999999999 梯度值为: 7.199999999999999
第 3 次迭代:x 值为 1.2959999999999998 函数值为: 2.6796159999999993 梯度值为: 4.319999999999999
第 4 次迭代:x 值为 0.7775999999999998 函数值为: 1.6046617599999997 梯度值为: 2.5919999999999996
第 5 次迭代:x 值为 0.46655999999999986 函数值为: 1.2176782335999998 梯度值为: 1.5551999999999997
第 6 次迭代:x 值为 0.2799359999999999 函数值为: 1.078364164096 梯度值为: 0.9331199999999997
第 7 次迭代:x 值为 0.16796159999999993 函数值为: 1.0282110990745599 梯度值为: 0.5598719999999998
第 8 次迭代:x 值为 0.10077695999999996 函数值为: 1.0101559956668416 梯度值为: 0.33592319999999987
第 9 次迭代:x 值为 0.06046617599999997 函数值为: 1.003656158440063 梯度值为: 0.20155391999999991
第 10 次迭代:x 值为 0.036279705599999976 函数值为: 1.0013162170384227 梯度值为: 0.12093235199999994
第 11 次迭代:x 值为 0.021767823359999987 函数值为: 1.000473838133832 梯度值为: 0.07255941119999995
第 12 次迭代:x 值为 0.013060694015999992 函数值为: 1.0001705817281796 梯度值为: 0.043535646719999974
第 13 次迭代:x 值为 0.007836416409599995 函数值为: 1.0000614094221447 梯度值为: 0.026121388031999985
第 14 次迭代:x 值为 0.004701849845759997 函数值为: 1.0000221073919722 梯度值为: 0.01567283281919999
第 15 次迭代:x 值为 0.002821109907455998 函数值为: 1.00000795866111 梯度值为: 0.009403699691519994
第 16 次迭代:x 值为 0.0016926659444735988 函数值为: 1.0000028651179995 梯度值为: 0.005642219814911996
第 17 次迭代:x 值为 0.0010155995666841593 函数值为: 1.0000010314424799 梯度值为: 0.0033853318889471976
第 18 次迭代:x 值为 0.0006093597400104956 函数值为: 1.0000003713192926 梯度值为: 0.0020311991333683186
第 19 次迭代:x 值为 0.0003656158440062973 函数值为: 1.0000001336749453 梯度值为: 0.001218719480020991
第 20 次迭代:x 值为 0.0002193695064037784 函数值为: 1.0000000481229803 梯度值为: 0.0007312316880125946
第 21 次迭代:x 值为 0.00013162170384226703 函数值为: 1.000000017324273 梯度值为: 0.0004387390128075568
第 22 次迭代:x 值为 7.897302230536021e-05 函数值为: 1.0000000062367382 梯度值为: 0.00026324340768453405
第 23 次迭代:x 值为 4.7383813383216124e-05 函数值为: 1.0000000022452258 梯度值为: 0.00015794604461072043
第 24 次迭代:x 值为 2.8430288029929674e-05 函数值为: 1.0000000008082812 梯度值为: 9.476762676643225e-05
第 25 次迭代:x 值为 1.7058172817957805e-05 函数值为: 1.0000000002909812 梯度值为: 5.686057605985935e-05
第 26 次迭代:x 值为 1.0234903690774682e-05 函数值为: 1.0000000001047533 梯度值为: 3.411634563591561e-05
第 27 次迭代:x 值为 6.1409422144648085e-06 函数值为: 1.0000000000377112 梯度值为: 2.0469807381549363e-05
第 28 次迭代:x 值为 3.684565328678885e-06 函数值为: 1.000000000013576 梯度值为: 1.2281884428929617e-05
第 29 次迭代:x 值为 2.210739197207331e-06 函数值为: 1.0000000000048874 梯度值为: 7.36913065735777e-06
第 30 次迭代:x 值为 1.3264435183243986e-06 函数值为: 1.0000000000017595 梯度值为: 4.421478394414662e-06
第 31 次迭代:x 值为 7.958661109946391e-07 函数值为: 1.0000000000006335 梯度值为: 2.652887036648797e-06
第 32 次迭代:x 值为 4.775196665967835e-07 函数值为: 1.000000000000228 梯度值为: 1.5917322219892782e-06
局部最小值 x = 4.775196665967835e-07
下面是二维情况的代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Created on
@author: gaolei82@jd.com
"""
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
二维问题的梯度下降法示例
"""
import math
import numpy as np
def func_2d(x):
"""
目标函数
:param x: 自变量,两个坐标
:return: 因变量,标量
"""
return - math.exp(-(x[0] ** 2 + x[1] ** 2))
def grad_2d(x):
"""
目标函数的梯度
:param x: 自变量,需要两个坐标来定义
:return: 因变量,二维向量
"""
deriv0 = 2 * x[0] * math.exp(-(x[0] ** 2 + x[1] ** 2))
deriv1 = 2 * x[1] * math.exp(-(x[0] ** 2 + x[1] ** 2))
return np.array([deriv0, deriv1])
def gradient_descent_2d(grad, cur_x=np.array([0.1, 0.1]), learning_rate=0.01, precision=0.0001, max_iters=10000):
"""
二维问题的梯度下降法
:param grad: 目标函数的梯度
:param cur_x: 当前 x 值,通过参数可以提供初始值
:param learning_rate: 学习率,也相当于设置的步长
:param precision: 设置收敛精度
:param max_iters: 最大迭代次数
:return: 局部最小值 x*
"""
print(f"{cur_x} 作为初始值开始迭代...")
for i in range(max_iters):
grad_cur = grad(cur_x)
if np.linalg.norm(grad_cur, ord=2) < precision:
break # 当梯度趋近为 0 时,视为收敛
cur_x = cur_x - grad_cur * learning_rate
print("第", i, "次迭代:x 值为 ", cur_x,"函数值为:", func_2d(cur_x),"梯度值为:", grad_cur,"梯度的二范数为:",np.linalg.norm(grad_cur,ord=2))
print("取局部最小值时x =", cur_x)
return cur_x
if __name__ == '__main__':
gradient_descent_2d(grad_2d, cur_x=np.array([1, -1]), learning_rate=0.2, precision=0.000001, max_iters=10000)
[ 1 -1] 作为初始值开始迭代...
第 0 次迭代:x 值为 [ 0.94586589 -0.94586589] 函数值为: -0.16707298079708022 梯度值为: [ 0.27067057 -0.27067057] 梯度的二范数为: 0.3827859860416437
第 1 次迭代:x 值为 [ 0.88265443 -0.88265443] 函数值为: -0.21052356217619125 梯度值为: [ 0.31605727 -0.31605727] 梯度的二范数为: 0.4469724724205303
第 2 次迭代:x 值为 [ 0.80832661 -0.80832661] 函数值为: -0.2706892429850575 梯度值为: [ 0.37163911 -0.37163911] 梯度的二范数为: 0.5255770710888176
第 3 次迭代:x 值为 [ 0.72080448 -0.72080448] 函数值为: -0.35376649295892587 梯度值为: [ 0.43761064 -0.43761064] 梯度的二范数为: 0.6188748978419849
第 4 次迭代:x 值为 [ 0.61880589 -0.61880589] 函数值为: -0.4649425315105642 梯度值为: [ 0.50999295 -0.50999295] 梯度的二范数为: 0.7212389448066557
第 5 次迭代:x 值为 [ 0.50372222 -0.50372222] 函数值为: -0.6020154587768 梯度值为: [ 0.57541836 -0.57541836] 梯度的二范数为: 0.8137644457050167
第 6 次迭代:x 值为 [ 0.3824228 -0.3824228] 函数值为: -0.7463994318061138 梯度值为: [ 0.60649713 -0.60649713] 梯度的二范数为: 0.8577164665081215
第 7 次迭代:x 值为 [ 0.26824673 -0.26824673] 函数值为: -0.8659634127156354 梯度值为: [ 0.57088032 -0.57088032] 梯度的二范数为: 0.807346685606515
第 8 次迭代:x 值为 [ 0.17532999 -0.17532999] 函数值为: -0.9403706139443672 梯度值为: [ 0.46458371 -0.46458371] 梯度的二范数为: 0.6570205882451555
第 9 次迭代:x 值为 [ 0.10937992 -0.10937992] 函数值为: -0.9763560685164637 梯度值为: [ 0.32975034 -0.32975034] 梯度的二范数为: 0.466337405811507
第 10 次迭代:x 值为 [ 0.06666242 -0.06666242] 函数值为: -0.9911516223656849 梯度值为: [ 0.2135875 -0.2135875] 梯度的二范数为: 0.30205834181170976
第 11 次迭代:x 值为 [ 0.04023339 -0.04023339] 函数值为: -0.996767782771522 梯度值为: [ 0.13214514 -0.13214514] 梯度的二范数为: 0.18688144253669445
第 12 次迭代:x 值为 [ 0.02419205 -0.02419205] 函数值为: -0.9988301738125699 梯度值为: [ 0.0802067 -0.0802067] 梯度的二范数为: 0.1134294080240341
第 13 次迭代:x 值为 [ 0.01452655 -0.01452655] 函数值为: -0.9995780475808271 梯度值为: [ 0.04832751 -0.04832751] 梯度的二范数为: 0.06834541626930543
第 14 次迭代:x 值为 [ 0.00871838 -0.00871838] 函数值为: -0.9998479911356031 梯度值为: [ 0.02904085 -0.02904085] 梯度的二范数为: 0.041069958775312394
第 15 次迭代:x 值为 [ 0.00523156 -0.00523156] 函数值为: -0.9999452630546931 梯度值为: [ 0.01743412 -0.01743412] 梯度的二范数为: 0.024655563714951496
第 16 次迭代:x 值为 [ 0.00313905 -0.00313905] 函数值为: -0.9999802929163435 梯度值为: [ 0.01046255 -0.01046255] 梯度的二范数为: 0.014796276715684096
第 17 次迭代:x 值为 [ 0.00188346 -0.00188346] 函数值为: -0.9999929052187241 梯度值为: [ 0.00627798 -0.00627798] 梯度的二范数为: 0.008878401005894307
第 18 次迭代:x 值为 [ 0.00113008 -0.00113008] 函数值为: -0.9999974458487806 梯度值为: [ 0.00376688 -0.00376688] 梯度的二范数为: 0.005327177778946798
第 19 次迭代:x 值为 [ 0.00067805 -0.00067805] 函数值为: -0.9999990805016781 梯度值为: [ 0.00226015 -0.00226015] 梯度的二范数为: 0.0031963362988502823
第 20 次迭代:x 值为 [ 0.00040683 -0.00040683] 函数值为: -0.9999996689801008 梯度值为: [ 0.0013561 -0.0013561] 梯度的二范数为: 0.0019178081798342519
第 21 次迭代:x 值为 [ 0.0002441 -0.0002441] 函数值为: -0.9999998808327711 梯度值为: [ 0.00081366 -0.00081366] 梯度的二范数为: 0.0011506862904233897
第 22 次迭代:x 值为 [ 0.00014646 -0.00014646] 函数值为: -0.9999999570997892 梯度值为: [ 0.0004882 -0.0004882] 梯度的二范数为: 0.0006904120728797162
第 23 次迭代:x 值为 [ 8.78751305e-05 -8.78751305e-05] 函数值为: -0.999999984555923 梯度值为: [ 0.00029292 -0.00029292] 梯度的二范数为: 0.0004142473082310354
第 24 次迭代:x 值为 [ 5.27250788e-05 -5.27250788e-05] 函数值为: -0.9999999944401321 梯度值为: [ 0.00017575 -0.00017575] 梯度的二范数为: 0.0002485483988713182
第 25 次迭代:x 值为 [ 3.16350474e-05 -3.16350474e-05] 函数值为: -0.9999999979984475 梯度值为: [ 0.00010545 -0.00010545] 梯度的二范数为: 0.00014912904233225382
第 26 次迭代:x 值为 [ 1.89810285e-05 -1.89810285e-05] 函数值为: -0.9999999992794412 梯度值为: [ 6.32700947e-05 -6.32700947e-05] 梯度的二范数为: 8.947742604939632e-05
第 27 次迭代:x 值为 [ 1.13886171e-05 -1.13886171e-05] 函数值为: -0.9999999997405988 梯度值为: [ 3.79620569e-05 -3.79620569e-05] 梯度的二范数为: 5.3686455770047314e-05
第 28 次迭代:x 值为 [ 6.83317026e-06 -6.83317026e-06] 函数值为: -0.9999999999066156 梯度值为: [ 2.27772342e-05 -2.27772342e-05] 梯度的二范数为: 3.2211873492356835e-05
第 29 次迭代:x 值为 [ 4.09990215e-06 -4.09990215e-06] 函数值为: -0.9999999999663816 梯度值为: [ 1.36663405e-05 -1.36663405e-05] 梯度的二范数为: 1.9327124101965046e-05
第 30 次迭代:x 值为 [ 2.45994129e-06 -2.45994129e-06] 函数值为: -0.9999999999878973 梯度值为: [ 8.19980431e-06 -8.19980431e-06] 梯度的二范数为: 1.1596274462594029e-05
第 31 次迭代:x 值为 [ 1.47596478e-06 -1.47596478e-06] 函数值为: -0.999999999995643 梯度值为: [ 4.91988259e-06 -4.91988259e-06] 梯度的二范数为: 6.957764677862059e-06
第 32 次迭代:x 值为 [ 8.85578865e-07 -8.85578865e-07] 函数值为: -0.9999999999984315 梯度值为: [ 2.95192955e-06 -2.95192955e-06] 梯度的二范数为: 4.174658806783254e-06
第 33 次迭代:x 值为 [ 5.31347319e-07 -5.31347319e-07] 函数值为: -0.9999999999994353 梯度值为: [ 1.77115773e-06 -1.77115773e-06] 梯度的二范数为: 2.504795284084212e-06
第 34 次迭代:x 值为 [ 3.18808392e-07 -3.18808392e-07] 函数值为: -0.9999999999997967 梯度值为: [ 1.06269464e-06 -1.06269464e-06] 梯度的二范数为: 1.5028771704536073e-06
取局部最小值时 x = [ 3.18808392e-07 -3.18808392e-07]
可以和一维的情况类比看,二维的情况和一维的情况很类似,思路也都一样,差别比较大的地方在于二维的情况不能用绝对值指标来判断收敛与否,而是采用了梯度的二范数,函数为np.linalg.norm(),关于此函数的用法可以参考[https://blog.csdn.net/hqh131360239/article/details/79061535]
该篇文章的原作者将自变量视作二维向量,这在技术上是可以的,也比较好处理。在理论上其实可以不把自变量x看作向量,其本质上仍然是一个点,只不过这个点是在三维空间中,要以两个坐标x0和y来表示而已。
该函数在x=0,y=0,取得最小值-1。
网友评论