Как определить, что метод Ньютона не работает - PullRequest
0 голосов
/ 11 сентября 2018

Я создаю основной алгоритм метода Ньютона для задачи оптимизации без ограничений, и мои результаты по алгоритму не соответствуют ожиданиям.Это простая целевая функция, поэтому ясно, что алгоритм должен сходиться к (1,1).Это подтверждается алгоритмом градиентного спуска, который я создал ранее, здесь:

def grad_descent(x, t, count, magnitude):
    xvalues.append(x)
    gradvalues.append(np.array([dfx1(x), dfx2(x)]))
    fvalues.append(f(x))   
    temp=x-t*dfx(x)
    x = temp
    magnitude = mag(dfx(x))    
    count+=1

    return xvalues, gradvalues, fvalues, count

Моя попытка создать алгоритм для метода Ньютона здесь:

def newton(x, t, count, magnitude):
  xvalues=[]
  gradvalues=[]
  fvalues=[]
  temp=x-f(x)/dfx(x)

  while count < 10:
    xvalues.append(x)
    gradvalues.append(dfx(x))
    fvalues.append(f(x))  

    temp=x-t*f(x)/dfx(x)
    x = temp
    magnitude = mag(dfx(x))    
    count+=1
    if count > 100:
      break
  return xvalues, gradvalues, fvalues, count

Вот целевая функцияи функция градиента:

f = lambda x: 100*np.square(x[1]-np.square(x[0])) + np.square((1-x[0]))
dfx = lambda x: np.array([-400*x[0]*x[1]+400*np.power(x[0],3)+2*x[0]-2, 200*(x[1]-np.square(x[0]))])

Вот начальные условия.Обратите внимание, что альфа и бета не используются в методе Ньютона.

x0, t0, alpha, beta, count = np.array([-1.1, 1.1]), 1, .15, .7, 1
magnitude = mag(np.array([dfx1(x0), dfx2(x0)]))

Для вызова функции:

xvalues, gradvalues, fvalues, iterations = newton(x0, t0, count, magnitude)

Это приводит к очень странным результатам.Вот первые 10 итераций значений x, значений градиента и решения функции для соответствующего ввода x:

[array([-1.1,  1.1]), array([-0.99315589,  1.35545455]), array([-1.11651296,  1.11709035]), array([-1.01732476,  1.35478987]), array([-1.13070578,  1.13125051]), array([-1.03603697,  1.35903467]), array([-1.14368874,  1.14364506]), array([-1.05188162,  1.36561528]), array([-1.15600558,  1.15480705]), array([-1.06599492,  1.37360245])]
[array([-52.6, -22. ]), array([142.64160215,  73.81918332]), array([-62.07323963, -25.90216846]), array([126.11789251,  63.96803995]), array([-70.85773749, -29.44900758]), array([114.31050737,  57.13241151]), array([-79.48668009, -32.87577304]), array([104.93863096,  51.83206539]), array([-88.25737032, -36.308371  ]), array([97.03403558, 47.45145765])]
[5.620000000000003, 17.59584998020613, 6.156932949106968, 14.29937453260906, 6.7080172227439725, 12.305727666787176, 7.297442528545537, 10.926625703722639, 7.944104584786208, 9.89743708419569]  

Вот окончательный результат:

final_value = print('Final set of x values: ', xvalues[-1])
final_grad = print('Final gradient values: ', gradvalues[-1])
final_f = print('Final value of the object function with optimized inputs: ', fvalues[-1])
final_grad_mag = print('Final magnitude of the gradient with optimized inputs: ', mag(np.array([dfx1(xvalues[-1]), dfx2(xvalues[-1])])))
total_iterations = print('Total iterations: ', iterations)

3D-графикпоказано здесь код:

x = np.array([i[0] for i in xvalues])
y = np.array([i[1] for i in xvalues])
z = np.array(fvalues)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(x, y, z, label='Newton Method')
ax.legend()

Есть ли причина для этого, потому что первоначальное предположение настолько близко к оптимальной точке, или в моем алгоритме есть какая-то ошибка, которую я не улавливаю?Любой совет будет принята с благодарностью.Похоже, что решение может даже колебаться, но трудно сказать

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Теперь я уверен, что что-то не так с кодом Python. Я решил реализовать алгоритм в Matlab, и он, кажется, работает нормально. Вот этот код:

clear; clc;
x=[-1.1, 1.1]';
t=1;
count=1;

xvalues=[];

temp = x - inv([(-400*x(2)+1200*x(1)^2+2), -400*x(1); -400*x(1), 200]);
disp(x-inv([(-400*x(2)+1200*x(1)^2+2), -400*x(1); -400*x(1), 200])*[-400*x(1)*x(2)+400*x(1)^3+2*x(1)-2; 200*(x(2)-x(1)^2)])

while count<10
    xvalues(count,:)= x;
    temp = x - inv([(-400*x(2)+1200*x(1)^2+2), -400*x(1); -400*x(1), 200]) * [-400*x(1)*x(2)+400*x(1)^3+2*x(1)-2; 200*(x(2)-x(1)^2)];    
    x = temp;
    count = count+1;
end

disp(xvalues)

Выход:

-1.1000    1.1000
   -1.0087    1.0091
   -0.2556   -0.5018
   -0.2446    0.0597
    0.9707   -0.5348
    0.9708    0.9425
    1.0000    0.9991
    1.0000    1.0000
    1.0000    1.0000
