基于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实现2014火车票查询代码分享
Jan 10 Python
分享一下Python 开发者节省时间的10个方法
Oct 02 Python
深入理解Python中的super()方法
Nov 20 Python
如何使用Python进行OCR识别图片中的文字
Apr 01 Python
Python3匿名函数lambda介绍与使用示例
May 18 Python
Python使用import导入本地脚本及导入模块的技巧总结
Aug 07 Python
python实现滑雪者小游戏
Feb 22 Python
Python 实现将大图切片成小图,将小图组合成大图的例子
Mar 14 Python
Python中的流程控制详解
Feb 18 Python
浅谈Python 中的复数问题
May 19 Python
详解Python魔法方法之描述符类
May 26 Python
python实现剪贴板的操作
Jul 01 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
PHP 遍历XP文件夹下所有文件
2008/11/27 PHP
php读取csv实现csv文件下载功能
2013/12/18 PHP
Zend Framework创建自己的动作助手详解
2016/03/05 PHP
php 自定义错误日志实例详解
2016/11/12 PHP
thinkphp项目如何自定义微信分享描述内容
2017/02/20 PHP
php魔法函数与魔法常量使用介绍
2017/07/23 PHP
基于jQuery的模仿新浪微博时间的组件
2011/10/04 Javascript
javascript 使用 NodeList需要注意的问题
2013/03/04 Javascript
jquery中$.post()方法的简单实例
2014/02/04 Javascript
MVVM模式中ViewModel和View、Model有什么区别?
2015/06/19 Javascript
jQuery头像裁剪工具jcrop用法实例(附演示与demo源码下载)
2016/01/22 Javascript
JavaScript实现设计模式中的单例模式的一些技巧总结
2016/05/17 Javascript
JavaScript中数组的各种操作的总结(必看篇)
2017/02/13 Javascript
vue+vuex+axio从后台获取数据存入vuex实现组件之间共享数据
2017/04/22 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
微信小程序getPhoneNumber获取用户手机号
2017/09/29 Javascript
微信小程序实现音乐播放器
2019/11/20 Javascript
JavaScript常用8种数组去重代码实例
2020/09/09 Javascript
OpenLayers3加载常用控件使用方法详解
2020/09/25 Javascript
Python使用函数默认值实现函数静态变量的方法
2014/08/18 Python
python中pycurl库的用法实例
2014/09/30 Python
python常规方法实现数组的全排列
2015/03/17 Python
Python读取Excel的方法实例分析
2015/07/11 Python
Django rest framework实现分页的示例
2018/05/24 Python
Python实现简单的文本相似度分析操作详解
2018/06/16 Python
python简单鼠标自动点击某区域的实例
2019/06/25 Python
pytorch 实现在一个优化器中设置多个网络参数的例子
2020/02/20 Python
python录音并调用百度语音识别接口的示例
2020/12/01 Python
团队精神演讲稿
2013/12/31 职场文书
2014年教师工作总结
2014/11/10 职场文书
司机个人年终总结
2015/03/03 职场文书
2019年聘任书的写作格式及范文!
2019/07/03 职场文书
酒店工程部的岗位职责汇总大全
2019/10/23 职场文书
python 如何用terminal输入参数
2021/05/25 Python
Python还能这么玩之用Python修改了班花的开机密码
2021/06/04 Python
HTML怎么设置下划线?html文字加下划线方法
2021/12/06 HTML / CSS