我正在运行梯度下降来找到非线性方程组的根,我想知道如何检测该方法是否陷入局部最小值,因为我相信在我使用的设置下可能会出现这种情况?我的初始值为 [-2, -1],容差为 10^-2 和 20 次迭代。我读到的一件事是,如果残差开始持平或开始极其缓慢地减少,则可能表明该方法陷入局部最小值,但我并不完全确定。我已经将我的残差及其迭代绘制为每次迭代的迭代值,我想知道如何知道它是否停留在局部最小值。
def system(x):
F = np.zeros((2,1), dtype=np.float64)
F[0] = x[0]*x[0] + 2*x[1]*x[1] + math.sin(2*x[0])
F[1] = x[0]*x[0] + math.cos(x[0]+5*x[1]) - 1.2
return F
def jacb(x):
J = np.zeros((2,2), dtype=np.float64)
J[0,0] = 2*(x[0]+math.cos(2*x[0]))
J[0,1] = 4*x[1]
J[1,0] = 2*x[0]-math.sin(x[0]+5*x[1])
J[1,1] = -5*math.sin(x[0]+5*x[1])
return J
iterates, residuals = GradientDescent('system', 'jacb', np.array([[-2],[-1]]), 1e-2, 20, 0);
我通常使用 20 次迭代进行测试,但我做了 200 次来说明残差的减慢
Marat建议使用动量GD。 代码更改:
dn = 0
gamma = 0.8
dn_prev = 0
while (norm(F,2) > tol and n <= max_iterations):
J = eval(jac)(x,2,fnon,F,*fnonargs)
residuals.append(norm(F,2))
dn = gamma * dn_prev+2*(np.matmul(np.transpose(J), F))
dn_prev = dn
lamb = 0.01
x = x - lamb * dn
你可以通过单点迭代得到一个根......有很多欠松弛。
from math import cos, sin, sqrt
def f( x, y ):
return [ x ** 2 + 2 * y ** 2 + sin(2 * x), x ** 2 + cos(x + 5 * y) - 1.2 ]
x, y = -0.8, 0.0
F = f( x, y )
eps = 1.0e-15
underrelax = 0.1
while abs( F[0] ) + abs( F[1] ) > eps:
xold, yold = x, y
y = sqrt( ( - x ** 2 - sin( 2 * x ) ) / 2 )
x = -sqrt( 1.2 - cos( x + 5 * y ) )
x = xold + underrelax * ( x - xold )
y = yold + underrelax * ( y - yold )
F = f( x, y )
print( x, y, F[0], F[1] )
print( "Root at ", x, y )
输出
...
Root at -0.8405629295980004 0.3790605689518969