我制作了这个简单的程序,使用渐变方法计算目标函数的最小值。我测试它是为了一个简单的1D函数(http://en.wikipedia.org/wiki/Gradient_descent),并且它能很好地给我最小的确切位置。
我将它推广到2D函数:x ^ 4 + 2y ^ 4,其中只有(0,0)中的一个零如下:
real*8 function cubic(xvect_old,n)
real(8), dimension(n) :: xvect_old
cubic = 4.d0*(xvect_old(1)**3.d0)+8.d0*(xvect_old(2)**3.d0)
!cubic = 4.d0*(xvect_old(1)**3.d0)-9.d0*(xvect_old(1)**2.d0)
end function cubic
program findmin
implicit none
integer, parameter :: n=2
integer :: i,j,m
real(8) :: cubic
real(8), dimension(n) :: xvect,xvect_old
real(8) :: eps,max_prec
m=30
eps = 0.01d0 ! step size
xvect_old =0.d0
xvect(1) = 2.2d0 ! first guess
xvect(2) = 3.1d0
max_prec = 1e-16
do while ( abs(xvect(1) - xvect_old(1)) > max_prec .and. &
& abs(xvect(2) - xvect_old(2)) > max_prec)
xvect_old(1:2) = xvect(1:2)
xvect(1:2) = xvect_old(1:2) - eps*cubic(xvect_old,n)
end do
print*, "Local minimum occurs at : ", xvect(1:2)
end program findmin
但它给了我,如果我非常接近正确的位置(让我们说,感谢第一次猜测(1.2,1.1))一些大的非正确的解决方案:
( - 0.5017; 0.3982)
方法是否实现错误或者我的理解缺乏方法的准确性?我知道有更先进的方法,比如遗传算法,它们可能更快但是它们也很容易实现吗?
非常感谢。
答案 0 :(得分:1)
cubic
应该返回渐变,因此必须是一个向量。
尝试以下方法:
module functions
implicit none
contains
function cubic(x,n) result(g)
integer, intent(in) :: n
real*8, dimension(n), intent(in) :: x
real*8, dimension(n) :: g
g =(/ 4.d0*(x(1)**3.d0), 8.d0*(x(2)**3.d0) /)
end function cubic
end module
program SOGradient
use functions
implicit none
integer, parameter :: n=2
integer :: i,j,m
real(8), dimension(n) :: xvect,xvect_old
real(8) :: eps,max_prec
m=30
eps = 0.01d0 ! step size
xvect_old =(/ 0.d0, 0d0 /)
! first guess
xvect = (/ 2.2d0, 3.1d0 /)
max_prec = 1e-12
do while ( MAXVAL(ABS(xvect-xvect_old))>max_prec )
xvect_old = xvect
xvect = xvect_old - eps*cubic(xvect_old,n)
end do
print*, "Local minimum occurs at : ", xvect
end program SOGradient
当然越接近最小值,步长越小,收敛速度就越慢。我建议使用牛顿拉夫森类型方法来找到梯度为零的位置。
所以要找到f(x,y)
的最小值,找到渐变g(x,y)=[gx,gy]=[df/dx,df/dy]
和渐变的渐变h(x,y) = [[ dgx/dx, dgx/dy],[dgy/dx, dgy/dy]]
现在你用
进行迭代[x,y] -> [x,y] - h(x,y)^(-1)*g(x,y)
在您的情况下f(x,y) = x^4+2*y^2
,g=[4*x^3, 8*y^3]
和h=[[12*x^2,0],[0,24*y^2]]
[x,y] -> [x,y] - [x/3,y/3]
显然在(0,0)中有一个解,但收敛速度要快得多。