怎么用C++编写梯度下降法?

Python010

怎么用C++编写梯度下降法?,第1张

#include<iostream>

#include<cmath>

#include<ctime>

using namespace std

double f(double x)

double g(double x)

double gd(double xs,double s)

{

    double x=xs

    double y

    for(int i=0i!=20++i)

    {

        double grad= -1*g(x)

        x+=grad*s

        y=f(x)

        cout <<"EPOCH "<<i<<" grad = " <<setprecision(15)<<  grad<< " x = "<< x <<"  y = " << y<< endl

        if(abs(grad) < 1e-6)

            break

    }

    return x

}

int main()

{

    double xk=-5,ak=0.1

    gd(xk,ak)

}

double f(double x)

{

    return x*x-2*x+1

}

double g(double x)

{

return 2*x-2

}

用matlab算的:

minf = 0

for x1 = -2 : 0.1 : 1

for x2 = -2 : 0.1 : 1

f = 4*x1+2*x2+10*x1*x2+6*x1^2+5*x2^2

if f <minf

minf = f

mx1 = x1

mx2 = x2

end

end

end

[minf mx1 mx2]

ans =

-1.2000 -1.00000.8000

当x1 = -1,x2 = 0.8时,取得最小值-1.2

Numerical Recipes in C

一书及所附程序,有完整程序。不过我封装了它的C++版本,可以对但参数或多参数求极值,完整的头文件为:

#ifndef __OPTIMIZATION_H__

#define __OPTIMIZATION_H__

//////////////////////////////////////////////////////////////////////////

// class TOptimization

//

// $ 求函数一个或多个参数的最小值

//

// 该类默认对一个参数优化,一般只要输入优化参数数目

// 优化目标函数就可以使用。

//

// ...主要代码来自:

// Numerical Recipes in C++

// The Art of Scientific Computing

// Second Edition

// William H. Press Saul A. Teukolsky

// William T. Vetterling Brian P. Flannery

//

// 中译本:

// C++ 数值算法(第二版) 胡健伟 赵志勇 薛运华 等译

// 电子工业出版社 北京 (2005)

//

// Author: Jian Feng

// Email: [email protected]

// Dec. 9, 2006

//

//////////////////////////////////////////////////////////////////////////

//

// 输入函数:

//

// @MaxIterationStep: 最大迭代次数,默认 1000

// @ParameterNumbers: 优化参数数目,默认 1

// @InitMatrix:初始化矩阵参数(N*N), 默认

// @Tolerance: 容许公差,默认 1E-7

//

// 执行函数:

//

// @ExecutePowell: 利用powell方法进行多参数优化

// @ExecuteBrent: 利用brent方法进行单参数优化

//

// 输出函数:

//

// @OptimizatedParameters: 优化结果数据

// @ObjectiveFunctionValue: 目标函数在优化值处的值

//

// 使用示例:

//

// 1. 单参数

// double objfun(double a){

// double sum = 0

// for(int i = 0i <DataPoints++i)

// sum += SQR(Exps[i] - Theo(a))

// }

// double value

// TOptimization opt

// if(opt.ExecuteBrent(objfun, -10, -1)) opt.OptimizatedParameters(&value)

//

// 2. 多参数

// double objfun(double *a){

// double sum = 0

// for(int i = 0i <DataPoints++i)

// sum += SQR(Exps[i] - Theo(a))

// }

// double value[3]

// TOptimization opt(3)

// double ival[3] = {-1, 0, 1}

// if(opt.ExecutePowell(objfun, ival)) opt.OptimizatedParameters(value)

//

namespace{

static int ncom //公用变量

static double *pcom_p//公用变量

static double *xicom_p //公用变量

static double (*nrfunc)(double*) //公用函数指针

}

class TOptimization

