当前位置:   article > 正文

求解函数最值的几种算法,梯度下降法python实现_用armijo准则求解极小值

用armijo准则求解极小值

原理就不做过多介绍了,直接上代码。其中的一维线搜索写了三种方法(黄金分割法,Armijo线搜索,Wolfe-Powell线搜索),可以稍微对比以下。

一、黄金分割法

黄金分割法计算步骤

 

  1. import numpy as np
  2. def golden(f, x0, d, s):
  3. '''
  4. 黄金分割法求最小值
  5. 返回下降步长
  6. f: 需要求最小值的函数
  7. x0: x_0
  8. d: 方向
  9. s: 步长上限
  10. '''
  11. t,e=0.618,1e-5
  12. a,b=0,s
  13. a1=a+(1-t)*(b-a)
  14. a2=a+t*(b-a)
  15. f1,f2=f(x0+a1*d),f(x0+a2*d)
  16. while abs(a-b)>=e:
  17. if f1<f2:
  18. a2,f2,b=a1,f1,a2
  19. a1=a+(1-t)*(b-a)
  20. f1=f(x0+a1*d)
  21. else:
  22. a,a1,f1=a1,a2,f2
  23. a2=a+t*(b-a)
  24. f2=f(x0+a2*d)
  25. a=(a1+a2)/2
  26. return a

二、Armijo线搜索

Armijo线搜索计算步骤 

  1. def armijo(f,df, x, d, sigma=0.1):
  2. '''
  3. Armijo非精确线搜索求最小值
  4. 返回搜索步长
  5. f: 需要求最小值的函数
  6. x: x_0
  7. d: 搜索方向
  8. sigma: armijo准则中的参数
  9. '''
  10. alpha, p, k=1.0, 0.8, 1
  11. while f(x+alpha*d)>=f(x)+sigma*alpha*df(x).dot(d) and k<100:
  12. alpha *= p
  13. k += 1
  14. return alpha

三、Wolfe-Powell线搜索

Wolfe-Powell线搜索计算步骤

  1. def wolfe_powell(f,df,x,d,sigma1=1e-3,sigma2=0.9):
  2. '''
  3. Wolfe-powell非精确线搜索求最小值
  4. 返回搜索步长
  5. f: 需要求最小值的函数
  6. x: x_0
  7. d: 搜索方向
  8. sigma1, sigma2: Wolfe-powell准则中的参数
  9. '''
  10. a, b, alpha = 0, float('inf'), 1
  11. k = 0
  12. while k<1000:
  13. k += 1
  14. if f(x+alpha*d) > f(x)+sigma1*alpha*df(x).dot(d): # 若不满足Wolfe-powell准则1,则缩小alpha
  15. b = alpha
  16. alpha = (alpha + a)/2
  17. elif df(x+alpha*d).dot(d) < sigma2*df(x).dot(d): # 若不满足Wolfe-powell准则2,则增大alpha
  18. a = alpha
  19. alpha = min(2*alpha, (alpha+b)/2)
  20. else: # 若准则1和2均满足,则跳出循环
  21. break
  22. return alpha

 四、梯度下降法

梯度下降法计算步骤

  1. def steepest_descent(f,df, x):
  2. '''
  3. 最速下降法求最小值
  4. 其中利用黄金分割法求步长
  5. f: 需要求最小值的函数
  6. df: 函数的导数
  7. x: 初始点
  8. '''
  9. k = 1
  10. while np.linalg.norm(df(x))>1e-5 and k<1000:
  11. d = -df(x)
  12. # 以下三种方法都是求一维线搜索的步长,根据需要任选一种,注释掉其余两行即可。
  13. #alpha = golden(f, x , d, 10) # 黄金分割法求步长
  14. #alpha = armijo(f, df, x, d, sigma=0.1) # armijo非精确搜索求步长
  15. alpha = wolfe_powell(f,df,x,d,sigma1=0.1,sigma2=0.9) # wolfe-powell非精确搜索求步长
  16. x = x + alpha*d
  17. k += 1
  18. return [x,f(x),k] # 返回最小值点,函数最小值,迭代次数

五、实例以及执行结果

  1. def testF1(x):
  2. return 4*(x[0]-2*x[1]-4)**2+(x[0]-2)**2
  3. def testDF1(x):
  4. res = np.zeros([2])
  5. res[0] = 8*(x[0]-2*x[1]-4)+2*(x[0]-2)
  6. res[1] = -16*(x[0]-2*x[1]-4)
  7. return res
  8. def testF2(x):
  9. return (x[0]-1)**2+(2*x[1]-1)**2+(4*x[2]-1)**2+(8*x[3]-1)**2
  10. def testDF2(x):
  11. res = np.zeros([4])
  12. res[0] = 2*(x[0]-1)
  13. res[1] = 2*(2*x[1]-1)
  14. res[2] = 2*(4*x[2]-1)
  15. res[3] = 2*(8*x[3]-1)
  16. return res
  17. problems = [
  18. {
  19. "f": testF1,
  20. "df": testDF1,
  21. "x0": np.array([1, 0])
  22. },
  23. {
  24. "f": testF2,
  25. "df": testDF2,
  26. "x0": np.array([0, 0, 0, 0])
  27. }
  28. ]
  29. for problem in problems:
  30. '''
  31. problem成员描述
  32. f: 函数f(x)
  33. df: 函数的梯度df(x)
  34. x0: 给定的初始点
  35. '''
  36. #print("测试函数在初始点的函数值为{},梯度为{}".format(problem["f"](problem["x0"]), problem["df"](problem["x0"])))
  37. #steepest_descent1,2,3分别是用不同线搜索方法所写的梯度下降算法,详见上steepest_descent的代码块
  38. result1 = steepest_descent1(problem['f'],problem['df'],problem['x0'])
  39. result2 = steepest_descent2(problem['f'],problem['df'],problem['x0'])
  40. result3 = steepest_descent3(problem['f'],problem['df'],problem['x0'])
  41. print('利用梯度下降法及黄金分割法求得测试函数在点{}取得最小值{},迭代次数为{}'.format(result1[0], result1[1],result1[2]))
  42. print('利用梯度下降法及Armijo线搜索求得测试函数在点{}取得最小值{},迭代次数为{}'.format(result2[0], result2[1],result2[2]))
  43. print('利用梯度下降法及Wolfe-Powell线搜索求得测试函数在点{}取得最小值{},迭代次数为{}'.format(result3[0], result3[1],result3[2]),end='\n\n')

 

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号