Метод наискорейшего градиентного спуска с переменным шагом

Форум для обсуждения вопросов математики

Модератор: Admin

maximys
Сообщения: 16
Зарегистрирован: Ср сен 10, 2008 8:58 am

Метод наискорейшего градиентного спуска с переменным шагом

Сообщение maximys » Вс май 30, 2010 9:23 am

Имеется задача: "реализовать алгоритм метода наискорейшего градиентного спуска с переменным шагом для". Вроди бы формулы все есть, вроди бы я разработал и реализовал этот алгоритм согласно этим формулам, но проблема в том, что функция градиента по одной переменной убывает(по переменной X), а по другой очень-очень быстро возрастает(уже после двух проходов функция градиента по переменной Y становится равной 1.2983993*10^52, хотя в самом начале работы, эта величина была примерно равна 100). Формулы, которые у меня имеются, следующие:
F(X[k+1]) = F[X[k] - h*gradF(X[k])]
число h определяется по методу Золотого сечения(к примеру, для функции ( (X^2)/4 + Y^2) это значение высчитывается как минимум по переменной h от (X/2) и от (2Y) <для X и Y шаг h разный>, а левая и правая граница задаются пользователем).
Код на языке ObjectPascal следующий(функция, для которой ищем минимум имеет вид F(X)=(3x - 1.2y + e^[0.02x^2 + 0.3y^2])):

Код: Выделить всё

type
 TFunction1 = function(x:real):real;
 TFunction2 = function(x,y:real):real;
 TPrivateDerivative = function(f:TFunction2; aaV:real):real;
 TArrayWithPrivateDerivative = array[1..10] of function(f:TFunction2; aaV:real):real;


function MethodOfGoldenSection(Fun:TFunction1; Der:TFunction2; a,b:real; eps:real; tau:real):real;
    var h1,h2:real;
        y1,y2:real;
begin
h1:=b - (b - a) * tau;
    h2:=a + (b - a) * tau;
y1:=Fun(h1);
    y2:=Fun(h2);
//--------------------------
while(abs(b-a)>eps) do begin
   if(y2<y1) then begin
      a:=h1;
      h1:=h2;
      y1:=y2;
      h2:=a + (b - a) * tau;
      y2:=fun(h2);
    end
     else begin
         b:=h2;
         h2:=h1;
         y2:=y1;
         h1:=b - (b - a) * tau;
         y1:=fun(h1);
      end;
  end;
MethodOfGoldenSection:=(a + b)/2;
end;

procedure MethodOfGradientDescent(var F:TFile; Func:TFunction2; FuncH:TFunction1; FuncWithDescent:TArrayWithPrivateDerivative; AmountArgumentOfFunc:integer; Sl,Sr:real; epsilon:real; taus:real; var NowArray:TheArray; var aFiXY:real);
  const FirstH: real =10/9;
    var Fxy:real;
        CanStop:boolean;
        i,k:integer;
        h:real;
        grad:real;
        MaxGrad:real;
        NumStep:integer;
begin
h:=FirstH;
NumStep:=0;
CanStop:=false;
while not(CanStop) do begin
    MaxGrad:=0;
    inc(NumStep);
    for k:=1 to AmountArgumentOfFunc do begin
       if(NumStep>1) then
          h:=MethodOfGoldenSection(FuncH, Func, Sl, Sr, epsilon, taus);
       grad:=FuncWithDescent[k](Func, Nowarray[k][2]);
       NowArray[k][2]:=NowArray[k][2] - h*grad;
       if(grad>MaxGrad) then
          MaxGrad:=grad;
       end;
    if(MaxGrad<epsilon) then
        CanStop:=true
      else
           CanStop:=false;
   end;
end;

{===функция для подсчета значения функции F[x,y] = (3x - 1.2y + e^(0.02x^2 + 0.3y^2))}
function MyFunction(aX,aY:real):real;
begin
MyFunction:=3*aX - 1.2*aY + exp(0.02*sqr(aX) + 0.3*sqr(aY));
end;
{==============================================================}

{===функция для подсчета значения функции F[h,h]}
function  MyFunctionH(aH:real):real;
begin
MyFunctionH:=3*aH - 1.2*aH + exp(0.02*sqr(aH) + 0.3*sqr(aH));
end;
{===============================================}


{===функция для вычисления частной производной dF/dX(производной по X)}
function DerivativeX(func:TFunction2; aaX:real):real;
    const ParDer :  real   =0.001;
    const aaY    :  real   =1;    //т.к. это производная по X, то значение Y можно взять любым(оно ни как на значение самой производной не повлияет)
var aaXAddParDer:real;
      ZnacInaaX:real;
      ZnacInaaXAddParDer:real;
begin
aaXAddParDer:=aaX + ParDer;
ZnacInaaX:=func(aaX, aaY);
   ZnacInaaXAddParDer:=func(aaXAddParDer, aaY);
DerivativeX:=(ZnacInaaXAddParDer -  ZnacInaaX)   /   (aaXAddParDer - aaX);
end;

{===функция для вычисления частной производной dF/dY}
function DerivativeY(func:TFunction2; aaY:real):real;
    const ParDer :  real   =0.001;
    const aaX    :  real   =1;    //т.к. это производная по Y, то значение X можно взять любым(оно ни как на значение самой производной не повлияет)
var aaYAddParDer:real;
      ZnacInaaY:real;
      ZnacInaaYAddParDer:real;
begin
aaYAddParDer:=aaY + ParDer;
ZnacInaaY:=func(aaX, aaY);
   ZnacInaaYAddParDer:=func(aaX, aaYAddParDer);
DerivativeY:=(ZnacInaaYAddParDer -  ZnacInaaY)   /   (aaYAddParDer - aaY);
end;


Подскажите пожалуйста, что не так в моем коде? Как я подозреваю, у меня не совсем правильно определяется шаг h(в некоторой литературе написано, что он меняется лишь на каждой итерации<после того, как уточнили все корни> и определяется как минимум из всех возможных своих значений), но на лекциях ничего подобного нам не давали, тупо написано, что шаг меняется при каждой итерации
Учись, Учись и ещё раз Учись!