{

private:

typedef double (*Reff)(double *)

typedef double (*Ptrf)(double )

public:

TOptimization(int n = 1)

~TOptimization(){ FreeMemory()}

//主要方法

void ParameterNumbers(int n){ FreeMemory()num = nAllocateMemory()}

//利用powell方法对一个或多个参数优化

bool ExecutePowell(Reff obj, double *a = 0)

//利用brent方法对一个参数优化,需给出参数所在的区间

bool ExecuteBrent(Ptrf obj, double vFrom = 0, double vTo = 1)

void OptimizatedParameters(double *a){ for(int i=0i<num++i) a[i]=coef[i]}

void OptimizatedParameters(double &a){ a = vmin }

//void OptimizatedParameters(double *a){

// if(method) for(int i=0i<num++i) a[i]=coef[i]

// else *a = vmin

//}

//其它方法

void InitMatrix(double **m)

{

for(int i=0i<num++i)

for(int j = 0j<num++j)

matx[i][j]=m[i][j]

setm = true

}

void MaxIterationStep(int s){ ITMAX = s}

void Tolerance(double eps){ ftol = eps}

double ObjectiveFunctionValue()const{ return fret }

private:

double brent(double ax, double bx, double cx, Ptrf f, double tol, double &xmin, int &flag)

void mnbrak(double &ax, double &bx, double &cx, double &fa, double &fb, double &fc, Ptrf func)

void linmin(double *p, double *xi, double &fret, Reff func)

bool powell(double *p, double **xi, double ftol, int &iter, double &fret, Reff func)

void shft2(double &a, double &b, const double c){ a=bb=c}

void shft3(double &a, double &b, double &c, const double d){ a=bb=cc=d}

double SQR(double x){ return x * x}

void SWAP(double &a, double &b){ double dum=aa=bb=dum}

double SIGN(const double &a, const double &b){return b >= 0?(a>=0?a:-a):(a>=0?-a:a)}

double MAX(const double &a, const double &b){return b >a ? (b) : (a)}

void AllocateMemory()

void FreeMemory()

static double f1dim(double x)

{

int j

double *xt = new double [ncom]

//Vec_Dp &pcom=*pcom_p,&xicom=*xicom_p

double *pcom = pcom_p, *xicom = xicom_p

for (j=0j<ncomj++)

xt[j]=pcom[j]+x*xicom[j]

//delete []xt

double val = nrfunc(xt)

delete []xt

return val

}

bool setm //是否设置优化方向初始矩阵

int num//优化参数

int ITMAX //最大迭代数

int iter //实际迭代步数

int method //优化方法 0: 1-D brent, 2: M-D Powell

double vmin//一维优化参数

double ftol//容许差

double fret//目标函数值

double *coef //多维优化参数值

double **matx //多维优化参数方向的初始值

}

//////////////////////////////////////////////////////////////////////////

inline TOptimization::TOptimization(int n )

{

num= n

ftol = 1e-7

ITMAX = 1000

iter = 0

fret = 0.

vmin = 0.

method = 0

setm = false

AllocateMemory()

}

inline void TOptimization::AllocateMemory()

{

pcom_p = new double [num]

xicom_p = new double [num]

coef= new double [num]

matx= new double *[num]

for(int i = 0i <num++i)

{

coef[i] = 0.

matx[i] = new double [num]

for(int j = 0j <num++j)

matx[i][j]=(i == j ? 1.0 : 0.0)

}

}

inline void TOptimization::FreeMemory()

{

for(int i = 0i <num++i)

{

delete []matx[i]

}

delete []matx

delete []pcom_p

delete []xicom_p

delete []coef

}

inline bool TOptimization::ExecutePowell(Reff obj, double *a)

{

method = 1

if(a)

for(int i = 0i <num++i) coef[i] = a[i]

return powell(coef, matx, ftol, iter, fret, obj)

}

inline bool TOptimization::ExecuteBrent(Ptrf obj, double vFrom, double vTo)

{

method = 0

int flag

double cx, fa, fb, fc

mnbrak(vFrom,vTo,cx,fa,fb,fc,obj)

fret = brent(vFrom,vTo,cx,obj, ftol,vmin, flag)

return flag ? true : false

}

inline void TOptimization::mnbrak(double &ax, double &bx, double &cx, double &fa,

double &fb, double &fc, Ptrf func)

{

const double GOLD=1.618034,GLIMIT=100.0,TINY=1.0e-20

double ulim,u,r,q,fu

fa=func(ax)

fb=func(bx)

if (fb >fa) {

SWAP(ax,bx)

SWAP(fb,fa)

}

cx=bx+GOLD*(bx-ax)

fc=func(cx)

while (fb >fc) {

r=(bx-ax)*(fb-fc)

q=(bx-cx)*(fb-fa)

u=bx-((bx-cx)*q-(bx-ax)*r)/

(2.0*SIGN(MAX(fabs(q-r),TINY),q-r))

ulim=bx+GLIMIT*(cx-bx)

if ((bx-u)*(u-cx) >0.0) {

fu=func(u)

if (fu <fc) {

ax=bx

bx=u

fa=fb

fb=fu

return

} else if (fu >fb) {

cx=u

fc=fu

return

}

u=cx+GOLD*(cx-bx)

fu=func(u)

} else if ((cx-u)*(u-ulim) >0.0) {

fu=func(u)

if (fu <fc) {

shft3(bx,cx,u,cx+GOLD*(cx-bx))

shft3(fb,fc,fu,func(u))

}

} else if ((u-ulim)*(ulim-cx) >= 0.0) {

u=ulim

fu=func(u)

} else {

u=cx+GOLD*(cx-bx)

fu=func(u)

}

shft3(ax,bx,cx,u)

shft3(fa,fb,fc,fu)

}

}

