基于Python共轭梯度法与最速下降法之间的对比


Posted in Python onApril 02, 2020

在一般问题的优化中,最速下降法和共轭梯度法都是非常有用的经典方法,但最速下降法往往以”之”字形下降,速度较慢,不能很快的达到最优值,共轭梯度法则优于最速下降法,在前面的某个文章中,我们给出了牛顿法和最速下降法的比较,牛顿法需要初值点在最优点附近,条件较为苛刻。

算法来源:《数值最优化方法》高立,P111

我们选用了64维的二次函数来作为验证函数,具体参见上书111页。

采用的三种方法为:

共轭梯度方法(FR格式)、共轭梯度法(PRP格式)、最速下降法

# -*- coding: utf-8 -*-
"""
Created on Sat Oct 01 15:01:54 2016
@author: zhangweiguo
"""
import sympy,numpy
import math
import matplotlib.pyplot as pl
from mpl_toolkits.mplot3d import Axes3D as ax3
import SD#这个文件里有最速下降法SD的方法,参见前面的博客
#共轭梯度法FR、PRP两种格式
def CG_FR(x0,N,E,f,f_d):
  X=x0;Y=[];Y_d=[];
  n = 1
  ee = f_d(x0)
  e=(ee[0]**2+ee[1]**2)**0.5
  d=-f_d(x0)
  Y.append(f(x0)[0,0]);Y_d.append(e)
  a=sympy.Symbol('a',real=True)
  print '第%2s次迭代:e=%f' % (n, e)
  while n<N and e>E:
    n=n+1
    g1=f_d(x0)
    f1=f(x0+a*f_d(x0))
    a0=sympy.solve(sympy.diff(f1[0,0],a,1))
    x0=x0-d*a0
    X=numpy.c_[X,x0];Y.append(f(x0)[0,0])
    ee = f_d(x0)
    e = math.pow(math.pow(ee[0,0],2)+math.pow(ee[1,0],2),0.5)
    Y_d.append(e)
    g2=f_d(x0)
    beta=(numpy.dot(g2.T,g2))/numpy.dot(g1.T,g1)
    d=-f_d(x0)+beta*d
    print '第%2s次迭代:e=%f'%(n,e)
  return X,Y,Y_d
def CG_PRP(x0,N,E,f,f_d):
  X=x0;Y=[];Y_d=[];
  n = 1
  ee = f_d(x0)
  e=(ee[0]**2+ee[1]**2)**0.5
  d=-f_d(x0)
  Y.append(f(x0)[0,0]);Y_d.append(e)
  a=sympy.Symbol('a',real=True)
  print '第%2s次迭代:e=%f' % (n, e)
  while n<N and e>E:
    n=n+1
    g1=f_d(x0)
    f1=f(x0+a*f_d(x0))
    a0=sympy.solve(sympy.diff(f1[0,0],a,1))
    x0=x0-d*a0
    X=numpy.c_[X,x0];Y.append(f(x0)[0,0])
    ee = f_d(x0)
    e = math.pow(math.pow(ee[0,0],2)+math.pow(ee[1,0],2),0.5)
    Y_d.append(e)
    g2=f_d(x0)
    beta=(numpy.dot(g2.T,g2-g1))/numpy.dot(g1.T,g1)
    d=-f_d(x0)+beta*d
    print '第%2s次迭代:e=%f'%(n,e)
  return X,Y,Y_d