0 голосов
/ 16 сентября 2018

Итак, я наконец понял, что с этим происходит. Это было все о том, какие структуры данных Python хранит мои переменные как. Таким образом, я установил все свои значения на «float32» и инициализировал переменные, которые повторяются. Рабочий код здесь:

Примечание: лямбда-функция - это анонимная функция, полезная для однострочных выражений

f = lambda x: 100*np.square(x[1]-np.square(x[0])) + np.square((1-x[0]))
dfx = lambda x: np.array([-400*x[0]*x[1]+400*np.power(x[0],3)+2*x[0]-2, 200*(x[1]-np.square(x[0]))], dtype='float32')
dfx11 = lambda x: -400*(x[1])+1200*np.square(x[0])+2
dfx12 = lambda x: -400*x[0]
dfx21 = lambda x: -400*x[0]
dfx22 = lambda x: 200
hessian = lambda x: np.array([[dfx11(x), dfx12(x)], [dfx21(x), dfx22(x)]], dtype='float32')
inv_hessian = lambda x: inv(hessian(x))
mag = lambda x: math.sqrt(sum(i**2 for i in x))

def newton(x, t, count, magnitude):
  xvalues=[]
  gradvalues=[]
  fvalues=[]
  temp = np.zeros((2,1))

  while magnitude > .000005:
    xvalues.append(x)
    gradvalues.append(dfx(x))
    fvalues.append(f(x))      

    deltaX = np.array(np.dot(-inv_hessian(x), dfx(x)))
    temp = np.array(x+t*deltaX)
    x = temp
    magnitude = mag(deltaX)    
    count+=1
  return xvalues, gradvalues, fvalues, count

x0, t0, alpha, beta, count = np.array([[-1.1], [1.1]]), 1, .15, .7, 1
xvalues, gradvalues, fvalues, iterations = newton(x0, t0, count, magnitude)

final_value = print('Final set of x values: ', xvalues[-1])
final_grad = print('Final gradient values: ', gradvalues[-1])
final_f = print('Final value of the object function with optimized inputs: ', fvalues[-1])
final_grad_mag = print('Final magnitude of the gradient with optimized inputs: ', mag(np.array([dfx1(xvalues[-1]), dfx2(xvalues[-1])])))
total_iterations = print('Total iterations: ', iterations
print(xvalues)

Выход:

Final set of x values:  [[0.99999995]
 [0.99999987]]
Final gradient values:  [[ 9.1299416e-06]
 [-4.6193604e-06]]
Final value of the object function with optimized inputs:  [5.63044182e-14]
Final magnitude of the gradient with optimized inputs:  1.02320249276675e-05
Total iterations:  9
[array([[-1.1],
       [ 1.1]]), array([[-1.00869558],
       [ 1.00913081]]), array([[-0.25557778],
       [-0.50186648]]), array([[-0.24460602],
       [ 0.05971173]]), array([[ 0.97073805],
       [-0.53472879]]), array([[0.97083687],
       [0.94252417]]), array([[0.99999957],
       [0.99914868]]), array([[0.99999995],
       [0.99999987]])]
0 голосов
/ 11 сентября 2018

Я думаю, что нашел часть проблемы.Я использовал неправильный алгоритм Ньютона.Хотя раньше я использовал:
x {k + 1} = x {k} - f (x) ∇f (x)

Правильное обновление:
x {k + 1} = x {k} - [f '' (x *)1017 * {k} )] -1 f '(x {k} )

Когда я изменил это, результат все равно расходится, но этонемного лучше.Новая функция здесь:

f = lambda x: 100*np.square(x[1]-np.square(x[0])) + np.square((1-x[0]))
dfx1 = lambda x: -400*x[0]*x[1]+400*np.power(x[0],3)+2*x[0]-2
dfx2 = lambda x: 200*(x[1]-np.square(x[0]))
dfx = lambda x: np.array([-400*x[0]*x[1]+400*np.power(x[0],3)+2*x[0]-2, 200*(x[1]-np.square(x[0]))])
dfx11 = lambda x: -400*(x[1])+1200*np.square(x[0])+2
dfx12 = lambda x: -400*x[0]
dfx21 = lambda x: -400*x[0]
dfx22 = lambda x: 200
hessian = lambda x: np.array(([dfx11(x0), dfx12(x0)], [dfx21(x0), dfx22(x0)]))
inv_hessian = lambda x: inv(np.array(([dfx11(x0), dfx12(x0)], [dfx21(x0), dfx22(x0)])))  

def newton(x, t, count, magnitude):
  xvalues=[]
  gradvalues=[]
  fvalues=[]
  temp = x-(inv_hessian(x).dot(dfx(x)))

  while count < 25:
    xvalues.append(x)
    gradvalues.append(dfx(x))
    fvalues.append(f(x))  

    temp = x-(inv_hessian(x).dot(dfx(x)))
    x = temp
    magnitude = mag(dfx(x))    
    count+=1
    if count > 100:
      break
  return xvalues, gradvalues, fvalues, count

Ближайшее решение, до которого сходится решение, - это после первого шага, куда оно идет (-1.05, 1.1).Тем не менее, он все еще расходится.Я никогда не работал с методом Ньютона, поэтому я не уверен, насколько он точен, как алгоритм предназначен для получения или нет.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...