Python 多元标量函数的梯度下降优化
我试图在rosenbrock函数上测试我的梯度下降程序。但无论我如何调整我的学习速度(Python 多元标量函数的梯度下降优化,python,numpy,optimization,scipy,gradient-descent,Python,Numpy,Optimization,Scipy,Gradient Descent,我试图在rosenbrock函数上测试我的梯度下降程序。但无论我如何调整我的学习速度(stepargument)、精度(precisionargument)和迭代次数(iterationargument),我都无法得到非常接近的结果 import numpy as np def minimize(f, f_grad, x, step=1e-3, iterations=1e3, precision=1e-3): count = 0 while True: last
step
argument)、精度(precision
argument)和迭代次数(iteration
argument),我都无法得到非常接近的结果
import numpy as np
def minimize(f, f_grad, x, step=1e-3, iterations=1e3, precision=1e-3):
count = 0
while True:
last_x = x
x = x - step * f_grad(x)
count += 1
if count > iterations or np.linalg.norm(x - last_x) < precision:
break
return x
def rosenbrock(x):
"""The Rosenbrock function"""
return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)
def rosenbrock_grad(x):
"""Gradient of Rosenbrock function"""
xm = x[1:-1]
xm_m1 = x[:-2]
xm_p1 = x[2:]
der = np.zeros_like(x)
der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm)
der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
der[-1] = 200*(x[-1]-x[-2]**2)
return der
x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
minimize(rosenbrock, rosenbrock_grad, x0, step=1e-6, iterations=1e4, precision=1e-6)
将numpy导入为np
def最小化(f,f_梯度,x,步长=1e-3,迭代次数=1e3,精度=1e-3):
计数=0
尽管如此:
最后的x=x
x=x-阶跃*f_梯度(x)
计数+=1
如果计数>迭代次数或np.linalg.norm(x-last_x)<精度:
打破
返回x
戴夫·罗森布罗克(x):
“”“Rosenbrock函数”“”
回报总额(100.0*(x[1:]-x[:-1]**2.0)**2.0+(1-x[:-1])**2.0)
def rosenbrock_梯度(x):
“”“Rosenbrock函数的梯度”“”
xm=x[1:-1]
xm_m1=x[:-2]
xm_p1=x[2:]
der=np.类零(x)
der[1:-1]=200*(xm-xm_m1**2)-400*(xm_p1-xm**2)*xm-2*(1-xm)
der[0]=-400*x[0]*(x[1]-x[0]**2)-2*(1-x[0])
der[-1]=200*(x[-1]-x[-2]**2)
回程单
x0=np.数组([1.3,0.7,0.8,1.9,1.2])
最小化(rosenbrock,rosenbrock_grad,x0,步长=1e-6,迭代次数=1e4,精度=1e-6)
例如,上面的代码为我提供了数组([1.01723267,1.03694999,1.07870143,1.16693184,1.36404334])
。但是,如果我在scipy.optimize
中使用任何内置的优化方法,我可以得到非常接近的答案或完全相等的数组([1,1,1,1,1.])
(这是真正的答案)
但是,如果在我的程序中使用非常小的步长
,精度
和非常大的迭代次数
,计算只会在我的计算机上花费很长时间
我不知道这是不是因为
我的程序中有任何错误吗
或者仅仅因为
梯度下降在这里效率很低,而且要求非常小
步骤
,精度
和非常大的迭代
,以产生非常接近的
解决方案
还是因为
我需要做一些特殊的功能缩放
(注:我还尝试绘制二维图,其中函数值在y轴上,迭代次数在x轴上,以“调试”梯度下降,但即使我得到一个好看的下降曲线图,解决方案仍然不是很接近。)您的方法很容易出现超调。在具有瞬时高梯度的情况下,你的解会跳得很远。在优化中,当一个步骤不能降低成本时,拒绝它通常是合适的 线搜索 一旦你通过计算梯度选择了一个方向,沿着这个方向搜索,直到你将成本降低到梯度范数的一小部分 即从x[n+1]=x-α*梯度开始 α在1.0到0.0之间变化,接受x的值,如果x降低了梯度范数的一部分成本。这是一个很好的收敛规则,称为Armijo规则 其他忠告 首先考虑优化2D Rosenbrock函数,并在该成本域上绘制路径
考虑用数字验证渐变实现是否正确。通常情况下,这就是问题所在。您的方法容易出现超调。在具有瞬时高梯度的情况下,你的解会跳得很远。在优化中,当一个步骤不能降低成本时,拒绝它通常是合适的 线搜索 一旦你通过计算梯度选择了一个方向,沿着这个方向搜索,直到你将成本降低到梯度范数的一小部分 即从x[n+1]=x-α*梯度开始 α在1.0到0.0之间变化,接受x的值,如果x降低了梯度范数的一部分成本。这是一个很好的收敛规则,称为Armijo规则 其他忠告 首先考虑优化2D Rosenbrock函数,并在该成本域上绘制路径 考虑用数字验证渐变实现是否正确。通常情况下,这就是问题所在。引用以下内容: 全球最小值位于一个狭长的抛物线形平坦山谷内。找到山谷是微不足道的。然而,要收敛到全局最小值是困难的 梯度下降法是一种简单的算法,因此它不能找到最小值也就不足为奇了。让我们看看2D中不同起点的情况: 正如维基百科所说:它很容易找到山谷,但无法进一步收敛。与函数的其他部分相比,沿着山谷的梯度非常平坦 我认为您的实现工作正常,但Rosenbrock函数可能不是测试它的最合适的函数 与其他答案相反,我进一步认为步长太小而不是太大。问题不在于超调,而在于算法被卡住了。如果我将步长设置为
1e-3
,而不更改其他设置,则算法将在两位数内收敛到最大值。在2D的情况下,尽管从一些起始位置超调了山谷,但仍然会发生这种情况——可以这么说,你需要的是速度,不要在以后被卡住
下面是复制上图的修改代码:
import numpy as np
import matplotlib.pyplot as plt
def minimize(f, f_grad, x, step=1e-3, iterations=1e3, precision=1e-3):
count = 0
while True:
last_x = x
x_hist.append(x)
x = x - step * f_grad(x)
count += 1
if count > iterations or np.linalg.norm(x - last_x) < precision:
x_hist.append(x)
break
return x
def rosenbrock(x):
"""The Rosenbrock function"""
return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)
def rosenbrock_grad(x):
"""Gradient of Rosenbrock function"""
xm = x[1:-1]
xm_m1 = x[:-2]
xm_p1 = x[2:]
der = np.zeros_like(x)
der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm)
der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
der[-1] = 200*(x[-1]-x[-2]**2)
return der
k = np.linspace(0, 2, 101)
f = np.empty((k.shape[0], k.shape[0]))
for i, y in enumerate(k):
for j, x in enumerate(k):
f[i, j] = rosenbrock(np.array([x, y]))
plt.imshow(np.log10(f), extent=[k[0], k[-1], k[-1], k[0]], cmap='autumn')
for start in [[0.5, 0.5], [1.0, 0.5], [1.5, 0.5],
[0.5, 1.0], [1.0, 1.0], [1.5, 1.0],
[0.5, 1.5], [1.0, 1.5], [1.5, 1.5]]:
x0 = np.array(start)
x_hist = []
minimize(rosenbrock, rosenbrock_grad, x0, step=1e-6, iterations=1e4, precision=1e-9)
x_hist = np.array(x_hist)
plt.plot(x_hist[:, 0], x_hist[:, 1], 'k')
plt.plot(x0[0], x0[1], 'ok')
将numpy导入为np
将matplotlib.pyplot作为plt导入
def最小化(f,f_梯度,x,步长=1e-3,迭代次数=1e3,精度=1e-3):
计数=0
尽管如此:
最后的x=x
x_历史附加(x)
x=x-阶跃*f_梯度(x)
计数+=1
如果计数>迭代次数或np.linalg.norm(x-last_x)<精度:
x_历史附加(x)
打破
返回x
戴夫·罗森布罗克(x):
“”“Rosenbrock函数”“”
回报总额(100.0*(x[1:]-x[:-1]**2.0)**2.0+(1-x[:-1])**2.0)
def rosenbrock_梯度(x):
“”“Rosenbrock函数的梯度”“”
xm=x[1:-1]
xm_m1=x[:-2]
xm_p1=x[2:]
der=np.类零(x)
der[1:-1]=200*(xm-xm_m1**2)-400*(xm_p1-