if __name__=='__main__':
  '''
  G=numpy.array([[21.0,4.0],[4.0,15.0]])
  #G=numpy.array([[21.0,4.0],[4.0,1.0]])
  b=numpy.array([[2.0],[3.0]])
  c=10.0
  x0=numpy.array([[-10.0],[100.0]])
  '''
  
  m=4
  T=6*numpy.eye(m)
  T[0,1]=-1;T[m-1,m-2]=-1
  for i in xrange(1,m-1):
    T[i,i+1]=-1
    T[i,i-1]=-1
  W=numpy.zeros((m**2,m**2))
  W[0:m,0:m]=T
  W[m**2-m:m**2,m**2-m:m**2]=T
  W[0:m,m:2*m]=-numpy.eye(m)
  W[m**2-m:m**2,m**2-2*m:m**2-m]=-numpy.eye(m)
  for i in xrange(1,m-1):
    W[i*m:(i+1)*m,i*m:(i+1)*m]=T
    W[i*m:(i+1)*m,i*m+m:(i+1)*m+m]=-numpy.eye(m)
    W[i*m:(i+1)*m,i*m-m:(i+1)*m-m]=-numpy.eye(m)
  mm=m**2
  mmm=m**3
  G=numpy.zeros((mmm,mmm))
  G[0:mm,0:mm]=W;G[mmm-mm:mmm,mmm-mm:mmm]=W;
  G[0:mm,mm:2*mm]=-numpy.eye(mm)
  G[mmm-mm:mmm,mmm-2*mm:mmm-mm]=-numpy.eye(mm)
  for i in xrange(1,m-1):
    G[i*mm:(i+1)*mm,i*mm:(i+1)*mm]=W
    G[i*mm:(i+1)*mm,i*mm-mm:(i+1)*mm-mm]=-numpy.eye(mm)
    G[i*mm:(i+1)*mm,i*mm+mm:(i+1)*mm+mm]=-numpy.eye(mm)
  x_goal=numpy.ones((mmm,1))
  b=-numpy.dot(G,x_goal)
  c=0
  f = lambda x: 0.5 * (numpy.dot(numpy.dot(x.T, G), x)) + numpy.dot(b.T, x) + c
  f_d = lambda x: numpy.dot(G, x) + b
  x0=x_goal+numpy.random.rand(mmm,1)*100
  N=100
  E=10**(-6)
  print '共轭梯度PR'
  X1, Y1, Y_d1=CG_FR(x0,N,E,f,f_d)
  print '共轭梯度PBR'
  X2, Y2, Y_d2=CG_PRP(x0,N,E,f,f_d)
  figure1=pl.figure('trend')
  n1=len(Y1)
  n2=len(Y2)
  x1=numpy.arange(1,n1+1)
  x2=numpy.arange(1,n2+1)
  
  X3, Y3, Y_d3=SD.SD(x0,N,E,f,f_d)
  n3=len(Y3)
  x3=range(1,n3+1)
  pl.semilogy(x3,Y3,'g*',markersize=10,label='SD:'+str(n3))
  pl.semilogy(x1,Y1,'r*',markersize=10,label='CG-FR:'+str(n1))
  pl.semilogy(x2,Y2,'b*',markersize=10,label='CG-PRP:'+str(n2))
  pl.legend()
  #图像显示了三种不同的方法各自迭代的次数与最优值变化情况,共轭梯度方法是明显优于最速下降法的
  pl.xlabel('n')
  pl.ylabel('f(x)')
  pl.show()

最优值变化趋势:

基于Python共轭梯度法与最速下降法之间的对比

从图中可以看出,最速下降法SD的迭代次数是最多的,在与共轭梯度(FR与PRP两种方法)的比较中,明显较差。

补充知识:python实现牛顿迭代法和二分法求平方根,精确到小数点后无限多位-4

首先来看一下牛顿迭代法求平方根的过程:计算3的平方根

基于Python共轭梯度法与最速下降法之间的对比

如图,是求根号3的牛顿迭代法过程。这里使用的初始迭代值(也就是猜测值)为1,其实可以为任何值最终都能得到结果。每次开始,先检测猜测值是否合理,不合理时,用上面的平均值来换掉猜测值,依次继续迭代,直到猜测值合理。

原理:现在取一个猜测值 a, 如果猜测值合理的话,那么就有a^2=x,即x/a=a ,x为被开方数。不合理的话呢,就用表中的猜测值和商的平均值来换掉猜测值。当不合理时,比如 a>真实值,那么x/a<真实值,这时候取a 与 x/a 的平均值来代替a的话,那么新的a就会比原来的a要更接近真实值。同理有 a<真实值 的情况。于是,这样不断迭代下去最终是一个a不断收敛到真实值的一个过程。于是不断迭代就能得到真实值,证明了迭代法是正确的。

附上我的python代码:

利用python整数运算,python整数可以无限大,可以实现小数点后无限多位

#二分法求x的平方根小数点下任意K位数的精准值,利用整数运算 #思想:利用二分法,每次乘以10,取中间值,比较大小,从而定位精确值的范围,将根扩大10倍,则被开方数扩大100倍。 #quotient(商)牛顿迭代法:先猜测一个值,再求商,然后用猜测值和商的中间值代替猜测值,扩大倍数,继续进行。

import math
from math import sqrt
 
def check_precision(l,h,p,len1):#检查是否达到了精确位
  l=str(l);h=str(h)
  if len(l)<=len1+p or len(h)<=len1+p:
    return False
  for i in range(len1,p+len1):#检查小数点后面的p个数是否相等
    if l[i]!=h[i]:     #当l和h某一位不相等时,说明没有达到精确位
      return False
  return True
 
def print_result(x,len1,p):
  x=str(x)
  if len(x)-len1<p:#没有达到要求的精度就已经找出根
    s=x[:len1]+"."+x[len1:]+'0'*(p-len(x)+len1)
  else:s=x[:len1]+"."+x[len1:len1+p]
  print(s)
 
def binary_sqrt(x,p):
  x0=int(sqrt(x))
  if x0*x0==x: #完全平方数直接开方,不用继续进行
    print_result(x0,len(str(x0)),p)
    return 
  len1=len(str(x0))#找出整数部分的长度
  l=0;h=x
  while(not check_precision(l,h,p,len1)):#没有达到精确位,继续循环
    if not l==0:#第一次l=0,h=x时不用乘以10,直接取中间值
      h=h*10 #l,h每次扩大10倍
      l=l*10
      x=x*100 #x每次要扩大100倍,因为平方
    m=(l+h)//2
    if m*m==x:
      return print_result(m,len1,p)
    elif m*m>x:
      h=m
    else:
      l=m
  return print_result(l,len1,p)#当达到了要求的精度,直接返回l
 
