精华内容
下载资源
问答
  • 基于复变量求导法的共轭梯度法及其在边界条件辨识中的应用,崔苗,端维伟,为了利用共轭梯度法的计算精度高和收敛速度快的优点,避免传统共轭梯度法在求解非线性热传导反问题中的微分处理、复杂的推导过程
  • 共轭梯度法一个重要的优化算法,今天小编就来带大家看看共轭梯度法在Python中是如何实现的。共轭梯度法是介于最速下降法与牛顿法之间的一个方法,它仅需利用一阶导数信息,但克服了最速下降法收敛慢的缺点,又避免了...

    共轭梯度法一个重要的优化算法,今天小编就来带大家看看共轭梯度法在Python中是如何实现的。

    共轭梯度法是介于最速下降法与牛顿法之间的一个方法,它仅需利用一阶导数信息,但克服了最速下降法收敛慢的缺点,又避免了牛顿法需要存储和计算Hesse矩阵并求逆的缺点,共轭梯度法不仅是解决大型线性方程组最有用的方法之一,也是解大型非线性最优化最有效的算法之一。 在各种优化算法中,共轭梯度法是非常重要的一种。其优点是所需存储量小,具有步收敛性,稳定性高,而且不需要任何外来参数。

    算法步骤:

    b42aa078de9dd06021bc68483de200cb.pngimport random

    import numpy as np

    import matplotlib.pyplot as plt

    def goldsteinsearch(f,df,d,x,alpham,rho,t):

    '''

    线性搜索子函数

    数f,导数df,当前迭代点x和当前搜索方向d,t试探系数>1,

    '''

    flag = 0

    a = 0

    b = alpham

    fk = f(x)

    gk = df(x)

    phi0 = fk

    dphi0 = np.dot(gk, d)

    alpha=b*random.uniform(0,1)

    while(flag==0):

    newfk = f(x + alpha * d)

    phi = newfk

    # print(phi,phi0,rho,alpha ,dphi0)

    if (phi - phi0 )<= (rho * alpha * dphi0):

    if (phi - phi0) >= ((1 - rho) * alpha * dphi0):

    flag = 1

    else:

    a = alpha

    b = b

    if (b < alpham):

    alpha = (a + b) / 2

    else:

    alpha = t * alpha

    else:

    a = a

    b = alpha

    alpha = (a + b) / 2

    return alpha

    def Wolfesearch(f,df,d,x,alpham,rho,t):

    '''

    线性搜索子函数

    数f,导数df,当前迭代点x和当前搜索方向d

    σ∈(ρ,1)=0.75

    '''

    sigma=0.75

    flag = 0

    a = 0

    b = alpham

    fk = f(x)

    gk = df(x)

    phi0 = fk

    dphi0 = np.dot(gk, d)

    alpha=b*random.uniform(0,1)

    while(flag==0):

    newfk = f(x + alpha * d)

    phi = newfk

    # print(phi,phi0,rho,alpha ,dphi0)

    if (phi - phi0 )<= (rho * alpha * dphi0):

    # if abs(np.dot(df(x + alpha * d),d))<=-sigma*dphi0:

    if (phi - phi0) >= ((1 - rho) * alpha * dphi0):

    flag = 1

    else:

    a = alpha

    b = b

    if (b < alpham):

    alpha = (a + b) / 2

    else:

    alpha = t * alpha

    else:

    a = a

    b = alpha

    alpha = (a + b) / 2

    return alpha

    def frcg(fun,gfun,x0):

    # x0是初始点,fun和gfun分别是目标函数和梯度

    # x,val分别是近似最优点和最优值,k是迭代次数

    # dk是搜索方向,gk是梯度方向

    # epsilon是预设精度,np.linalg.norm(gk)求取向量的二范数

    maxk = 5000

    rho = 0.6

    sigma = 0.4

    k = 0

    epsilon = 1e-5

    n = np.shape(x0)[0]

    itern = 0

    W = np.zeros((2, 20000))

    f = open("共轭.txt", 'w')

    while k < maxk:

    W[:, k] = x0

    gk = gfun(x0)

    itern += 1

    itern %= n

    if itern == 1:

    dk = -gk

    else:

    beta = 1.0 * np.dot(gk, gk) / np.dot(g0, g0)

    dk = -gk + beta * d0

    gd = np.dot(gk, dk)

    if gd >= 0.0:

    dk = -gk

    if np.linalg.norm(gk) < epsilon:

    break

    alpha=goldsteinsearch(fun,gfun,dk,x0,1,0.1,2)

    # alpha=Wolfesearch(fun,gfun,dk,x0,1,0.1,2)

    x0+=alpha*dk

    f.write(str(k)+' '+str(np.linalg.norm(gk))+"

    ")

    print(k,alpha)

    g0 = gk

    d0 = dk

    k += 1

    W = W[:, 0:k+1] # 记录迭代点

    return [x0, fun(x0), k,W]

    def fun(x):

    return 100 * (x[1] - x[0] ** 2) ** 2 + (1 - x[0]) ** 2

    def gfun(x):

    return np.array([-400 * x[0] * (x[1] - x[0] ** 2) - 2 * (1 - x[0]), 200 * (x[1] - x[0] ** 2)])

    if __name__=="__main__":

    X1 = np.arange(-1.5, 1.5 + 0.05, 0.05)

    X2 = np.arange(-3.5, 4 + 0.05, 0.05)

    [x1, x2] = np.meshgrid(X1, X2)

    f = 100 * (x2 - x1 ** 2) ** 2 + (1 - x1) ** 2 # 给定的函数

    plt.contour(x1, x2, f, 20) # 画出函数的20条轮廓线

    x0 = np.array([-1.2, 1])

    x=frcg(fun,gfun,x0)

    print(x[0],x[2])

    # [1.00318532 1.00639618]

    W=x[3]

    # print(W[:, :])

    plt.plot(W[0, :], W[1, :], 'g*-') # 画出迭代点收敛的轨迹

    plt.show()

    代码中求最优步长用得是goldsteinsearch方法,另外的Wolfesearch是试验的部分,在本段程序中不起作用。

    迭代轨迹:

    b0026ceba121c98d2d2ccf2fdf3f1b98.png

    5350d1058d88d4303abda9d4f3ea6823.png

    三种最优化方法的迭代次数对比:

    1f7d3a6dbdcdb0e2816778959e417d3a.png

    以上就是共轭梯度法在Python中的实现,是不是很有意思呢~更多Python学习推荐:云海天Python教程网。

    展开全文
  • 全波形反演是一种全新的地震...同时,应用共轭梯度法对正、逆断层模型和Marmousi模型进行了速度结构反演。反演结果表明:共轭梯度法计算效率较高,反演得到的速度模型精度更高,反演效果较好,是一种有效的波形反演方法。
  • 共轭方向共轭梯度方向。 我们在关注共轭时,主要关注共轭的配对规律,共轭的性质,以及取共轭可以带来什么样的数学或应用优势。 共轭复数 配对规律:在复数中,实部相等,虚部互为相反数的两个复数互为...

    目录

    1. 共轭复数

    2. 傅里叶变换的共轭对称性

    3. 共轭根式(radical conjugates)

    4. 共轭矩阵(自共轭矩阵、Hermitian(埃尔米特)矩阵)

    5. 共轭方向

    6. 共轭方向法

    7. 共轭梯度法

    8. 共轭分布(conjugacy)

    9. 共轭函数(对偶函数、极化函数)


    共轭(conjugate )的概念在数学、物理、化学、地理等学科中都有出现。 本意:两头牛背上的架子称为轭,轭使两头牛同步行走。扩展到数学等领域,共轭即为按一定的规律相配的一对或一组。

    在数学中常见的共轭有:共轭复数,共轭根式,共轭矩阵,共轭转置,共轭分布,共轭先验,共轭函数, 共轭方向,共轭方向法,共轭梯度

    法。

    我们在关注共轭时,主要关注共轭的配对规律,共轭的性质,以及取共轭可以带来什么样的数学或应用优势。


    1. 共轭复数

    配对规律:在复数中,实部相等,虚部互为相反数的两个复数互为共轭复数。

    公式描述:z=a+ib 与 \widetilde{z}=a-ib 互为复数

    共轭性质:1)加和为实数

                      2)在复平面上,共轭复数所对应的点关于实轴对称


    2. 傅里叶变换的共轭对称性

    说明:这里的共轭就是上面介绍的复数共轭,不是指傅里叶变换与傅里叶反变换是一对共轭。

    定义:


    3. 共轭根式(radical conjugates)

    配对规律:两个不等于零的根式A、B,若它们的积AB不含根式,则称A、B互为共轭根式

    共轭性质:通过相乘能把根式去掉。

    描述:对根式的模式没有要求,只要满足配对规律的就都是共轭根式。


    4. 共轭矩阵(自共轭矩阵、Hermitian(埃尔米特)矩阵)

    描述:一般共轭矩阵是一个复数矩阵,实对称阵是Hermite阵的特例。

    配对规律:矩阵中第i行第j列的元素与第j行第i列的元素互为共轭复数,的矩阵称为共轭矩阵。

    公式描述:对于一个复数矩阵 A=(a_{ij}),如果a_{ij}=\widetilde{a_{ji}},则称A为共轭矩阵。

                      若用H表示矩阵的旋转取共轭操作(称为共轭转置操作),则满足A^{H}=A的矩阵是共轭矩阵。

    性质:1)主对角线上的元素全是实数。

               2)若A 和B 是Hermite阵,那么它们的和A+B 也是Hermite阵

               3)若A 和B 是Hermite阵,如果满足AB=BA,那么AB与BA也是Hermite阵

               4)更多性质可参考《矩阵分析与应用(张贤达 第2版)》第101页。拥有很多很好的性质。


    5. 共轭方向

    组配对规律:对于一组n维的非零(列)向量\{v_1,v_2,v_3,...v_i,...v_j,...\}和一个n*n的对称正定矩阵 Q,若 v_{i}^{T}Qv_j=0,则称这组向量关于矩阵Q是互相共轭的。因为每个向量都可以表示一个方向,所以称为共轭方向。

    描述:由定义可知,在高维空间中,一个方向向量的共轭方向不是唯一的,而是一组。

    特例:Q为单位矩阵时,v_{i}^{T}v_j=0,此时这组向量是正交的。由此可见,正交是共轭的一种特殊情况,共轭是正交的推广。

    性质:1)互为共轭的一组向量,线性无关

               2)n维空间中,关于任何一个n*n的对称正定矩阵 Q 非零的共轭向量个数不超过n


    6. 共轭方向法

    描述:共轭方向法(conjugate direction method)一种沿着共轭方向寻找无约束最优化问题极小点的一类方法。

    对于一个二次型函数f(\vec{x})=\frac{1}{2}\vec{x}^TG\vec{x} + \vec{b} ^T\vec{x} + c, 其中\vec{x}\in R^n,Q是一个正定对称矩阵,

    给定关于 Q 的一组包含k(k<=n)个共轭向量的共轭向量组 \{ \vec{d^1},\vec{d^2},...,\vec{d^i},...,\vec{d^k} \} ,与一个初始搜索点\vec{x}^{(1)},可以通过k次迭代,在\vec{x}^{(1)}\{ \vec{d^1},\vec{d^2},...,\vec{d^i},...,\vec{d^k} \}张成的k维子空间中找到f(\vec{x})的极小值。每一次迭代都沿着一个新的共轭方向更新,沿该共轭方向的更新步长是一个解析解。

    以下是来自共轭方向法 的摘抄。

    其中\alpha_k是沿 \vec{d}^{(k)} 方向的更新步长。\vec{d}^{(k)}是提前已知的。具体的公式证明可参考:《最优化方法(赖炎连 贺国平 主编)》的第三章,3.3节。


    7. 共轭梯度法

    描述:共轭梯度法可以看作一类特殊的共轭方向法,不同的是,共轭方向法在使用时需要预先定义好一组共轭方向向量。共轭梯度法克服这一缺点,共轭方向向量是随着迭代过程,当场生成下一次迭代的共轭方向。以下摘抄自:共轭梯度法

    其中\beta_{k}也是解析解,具体推论与证明可参考 《最优化方法(赖炎连 贺国平 主编)》的第三章,3.3节。。


    8. 共轭分布(conjugacy)

    配对规律:如果两个分布满足同样的分布律(形式相同,参数不同),那么这两个分布互称为共轭分布。

    性质:分布的表达式相同,参数不同

    描述:共轭分布概念通常出现在贝叶斯概率理论中,如果后验概率P(θ|X)和先验概率P(θ)满足同样的分布律(形式相同,参数不同)。那么,先验分布和后验分布被叫做共轭分布,同时,先验分布叫做似然函数的共轭先验(分布)


    9. 共轭函数(对偶函数、极化函数)

    定义:设函数 f:R^n\rightarrow R, 定义函数f^*:R^n\rightarrow R为:

                                                           f^*(y)=\sup_{x\in dom f} (y^Tx-f(x)),

    则函数f^*是函数f的共轭函数。其中dom f表示函数f的定义域。sup表示函数的上确界,即最小上界。y是共轭函数f^*的变量。

    使f^*上确界有限(即 y^Tx-f(x) 在dom f 上有上确界)的所有的y\in R^n构成共轭函数f^*的定义域。下图描述了此定义。

    特点:无论原函数f是否是凸函数,它的共轭函数f^*都是凸函数。

    性质:1)凸函数的共轭函数的共轭函数是原函数,f^{**}=f

               2)更多具体性质可参考《凸优化(王书宁 译)》第85页

    相关:可微函数的共轭函数称为函数的Legendre变换。为了区分一般情况和可微情况下所定义的共轭,一般函数的共轭有时称为Fenchel共轭


     

    参考:[1] 连续时间傅里叶变换的共轭与共轭对称性(详细推导)

               [2]【机器学习之数学】02 梯度下降法、最速下降法、牛顿法、共轭方向法、拟牛顿法

               [3]《凸优化(王书宁 译)》

               [4]《最优化方法(赖炎连 贺国平 主编)》的第三章

    展开全文
  • 共轭梯度法

    2015-06-13 17:58:21
    概述作为一种迭代的优化方法,共轭梯度(Conjugate Gradient,cg)由Hestenes和Stiefe于1951年提出。cg是针对形如式(1-1)的优化方法。 Ax=b(1-1) Ax=b \tag{1-1}\label{1-1} 需要指出的是,式(1-1)有着广泛的应用...

    概述

    作为一种迭代的优化方法,共轭梯度(Conjugate Gradient,cg)由Hestenes和Stiefe于1951年提出。cg是针对形如式(1-1)的优化方法。

    Ax=b(1-1)

    需要指出的是,式(1-1)有着广泛的应用场景。例如,令x为二次问题(如式(1-2)所示)的最小值:
    f(x)=12xTAxbx(1-2)

    x=argminxf(x)(1-3)
    则有
    f(x)=Axb=0(1-4)
    显然,式(1-4)可以用cg方法求解。
    此外,牛顿法的每轮迭代需要计算dk=(H(k))1gk,即H(k)dk=gk。此时,也可以使用cg来求取。

    原理

    共轭的定义

    ARn×n是对称正定矩阵。对于d(i),d(j)Rn ,若有(d(i))TAd(j)=0,则称d(i)d(j)关于A共轭。

    对于一组向量d(1),d(2),...,d(k)Rn,若它们两两关于A共轭,即(d(i))TAd(j)=0,ij,则称该组向量关于A共轭。

    需要指出的是,共轭是正交的推广。这是因为,若A=I,则有(d(i))TId(j)=0d(i)d(j)

    可以证明关于A共轭的一组向量d(1),d(2),...,d(k)线性无关。

    几何意义

    对于二次函数

    f(x)=12(xx)TA(xx)(2-1)

    其中ARn×n是对称正定矩阵,x0是某已知点。那么,有
    12(xx)TA(xx)=c(2-2)
    是以x为中心的椭球面。如图2-1所示:

    图1图2-1 二次函数#

    由于f(x)=A(xx)=0,且2f(x)=A>0,所以xf(x)的极小点。

    x(0)是某等值面上一点,d(1)Rn是其搜索方向,x(1)x(0) 沿着d(1)以最佳步长搜索得到的点,那么d(1)x(1)所在等值面的切向量。其对应的法向量为

    f(x(1))=A(x(1)x)(2-3)
    所以 d(1)f(x(1))正交。即d(1)A(x(1)x)=0。令d(2)=x(1)x,那么d(1)d(2)关于A共轭。 也就是说,等值面上某点的切向量与该点指向极小点的向量关于A共轭。如图2-2所示:

    这里写图片描述图2-2 共轭方向#

    共轭方向

    对于

    f(x)=12xTAx+bTx+c(2-4)

    其中ARn×n是对称正定矩阵。d(1),d(2),…,d(k)是一组关于A的共轭向量。那么从任意x(1)开始,依次沿d(1),d(2),…,d(k)搜索,设得到的点依次为x(2),x(3),…,x(k+1)。那么x(k+1)f(x)x(1)+Bk上得到的极小点,其中
    Bk={x|x=i=1kλid(i)}(2-5)

    特别的,当 k=n时,x(n+1)f(x)Rn上的唯一极小点。

    因此,对于式(2-4),可以按照如下步骤求解最小值
    1. 取定一组关于A的共轭方向d(1),d(2),…,d(k)
    2. 任取点x(1),依次按照如下过程由x(k)确定x(k+1)

    {x(k+1)=x(k)+λkd(k)f(x(k)+λkd(k))=minλf(x(k)+λkd(k))(2-6)

    直至某个x(k)满足f(x(k))=0

    共轭梯度

    将共轭方向的思想与最速下降法(steep descent)相结合,利用已知迭代点处的梯度构造一组共轭方向,并按此方向进行搜索,求出函数的极小值。

    实现

    对于式(1-1)按照如下步骤求解

    1. 初始化
      选取初始点x(0),令第一个搜索方向为
      d(0)=r(0)=Ax(0)b(3-1)
      其中,r()称为当前解x()关于式(1-1)的残差
    2. 求解当前搜索方向
      设当前迭代点为x(k),则r(k)=Ax(k)b,则下一个搜索方向按如下方式计算
      d(k)=r(k)+β(k1)d(k1)(3-2)
      由于要求d(k1)d(k)关于A共轭,因此
      0=(d(k1))TAd(k)=(d(k1))TA(r(k)+β(k1)d(k1))(3-3)

      可以计算出
      β(k1)=(d(k1))TAr(k)(d(k1))TAd(k1)=(r(k))TAd(k1)(d(k1))TAd(k1)(3-4)
    3. 求解当前步长
      x(k+1)=x(k)+α(k)d(k)
      根据line search的方法,可以求解得到
      α(k)=(d(k))TAr(k)(d(k))TAd(k)

      4 更新残差
      r(k+1)=r(k)+α(k)Ad(k)
    4. 循环2,3,4步,直至满足终止条件

    根据Krylov子空间的一些性质,可以将的迭代过程简化为:

    α(k)=(r(k))Tr(k)(d(k))TAd(k)=||r(k)||2(d(k))TAd(k)

    β(k)=(r(k+1))Tr(k+1)(r(k))Tr(k)=||r(k+1)||2||r(k)||2

    精简上述分析,得到如下的共轭梯度算法
    x(0)=0, r(0)=b,
    for k=0,1,2.
    1. if ||r(k)||ϵ||b||, return x(k)
    2. if k=0, d(k+1)=r(k); elsed(k+1)=r(k)+β(k)d(k)
    2. α(k+1)=||r(k)||2(d(k+1))TAd(k+1)
    3. x(k+1)=x(k)+α(k+1)d(k+1)
    4. r(k+1)=r(k)α(k+1)Ad(k+1)
    5. β(k+1)=||r(k+1)||2||r(k)||2

    展开全文
  • 针对目前焦炭质量预测线性方法的现状及不足,建立了共轭梯度法优化的BP神经网络焦炭质量预测...模型的实例验证分析表明,共轭梯度法优化的BP神经网络焦炭质量预测模型有较好的适应性和预测精度,具有一定的实际应用价值。
  • 上次我们介绍了二次型函数的共轭梯度法,这次我们来介绍可以应用于一般函数的共轭梯度法

    共轭梯度法(一般函数形式)


    一般形式函数对共轭梯度法的挑战

    一般形式的函数,黑塞矩阵不一定是个常量,这就必须寻找另外一个办法来迭代计算。当然也可以使用牛顿法进行近似,但是牛顿法到每步迭代都需要再迭代n步来近似,所以计算量还是很大的。

    复习一下二次型函数的共轭梯度法

    点击这里可以看我之前写的二次型共轭函数的博客

    迭代过程**

    1. 初始条件:
      g1=Hx1bd1=r1=g1 g_1 = Hx_1-b\\ d_1 = r_1 = -g_1

    2. 迭代关系
      ak=dKTrKdkTHdkxk+1=xk+akdkrk+1=rkakHdkβk=rk+1THdkdkTHdkdk+1=rk+1βkdk a_k = \frac{d^T_Kr_K}{d^T_kHd_k}\\x_{k+1} = x_k + a_kd_k\\r_{k+1} = r_k - a_kHd_k\\\beta_{k} = \frac{r_{k+1}^THd_{k}}{d^T_{k}Hd_{k}}\\d_{k+1} = r_{k+1} - \beta_kd_k

    黑塞矩阵H在非二次型函数中是一个n*n的每个元素都是一个关于自变量XX的函数的矩阵,所以计算量是很大的,特别是当函数是个多元函数的时候

    所以我们既想要保留共轭梯度法的优势,有想要尽量避免H的计算

    由上面的迭代关系可以看到,H的计算主要是在akβka_k和\beta_k的计算中,所以我们现在需要的就是变形这两个公式,来近似原本的迭代过程。(rk+1r_{k+1}这边没写是因为rk+1r_{k+1}可以变形成gk+1-g_{k+1}

    步长aka_k的变形

    步长的迭代其实就是找到该搜索方向下降速度最快的步长,(该方向的极小值),我们可以使用一维搜索算法,如果希望得到精确结果,可以使用牛顿法(一维的牛顿法H是常量矩阵),但是计算量比较大;也可以使用非精确的搜搜,例如划界法,黄金分割法等等…

    βk\beta_k的变形

    βk\beta_k的变形存在许多数学家提出的变形公式,不同的公式对不同的目标函数可能有不同的效果,我们在之后的代码中会进行比较

    Hesyenes-Stiefel公式

    我们知道βk\beta_k的迭代公式是这样的
    βk=rk+1THdkdkTHdk \beta_{k} = \frac{r_{k+1}^THd_{k}}{d^T_{k}Hd_{k}}
    该方法选择使用一下公式来近似HdkHd_k
    Hdk=gk+1gkak Hd_k = \frac{g_{k+1}-g_k}{a_k}
    于是原本的公式就变形称为了
    βk=gk+1T(gk+1gk)dkT(gk+1gk) \beta_{k} = -\frac{g_{k+1}^T(g_{k+1}-g_k)}{d^T_{k}(g_{k+1}-g_k)}

    Polak-Ribiere 公式

    是在上一个公式的基础上进一步变形,这里不详细说了
    βk=gk+1T(gk+1gk)dkT(gk+1gk)=gk+1T(gk+1gk)dkTgk+1dkTgk=gk+1T(gk+1gk)dkTgk \beta_{k} = -\frac{g_{k+1}^T(g_{k+1}-g_k)}{d^T_{k}(g_{k+1}-g_k)}=-\frac{g_{k+1}^T(g_{k+1}-g_k)}{d^T_{k}g_{k+1}-d^T_{k}g_k}= \frac{g_{k+1}^T(g_{k+1}-g_k)}{d^T_{k}g_k}
    这里的变形用到了共轭梯度法的性质:当前点的梯度方向与之前所有点的搜索方向都正交
    dk=rkβk1dk1=gkβk1dk1gkTdk=gkTgkβk1gkTdk1=gkTgkβk=gk+1T(gkgk+1)gkTgk d_k = r_k - \beta_{k-1}d_{k-1}=-g_k - \beta_{k-1}d_{k-1}\\ g_k^Td_k =-g_k^Tg_k - \beta_{k-1}g_k^Td_{k-1}=-g_k^Tg_k\\ \beta_k = \frac{g_{k+1}^T(g_{k}-g_{k+1})}{g_k^Tg_k}

    Fletcher-Reeves公式

    βk=gk+1Tgk+1gkTgk \beta_k = -\frac{g^T_{k+1}g_{k+1}}{g^T_kg_k}

    可以看出明显也是从上面的改进而来的。

    Dai-Yuan公式

    βk=gkTgkdk1T(gkgk1) \beta_k = -\frac{g^T_kg_k}{d^T_{k-1}(g_k-g_{k-1})}

    Powell公式

    βk=max{0,gk+1T(gkgk+1)gkTgk} \beta_k = max\lbrace0, \frac{g_{k+1}^T(g_{k}-g_{k+1})}{g_k^Tg_k}\rbrace

    重置搜索方向

    这里还有一个问题,对于二次型函数共轭函数可以在n步之内达到极小值,但是对于非二次型的函数,由于我们采用的是近似的方法,并不能保证在n步之内就达到最小值,但是n元的目标函数最多只能构建n个互相线性独立的共轭防线,所以我们需要

    将n次或者n次以后的搜索方向重置为梯度负方向

    迭代过程

    1. 初始条件
      g1=g(x0)d1=g1 g_1 = g(x0) \\d_1 = -g1

    2. 迭代
      αk=seachalpha(...)xk+1=xk+αkdkβk=dk+1=gk+1βkdk \alpha_k = seach-alpha(...) \\x_{k+1} = x_k + \alpha_kd_k \\\beta_k = 选择一种公式 \\d_{k+1} = -g_{k+1}-\beta_kd_k

    代码示例

    using LinearAlgebra
    using Gadfly
    
    ## 非精确方法
    function inexact_alpha(f,g,xk,fk,gk,d;
                         α0 =1,ϵ=0.1,τ =0.5,
                         η = 0.5,ζ=2.0)
        α = α0
        Φ0 = d' * gk
        δ = α .* d
        xn = xk .+ δ
        fn = f(xn...)
        gn = g(xn...)
    
        # Armijo 不太大条件
        while fn > fk + ϵ*α*Φ0
            α = τ * α
            δ = α .* d
            xn = xk .+ δ
            fn = f(xn...)
            gn = g(xn...)
        end
        # Wolfe 不太小条件
        while d' *gn < η * Φ0
            α = ζ*α
            δ = α .* d
            xn = xk .+ δ
            fn = f(xn...)
            gn = g(xn...)
        end
        return α,δ,xn,fn,gn
    end
    
    ## TODO 划界法搜索步长
    function aecant_alpha(f,g,xk,fk,gk,d;α0=1,accuracy=0.001,maxIter = 128)
        # _l是当前点,k-1
        # _u是下一个点,k
        αl = α0
        αu = α0*1.1
        xl = xk .+ αl .* d
        xu = xk .+ αu .* d
        gl = g(xl...)
        gu = g(xu...)
    
        Φl = d' * gl
        Φu = d' * gu
    
        for i in 1:maxIter
            Δ = Φu - Φl
            # 防止出现分母为0的数学错误
            if Δ == 0.0
                println("error:出现分母为0的数学错误")
                return αu,αu.*d,xu,f(xu...),gu
            else
                Δ = Φu * (αu - αl)/ Δ
            end
            if abs(Δ) <= accuracy
                return αu,αu.*d,xu,f(xu...),gu
            end
    
            αl = αu
            xl = xu
            gl = gu
            Φl = Φu
            αu = αu - Δ
            xu = xk .+ αu .* d
            gu = g(xu...)
            Φu = d' * gu
        end
        return αu,αu.*d,xu,f(xu...),gu
    end
    
    # β值公式函数,可供选择
    function Hestence_Stiefel(d,gk,gn)
        return -1 * (gn' * (gn .- gk))/(d' * (gn .- gk))
    end
    
    function Polak_Ribiere(d,gk,gn)
        return (gn' * (gk .- gn)) / (gk' * gk)
    end
    
    function Fletcher_Reeves(d,gk,gn)
        return -1 * (gn' * gn) / (gk' * gk)
    end
    
    function Dai_Yuan(d,gk,gn)
        return -1 * (gn' * gn) /(d' * (gn .- gk))
    end
    
    function Powell(d,gk,gn)
        return max(0,(gn' * (gn .- gk)/(d' * (gn .- gk))))
    end
    
    function ConjugateGradient(f,
                               g,
                               x0;
                               fβ = Hestence_Stiefel,
                               fα = seach_alpha, ##定义搜索步长的方法
                               accuracy = 0.001,
                               #accurary_α = 0.001, #用来搜寻α的精度
                               accuracy_x = accuracy,
                               accurary_f = accuracy,
                               accurary_g = accuracy,
                               convergence_rule = x -> reduce(&,x),
                               convergence_abs = true,
                               iterations = 256,
                               plotStep = false,
                               debug = false)
        n = length(x0)
    
        xk = x0
        fk = f(xk...)
        gk = g(xk...)
        d = -gk
        ## 输出的列表用来画图
        pts = []
        push!(pts,xk)
    
        #从0开始是因为第一次和第n次要重置共轭方向
        for i in 0:iterations
            # δ是 xn .- xk的结果
            α,δ,xn,fn,gn = fα(f,g,xk,fk,gk,d)
            # 第一次迭代和第n次迭代重置搜索方向
            if mod(i,n) == 0
                β = 0
            else
                β = fβ(d,gk,gn)
            end
    
            # 判断收敛
            conditions = [norm(δ),abs(fn-fk),norm(gn)]
            denominator = [max(1,norm(xk)),max(1,fk),1]
            if !convergence_abs
                conditions = conditions ./ denominator
            end
            if convergence_rule(conditions .< [accuracy_x,accurary_f,accurary_g])
                println("-------------------达到迭代条件,结束迭代-----------------")
                println("迭代步数:",i+1) ##因为迭代从i=0开始
                println("最后一步x差值的模长:",norm(δ))
                println("最后一步g的模长:",norm(gn))
                println("最后一步的f差值:",abs(fn-fk))
                return xn,fn,gn,pts
            end
    
            d = -gn .- β*d
            xk = xn
            fk = fn
            gk = gn
    
            ## 如果需要绘画出迭代过程
            if plotStep
                push!(pts,xk)
            end
    
            if debug
                println(i,"\tx:",xn,"\tf:",fn,"\ng:",gn,"\tα:",α,"\tδ:",δ,"\tnorm(δ):",norm(δ))
            end
    
    
        end
    
    
        println("-------------------达到最大迭代步数,结束迭代-----------------")
        return xn,fn,gn,pts
    end
    
    
    # 测试用例
    x,f,g,pts = ConjugateGradient((x1, x2) -> 2.5*x1^2 + 0.5*x2^2 +2*x1*x2-3*x1-x2,
                              (x1, x2) -> [5*x1+2*x2-3,
                                           x2+2*x1-1],
                                           [100,100],
                                           plotStep=true,
                                           debug = true,fα = inexact_alpha)
    
    
    # 画图
    n = length(pts)
    rosen = layer((x1, x2) -> 2.5*x1^2 + 0.5*x2^2 +2*x1*x2-3*x1-x2,-100.0,100.0,-100.0,100.0,Geom.contour())
    steps = layer(
    ## convert()函数将数据转化成了浮点型,这样子才不会报错
    ## 最后一点不作为起点
    x = convert(Vector{Float64},[pts[i][1] for i in 1:n-1]),
    y = convert(Vector{Float64},[pts[i][2] for i in 1:n-1]),
    ## 第一点不作为终点
    xend = convert(Vector{Float64},[pts[i][1] for i in 2:n]),
    yend = convert(Vector{Float64},[pts[i][2] for i in 2:n]),
    Geom.point,Geom.vector(filled = true))
    plot(rosen,steps,Scale.x_continuous(minvalue = low,maxvalue = up),
        Scale.y_continuous(maxvalue=up,minvalue=low))
    
    # # 比较多种方法之间的差异
    # map(b ->
    #     map(a -> println("\n",a,"\t",b,"\t",
    #     ConjugateGradient((x1,x2) -> 2.5*x1^2 + 0.5*x2^2 +2*x1*x2-3*x1-x2,
    #     (x1, x2) -> [5*x1+2*x2-3,
    #                  x2+2*x1-1],
    #                  [0,0],
    #                  fβ = b,
    #                  fα = a,
    #                  accuracy = 0.01,
    #                  debug = false),"\n\n"),
    #                  [seach_alpha, inexact_alpha]),
    #                  [Hestence_Stiefel,Polak_Ribiere,Fletcher_Reeves,Powell,Dai_Yuan])
    
    

    调用函数

    using LinearAlgebra
    using Gadfly
    

    定义搜索步长的函数

    ## 非精确方法
    function inexact_alpha(f,g,xk,fk,gk,d;
                         α0 =1,ϵ=0.1,τ =0.5,
                         η = 0.5,ζ=2.0)
        α = α0
        Φ0 = d' * gk
        δ = α .* d
        xn = xk .+ δ
        fn = f(xn...)
        gn = g(xn...)
    
        # Armijo 不太大条件
        while fn > fk + ϵ*α*Φ0
            α = τ * α
            δ = α .* d
            xn = xk .+ δ
            fn = f(xn...)
            gn = g(xn...)
        end
        # Wolfe 不太小条件
        while d' *gn < η * Φ0
            α = ζ*α
            δ = α .* d
            xn = xk .+ δ
            fn = f(xn...)
            gn = g(xn...)
        end
        return α,δ,xn,fn,gn
    end
    
    ##划界法搜索步长
    function aecant_alpha(f,g,xk,fk,gk,d;α0=1,accuracy=0.001,maxIter = 128)
        # _l是当前点,k-1
        # _u是下一个点,k
        αl = α0
        αu = α0*1.1
        xl = xk .+ αl .* d
        xu = xk .+ αu .* d
        gl = g(xl...)
        gu = g(xu...)
    
        Φl = d' * gl
        Φu = d' * gu
    
        for i in 1:maxIter
            Δ = Φu - Φl
            # 防止出现分母为0的数学错误
            if Δ == 0.0
                println("error:出现分母为0的数学错误")
                return αu,αu.*d,xu,f(xu...),gu
            else
                Δ = Φu * (αu - αl)/ Δ
            end
            if abs(Δ) <= accuracy
                return αu,αu.*d,xu,f(xu...),gu
            end
    
            αl = αu
            xl = xu
            gl = gu
            Φl = Φu
            αu = αu - Δ
            xu = xk .+ αu .* d
            gu = g(xu...)
            Φu = d' * gu
        end
        return αu,αu.*d,xu,f(xu...),gu
    end
    
    

    函数提供了非精确搜索和划界法两种方法来线性搜索步长

    关于非精确搜索和划界法可以查看一下这个视频

    非精确搜索和划界法

    构建搜索β\beta 的函数

    # β值公式函数,可供选择
    function Hestence_Stiefel(d,gk,gn)
        return -1 * (gn' * (gn .- gk))/(d' * (gn .- gk))
    end
    
    function Polak_Ribiere(d,gk,gn)
        return (gn' * (gk .- gn)) / (gk' * gk)
    end
    
    function Fletcher_Reeves(d,gk,gn)
        return -1 * (gn' * gn) / (gk' * gk)
    end
    
    function Dai_Yuan(d,gk,gn)
        return -1 * (gn' * gn) /(d' * (gn .- gk))
    end
    
    function Powell(d,gk,gn)
        return max(0,(gn' * (gn .- gk)/(d' * (gn .- gk))))
    end
    

    这里提供了我们上面学习到的全部β\beta变形公式,可以根据自己的需要选择,下面我们也会提供函数对这几个公式的性能进行比较。

    构造函数接口

    function ConjugateGradient(f,
                               g,
                               x0;
                               fβ = Hestence_Stiefel,
                               fα = seach_alpha, ##定义搜索步长的方法
                               accuracy = 0.001,
                               #accurary_α = 0.001, #用来搜寻α的精度
                               accuracy_x = accuracy,
                               accurary_f = accuracy,
                               accurary_g = accuracy,
                               # 用来定义结束迭代阈值的方法,
                               # x -> x[3],表示用accurary_g作为条件结束迭代
                               # x -> reduce(&,x),表示三个都要满足
                               # x -> reduce(|,x),表示只要满足其中一个
                               convergence_rule = x -> reduce(&,x),
                               convergence_abs = true,
                               iterations = 256,
                               plotStep = true,
                               debug = false)
    end
    
    

    每n次迭代重置一次搜索方向

    我们知道在对于n元的函数最多只能有n个共轭方向,但是我们并不一定能在n次迭代中完成寻找最小值的迭代,所以每逢n次迭代我们就需要重置一下搜索方向

    if mod(i,n) == 0
                β = 0
            else
                β = fβ(d,gk,gn)
            end
    
    

    mod函数是取模,和取余有点相似,只有当i是0或者n的倍数的时候,mod(i,n)才会等于0

    判断收敛

            # 判断收敛
            conditions = [norm(δ),abs(fn-fk),norm(gn)]
            denominator = [max(1,norm(xk)),max(1,fk),1]
            if !convergence_abs
                conditions = conditions ./ denominator
            end
            if convergence_rule(conditions .< [accuracy_x,accurary_f,accurary_g])
                println("-------------------达到迭代条件,结束迭代-----------------")
                println("迭代步数:",i+1) ##因为迭代从i=0开始
                println("最后一步x差值的模长:",norm(δ))
                println("最后一步g的模长:",norm(gn))
                println("最后一步的f差值:",abs(fn-fk))
                return xn,fn,gn,pts
            end
    

    这里convergence_abs是选择绝对收敛和相对收敛的参数,可以根据自己的需要进行选择。有时候使用绝对收敛条件的效果并不是很好,我们就可以选择相对收敛条件。

    比较多个方法之间的差异

    map(b ->
        map(a -> println("\n",a,"\t",b,"\t",
        ConjugateGradient((x1,x2) -> 2.5*x1^2 + 0.5*x2^2 +2*x1*x2-3*x1-x2,
        (x1, x2) -> [5*x1+2*x2-3,
                     x2+2*x1-1],
                     [0,0],
                     fβ = b,
                     fα = a,
                     accuracy = 0.01,
                     debug = false),"\n\n"),
                     [seach_alpha, inexact_alpha]),
                     [Hestence_Stiefel,Polak_Ribiere,Fletcher_Reeves,Powell,Dai_Yuan])
    
    

    map()函数是用来组合多个函数的效果,例如:

    map(x -> x^2,[3,4,5])
    ## 结果:[9,16,25]
    map(x -> map(y -> x+y,[2,3]),[3,5])
    ##结果:[5,6][7,8]
    

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:14
    最后一步x差值的模长:0.0030420392224767886
    最后一步g的模长:0.005562147029090805
    最后一步的f差值:1.0047870551255222e-5

    seach_alpha Hestence_Stiefel ([0.999118440357853, -1.0003654682602674], -0.9999973459838314, [-0.

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:14
    最后一步x差值的模长:0.0030420392224767886
    最后一步g的模长:0.005562147029090805
    最后一步的f差值:1.0047870551255222e-5

    inexact_alpha Hestence_Stiefel ([0.999118440357853, -1.0003654682602674], -0.9999973459838314, [-0.

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:40
    最后一步x差值的模长:0.003228212139500723
    最后一步g的模长:0.007127315086803913
    最后一步的f差值:1.5304993490783403e-5

    seach_alpha Polak_Ribiere ([0.9907284387629632, -0.9751557156334197], -0.9999371667555162, [0.00333076

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:40
    最后一步x差值的模长:0.003228212139500723
    最后一步g的模长:0.007127315086803913
    最后一步的f差值:1.5304993490783403e-5

    inexact_alpha Polak_Ribiere ([0.9907284387629632, -0.9751557156334197], -0.9999371667555162, [0.00333076

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:14
    最后一步x差值的模长:0.00503044661683969
    最后一步g的模长:0.00979124983859048
    最后一步的f差值:3.0293491641519843e-5

    seach_alpha Fletcher_Reeves ([0.990048831814127, -0.9800175405374091], -0.9999504839160135, [-0.00979092

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:14
    最后一步x差值的模长:0.00503044661683969
    最后一步g的模长:0.00979124983859048
    最后一步的f差值:3.0293491641519843e-5

    inexact_alpha Fletcher_Reeves ([0.990048831814127, -0.9800175405374091], -0.9999504839160135, [-0.00979092

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:67
    最后一步x差值的模长:0.0033054909578306693
    最后一步g的模长:0.009896610447074796
    最后一步的f差值:4.319662391782941e-6

    seach_alpha Powell ([0.9805380034157036, -0.9553978185618385], -0.9997944944334644, [-0.008105620045158

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:67
    最后一步x差值的模长:0.0033054909578306693
    最后一步g的模长:0.009896610447074796
    最后一步的f差值:4.319662391782941e-6

    inexact_alpha Powell ([0.9805380034157036, -0.9553978185618385], -0.9997944944334644, [-0.008105620045158

    -------------------达到迭代条件,结束迭代-----------------
    迭代步数:17
    最后一步x差值的模长:0.004073036874444339
    最后一步的f差值:1.839296890449038e-5

    seach_alpha Dai_Yuan ([0.9907792986521452, -0.9748192338314118], -0.999934779823317, [0.004258025

    最后一步的f差值:1.839296890449038e-5

    inexact_alpha Dai_Yuan ([0.9907792986521452, -0.9748192338314118], -0.999934779823317, [0.004258025597902559, 0.006739363472878512], Any[[0, 0]])

    测试并绘图

    # 测试用例
    x,f,g,pts = ConjugateGradient((x1, x2) -> 2.5*x1^2 + 0.5*x2^2 +2*x1*x2-3*x1-x2,
                              (x1, x2) -> [5*x1+2*x2-3,
                                           x2+2*x1-1],
                                           [100,100],
                                           plotStep=true,
                                           debug = true,fα = inexact_alpha)
    
    
    # 画图
    n = length(pts)
    rosen = layer((x1, x2) -> 2.5*x1^2 + 0.5*x2^2 +2*x1*x2-3*x1-x2,-100.0,100.0,-100.0,100.0,Geom.contour())
    steps = layer(
    ## convert()函数将数据转化成了浮点型,这样子才不会报错
    ## 最后一点不作为起点
    x = convert(Vector{Float64},[pts[i][1] for i in 1:n-1]),
    y = convert(Vector{Float64},[pts[i][2] for i in 1:n-1]),
    ## 第一点不作为终点
    xend = convert(Vector{Float64},[pts[i][1] for i in 2:n]),
    yend = convert(Vector{Float64},[pts[i][2] for i in 2:n]),
    Geom.point,Geom.vector(filled = true))
    plot(rosen,steps,Scale.x_continuous(minvalue = low,maxvalue = up),
        Scale.y_continuous(maxvalue=up,minvalue=low))
    

    结果:

    在这里插入图片描述

    可以看出来共轭梯度法的效果还是很好的,相比较于梯度下降法。

    声明

    这个博客是博主根据博主的老师上传的视频整理得到的,仅供参考和学习,也欢迎大家和我交流讨论。

    参考

    参考视频

    展开全文
  • 提出了一种分析频谱的新方法,其主要思想是采用共轭梯度法训练傅里叶基神经网络权值,根据权值获得信号的幅度谱和相位谱,并给出了基于Matlab语言的频谱分析应用实例。仿真结果表明,与FFT相比,该方法具有计算精度...
  • 当复线性方程组的规模较大或系数矩阵的条件数很大时,系数矩阵易呈现病态特性,双共轭梯度法存在不收敛和收敛速度慢的潜在问题,采用适当的预处理技术,可以改善矩阵病态特性,加快收敛速度。从实型不完全Cholesky...
  • 前4节讲了Trust-Region+DogLeg、最速下降法(SD)、Barzilar, Borwein(BB)法。  信赖域法:Trust-Region+DogLeg  ... 梯度法:最速下降法(SD)、Barzilar, ... 这节将会讲一种共轭梯度法(CG),... 共轭梯度法
  • 在这里,共轭梯度法用于解决基于模型的改进的最优控制问题,其中反复使用所用模型的最优解,然后在每个迭代步骤中更新调整后的参数。 当达到收敛时,尽管模型与现实之间存在差异,但迭代解决方案仍将逼近原始最优...
  • 2.1 测试代码:共轭梯度法 本章中使用共轭梯度法作为标准测试代码。共轭梯度法是一种迭代算法,常用来逼近一组线性方程组成的大型稀疏系统。由于这种系统通常规模庞大,因此难于使用直接法进行求解。阅读本章不需要...
  • 基于Andrew Ng机器学习视频的神经网络作业,自己写的优化算法,速度相比于给的fmincg函数慢了很多,但可以帮助你加深共轭梯度法在实际寻优工程中应用的理解,matlab程序
  • 『运筹OR帷幄』转载作者:学弱猹编者按这一节,我们会开始关注拟牛顿。...不过这样也不是坏事,毕竟优化本来就是一门应用性很强的学科。多花点时间关心下实际的效果也自然是有必要的233。学弱猹,厦门大学信息与计...
  • 利用共轭梯度算法求解n 元正定二次函数的极小点我利用共轭梯度算法来解决n 元正定二次函数的极小点问题,并通过一个简单的函数模型来测试基于该算法的程序的正确性。通过分析该算法后,我采用MATLAB7.0中的设计语言...
  • 学习共轭梯度算法,最好是在了解了梯度下降和(拟)牛顿之后,再学习,省事而且三种方法对比记忆,效果会更好,废话不多说,进入正题。 链接抛上: 梯度下降算法原理及其在线性回归中的应用 最优化算法之牛顿和...
  • 常见的最优化方法有梯度下降法、牛顿法和拟牛顿法、共轭梯度法等等,本文主要介绍牛顿法和梯度下降法原理以及使用Python编程应用问题。 二、应用领域 使用牛顿法或梯度下降法,在最优化算法所解决的问题中,有着很...
  • 提出了一种改进的Polak-Ribière-Polyak共轭梯度投影方法,用于基于Solodov和Svaiter投影方法求解大规模非线性凸约束单调方程。 所获得的方法具有低复杂度的特性并且全局收敛。 此外,该方法也已扩展为解决压缩感测...
  • 矢量分析在场论中非常...1.梯度(Gradient)梯度在数值计算中有着非常广泛的应用,如共轭梯度法,梯度下降法与梯度上升法等,在三维直角坐标系中,某个场 的梯度定义为: 梯度物理意义为:在某个场中,某点的某物理参...
  • 1)共轭梯度法 适用对象限定为对称正定方程组Ax=b 2、双共轭梯度法 若A不是实对称矩阵,求解方程组 在这种方法中有两个搜索方向与矩阵A共轭 3、预处理共轭梯度法 针对对称不定鞍点的问题 ...
  • 共轭梯度法程序 共轭梯度法 一实验目的 (1.熟悉使用共轭梯度法求解无约束非线性规划问题的原理 (2.在掌握原理的基础上熟练运用此方法解决问题 (3.学会利用计算机语言编写程序来辅助解决数学问题 (4.解决问题的同时...
  • 基于梯度理论的非线性优化研究,张璐,,在生产实践中,非线性优化方法应用广泛,基于梯度搜索理论的共轭梯度法是一种寻找最优解的有效方法。我们将其应用到目前同样被广
  • 梯度下降算法推导(笔记)

    千次阅读 2017-10-09 21:55:08
    一直对ML中各种数学推导...1.梯度下降是ML中应用最广泛的用于求解模型参数的算法(类似算法还有牛顿法、拟牛顿法、共轭方向、共轭梯度法等)。原理主要是对损失函数的每一个函数求导,并利用负梯度对权值w进行更新。
  • 依据可控源音频大地电磁(CSAMT)的带地形二维非线性共轭梯度(NLCG)反演结果,把电阻率异常分为Ⅴ类、Ⅳ类、Ⅲ类及Ⅱ类,分别对应极破碎岩体(Ⅴ级围岩)、破碎岩体(Ⅳ级围岩)、较破碎岩体(Ⅲ级围岩)和完整岩体(Ⅱ级围岩...
  • 遗传算法原理段玉帅 马聪聪 舒豪杰42 遗传算法的应用及一些问题遗传算法基本原理主要内容1遗传算法概述3遗传算法改进遗传算法概述1优化方法传统的优化方法局部优化 共轭梯度法拟牛顿法单纯形方法全局优化方法 GA漫步...
  • 介绍的算法有:无约束问题的最速下降法、Newton法、拟Newton法、共轭梯度法、信赖域算法和直接法;非线性方程组和最小二乘问题的Newton法和拟Newton法;约束问题的罚函数法、乘子法、可行方向法、序列二次规划算法和...
  • 这里的最优化 是指非线性最优化,解非线性最优化的方法有很多,比如 梯度下降法、共轭梯度法、变尺度法和步长加速法 等,这里我们只讲 牛顿法。 其中H是hessian矩阵, 定义见上. 高维情况依然可以用牛顿迭代求解, ...
  • 将优化设计中牛顿法,共轭梯度法,单纯形法等应用计算机来实现.

空空如也

空空如也

1 2 3
收藏数 57
精华内容 22
关键字:

共轭梯度法应用