inline double TOptimization::brent(double ax, double bx, double cx,

Ptrf f, double tol, double &xmin, int &flag)

{

flag = 1

const double CGOLD=0.3819660

const double ZEPS=1.0e-20

int iter

double a,b,d=0.0,etemp,fu,fv,fw,fx

double p,q,r,tol1,tol2,u,v,w,x,xm

double e=0.0

a=(ax <cx ? ax : cx)

b=(ax >cx ? ax : cx)

x=w=v=bx

fw=fv=fx=f(x)

for (iter=0iter<ITMAXiter++) {

xm=0.5*(a+b)

tol2=2.0*(tol1=tol*fabs(x)+ZEPS)

if (fabs(x-xm) <= (tol2-0.5*(b-a))) {

xmin=x

return fx

}

if (fabs(e) >tol1) {

r=(x-w)*(fx-fv)

q=(x-v)*(fx-fw)

p=(x-v)*q-(x-w)*r

q=2.0*(q-r)

if (q >0.0) p = -p

q=fabs(q)

etemp=e

e=d

if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x))

d=CGOLD*(e=(x >= xm ? a-x : b-x))

else {

d=p/q

u=x+d

if (u-a <tol2 || b-u <tol2)

d=SIGN(tol1,xm-x)

}

} else {

d=CGOLD*(e=(x >= xm ? a-x : b-x))

}

u=(fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d))

fu=f(u)

if (fu <= fx) {

if (u >= x) a=xelse b=x

shft3(v,w,x,u)

shft3(fv,fw,fx,fu)

} else {

if (u <x) a=uelse b=u

if (fu <= fw || w == x) {

v=w

w=u

fv=fw

fw=fu

} else if (fu <= fv || v == x || v == w) {

v=u

fv=fu

}

}

}

flag = 0

xmin=x

return fx

}

inline void TOptimization::linmin(double *p, double *xi, double &fret, Reff func)

{

int j, flag

const double TOL=1.0e-8

double xx,xmin,fx,fb,fa,bx,ax

int n=num

ncom=n

//pcom_p=new Vec_Dp(n)

//xicom_p=new Vec_Dp(n)

nrfunc=func

//Vec_Dp &pcom=*pcom_p,&xicom=*xicom_p

double *pcom = pcom_p, *xicom = xicom_p

for (j=0j<nj++) {

pcom[j]=p[j]

xicom[j]=xi[j]

}

ax=0.0

xx=1.0

mnbrak(ax,xx,bx,fa,fx,fb,f1dim)

fret=brent(ax,xx,bx,f1dim,TOL,xmin, flag)

for (j=0j<nj++) {

xi[j] *= xmin

p[j] += xi[j]

}

//delete xicom_p

//delete pcom_p

}

inline bool TOptimization::powell(double *p, double **xi, double ftol, int &iter,

double &fret, Reff func)

{

const int ITMAX=500

const double TINY=1.0e-20

int i,j,ibig

double del,fp,fptt,t

int n=num

//Vec_Dp pt(n),ptt(n),xit(n)

double *pt, *ptt, *xit

for(i = 0i <n++i)

{

pt = new double [n]

ptt = new double [n]

xit = new double [n]

}

fret=func(p)

for (j=0j<nj++) pt[j]=p[j]

for (iter=0++iter) {

fp=fret

ibig=0

del=0.0

for (i=0i<ni++) {

for (j=0j<nj++) xit[j]=xi[j][i]

fptt=fret

linmin(p,xit,fret,func)

if (fptt-fret >del) {

del=fptt-fret

ibig=i+1

}

}

if (2.0*(fp-fret) <= ftol*(fabs(fp)+fabs(fret))+TINY) {

delete []pt

delete []ptt

delete []xit

return true

}

if (iter == ITMAX)

{

delete []pt

delete []ptt

delete []xit

return false

//cerr<<"powell exceeding maximum iterations."

}

for (j=0j<nj++) {

ptt[j]=2.0*p[j]-pt[j]

xit[j]=p[j]-pt[j]

pt[j]=p[j]

}

fptt=func(ptt)

if (fptt <fp) {

t=2.0*(fp-2.0*fret+fptt)*SQR(fp-fret-del)-del*SQR(fp-fptt)

if (t <0.0) {

linmin(p,xit,fret,func)

for (j=0j<nj++) {

xi[j][ibig-1]=xi[j][n-1]

xi[j][n-1]=xit[j]

}

}

}

}

}

#endif