#牛顿迭代法求平方根
def newton_sqrt(x,p):
  x0=int(sqrt(x))
  if x0*x0==x: #完全平方数直接开方,不用继续进行
    print_result(x0,len(str(x0)),p)
    return
  len1=len(str(x0))#找出整数部分的长度
  g=1;q=x//g;g=(g+q)//2
  while(not check_precision(g,q,p,len1)):
    x=x*100
    g=g*10
    q=x//g   #求商
    g=(g+q)//2 #更新猜测值为猜测值和商的中间值
  return print_result(g,len1,p)
 
while True:  
  x=int(input("请输入待开方数:"))
  p=int(input("请输入精度:"))
  print("binary_sqrt:",end="")
  binary_sqrt(x,p)
  print("newton_sqrt:",end="")
  newton_sqrt(x,p)

以上这篇基于Python共轭梯度法与最速下降法之间的对比就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现基本进制转换的方法
Jul 11 Python
Python保存MongoDB上的文件到本地的方法
Mar 16 Python
Python自定义函数实现求两个数最大公约数、最小公倍数示例
May 21 Python
python pandas库的安装和创建
Jan 10 Python
Python模拟百度自动输入搜索功能的实例
Feb 14 Python
python 画二维、三维点之间的线段实现方法
Jul 07 Python
Python常用数据类型之间的转换总结
Sep 06 Python
python sorted函数的小练习及解答
Sep 18 Python
Python requests上传文件实现步骤
Sep 15 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
Nov 30 Python
python爬虫请求头的使用
Dec 01 Python
Python爬虫基础初探selenium
May 31 Python
python 的topk算法实例
Apr 02 #Python
python torch.utils.data.DataLoader使用方法
Apr 02 #Python
Python基于stuck实现scoket文件传输
Apr 02 #Python
Python要求O(n)复杂度求无序列表中第K的大元素实例
Apr 02 #Python
Pytorch 使用不同版本的cuda的方法步骤
Apr 02 #Python
pytorch 中的重要模块化接口nn.Module的使用
Apr 02 #Python
python递归函数求n的阶乘,优缺点及递归次数设置方式
Apr 02 #Python
You might like
PHP5在Apache下的两种模式的安装
2006/09/05 PHP
基于PHP的cURL快速入门教程 (小偷采集程序)
2011/06/02 PHP
php中判断数组是一维,二维,还是多维的解决方法
2013/05/04 PHP
PHP+Ajax+JS实现多图上传
2016/05/07 PHP
JQury slideToggle闪烁问题及解决办法
2011/07/05 Javascript
使用Js让Html中特殊字符不被转义
2013/11/05 Javascript
详谈jQuery操纵DOM元素属性 attr()和removeAtrr()方法
2015/01/22 Javascript
JavaScript编程中的Promise使用大全
2015/07/28 Javascript
js类式继承与原型式继承详解
2016/04/07 Javascript
JS组件Bootstrap Select2使用方法解析
2016/05/30 Javascript
js实现表单及时验证功能 用户信息立即验证
2016/09/13 Javascript
JQuery遍历元素的父辈和祖先的方法
2016/09/18 Javascript
官方推荐react-navigation的具体使用详解
2018/05/08 Javascript
从零开始搭建webpack+react开发环境的详细步骤
2018/05/18 Javascript
node.js处理前端提交的GET请求
2019/08/30 Javascript
Python实现简单生成验证码功能【基于random模块】
2018/02/10 Python
使用pandas对矢量化数据进行替换处理的方法
2018/04/11 Python
详解Python3的TFTP文件传输
2018/06/26 Python
Python中的支持向量机SVM的使用(附实例代码)
2019/06/26 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
2019/07/22 Python
Python中list的交、并、差集获取方法示例
2019/08/01 Python
python命名空间(namespace)简单介绍
2019/08/10 Python
Python函数的定义方式与函数参数问题实例分析
2019/12/26 Python
Python新手如何理解循环加载模块
2020/05/29 Python
新西兰珠宝品牌:Michael Hill
2017/09/16 全球购物
销售高级职员求职信
2013/10/29 职场文书
信息部岗位职责
2013/11/12 职场文书
健康家庭事迹材料
2014/05/02 职场文书
消防安全宣传标语
2014/06/07 职场文书
售后客服工作职责
2014/06/16 职场文书
公安交警中队队长个人对照检查材料思想汇报
2014/10/05 职场文书
县委务虚会发言材料
2014/10/20 职场文书
新郎婚礼答谢词
2015/01/04 职场文书
汽车4S店销售经理岗位职责
2015/04/02 职场文书
为什么不建议在go项目中使用init()
2021/04/12 Golang
java项目构建Gradle的使用教程
2022/03/24 Java/Android