Автобиография Магистерская работа Библиотека
Ссылки Индивидуальное задание Отчет о поиске

Ткаченко А.В.

Ткаченко Александр Валерьевич

Тема магистерской работы:
Разработка нейросетевой системы управления котлом энергоблока


//main.cpp
//---------------------------------------------------------------------------

#pragma  hdrstop

#include<iostream.h>
#include<conio.h>
#include<stdio.h>
#include<sys\timeb.h>
#include<dos.h>
#include"net.h"

void  main()
{
      int  LS[3]={1,5,1},bias[2]={1,1},i;
      CTransferFunction  *TF[2]={tansig,purelin};
      double  *input,*output,*h1,*h2;

      //Читаем  данные
      FILE  *f;
      f=fopen("sin.dat","r");
      input=(double*)malloc(sizeof(double)*100*1);
      output=(double*)malloc(sizeof(double)*100*1);
      h1=input;
      h2=output;
      for(int  i=0;i<100;i++)
      {
                for(int  j=0;j<1;j++)
                {
                      fscanf(f,"%lf",h1);
                      h1++;
                }
                for(int  j=0;j<1;j++)
                {
                      fscanf(f,"%lf",h2);
                      h2++;
                }
      }

      fclose(f);
      struct  timeb  t1,t2;
      randomize();
      double  mi=0,mt=0;
      int  fall=0;
      i=0;

      ftime(&t1);

      //создаем  сеть
      //0  -  минимальное  значение  входа
      //6.28  -  максимальное  значение  входа
      //LS  -  структура  слоев
      //bias  -  смещения
      //TF  -  фнкции  активации
      CNeuralNetwork  *net=new  CNeuralNetwork(0,6.28,2,LS,bias,TF);

      //инициализируем  сеть
      net->Init();

      //обучаем  сеть
      //100-число  обучающих  наборов
      //(double  *)input  -  входные  наборы
      //(double  *)output    -  выходные  наборы
      int  k=net->Train(100,(double  *)input,(double  *)output);

      //удаляем  сеть
      delete  net;

      ftime(&t2);
      long  l=1000*(t2.time-t1.time)+t2.millitm-t1.millitm;
      printf("\n  time=%ld",l,t2.millitm,t1.millitm);

      getch();
}



//net.h
//---------------------------------------------------------------------------
#include"layer.h"
#include"c_net.h"

const  double  n_minus=0.5;  //фактор  уменьшения
const  double  n_plus=1.2;    //фактор  уменьшения
const  double  d_min=1e-300;//минимальное  значение  шага
const  double  d_max=50;        //максимально  значение  шага

const  int  show=10;  //показывать  шаги
const  int  max_fall=10000;  //прекратить  обучение
const  double  e=0.001;//Ошибка  обучения

//Класс  нейронная  сеть
class  CNeuralNetwork
{
      private:
            int  numLayers  //число  слоев
                ,numInputs    //число  входов
                ,numOutputs;//число  выходов
            double  *Output;//массив  выхода
            CLayer  **Layers;//слои
            CCNeuralNetwork  *_net;//сорпяженная  нейронная  сеть
            int  N;                                //число  элементов  выборки
            double  Input_min//минимальное  значение  входа
                ,Input_max;//максимальное  значение  входа
            double  *InputT  //вспомогательные  массивы  входа/выхода
                ,*OutputT
                ,*OutputR
                ,*Diff;

            void  Copy_net();//создание  сопряженной  сети
            void  Backpropogation();//обучение
            void  Gradient();//получение  градиента  ошибки
            void  Clear_grad();//очистка  градиента
            void  G_step();//один  шаг  метода  RPROP

      public:
            CNeuralNetwork(int,int,int,int*,int*,CTransferFunction  **);
            ~CNeuralNetwork();

            void  Init();  //инициализация  весовых  коэффициентов
            void  Work(double  *Input);//прямое  распространение
            int  Train(int  n,double  *InputN,double  *OutputN);//обучение
            double  E();//ошибка  обучения
};

//конструктор,  создает  сеть  заданной  размерности
CNeuralNetwork::CNeuralNetwork(int  Input_min,int  Input_max,int  ni,int  *nl,int  *Bias,
                                                        CTransferFunction  **TF)
{
      this->Input_max=Input_max;
      this->Input_min=Input_min;
      numLayers=ni;
      numInputs=nl[0];
      numOutputs=nl[numLayers];
      Layers=(CLayer**)malloc(numLayers*sizeof(void  *));
      Layers[0]=new  CLayer(nl[0],nl[1],Bias[0],TF[0]);
      for(int  i=1;i<numLayers;i++)
      {
            Layers[i]=new  CLayer(nl[i],nl[i+1],Bias[i],TF[i]);
            Layers[i]->Input=Layers[i-1]->Output;
      }
      Output=Layers[numLayers-1]->Output;
}

//деструктор,  освобожает  память
CNeuralNetwork::~CNeuralNetwork()
{
      for(int  i=0;i<numLayers;i++)
            delete  Layers[i];
      free(Layers);
}

//инициализация  весовых  коэффициентов,  метод  Нгуена-Видроу
void  CNeuralNetwork::Init()
{
      int  i,j,k,k1,k2;
      double  *pw,Nmin,Nmax,wmm,wm;
      for(i=0;i<numLayers;i++)
      {
            k1=Layers[i]->numOutputs;
            k2=Layers[i]->numInputs;
            pw=Layers[i]->w;
            if(Layers[i]->Bias&&Layers[i]->TransferFunction->type<10)
            {
                    if(i==0)
                    {
                          Nmin=Input_min;
                          Nmax=Input_max;
                    }else{
                          Nmin=Layers[i-1]->TransferFunction->min;
                          Nmax=Layers[i-1]->TransferFunction->max;
                    }
                    wm=1/(Nmax-Nmin)*pow(Layers[i]->numOutputs,1/Layers[i]->numInputs);
                    for(j=0;j<k1;j++)
                    {
                          for(k=0;k<k2;k++)
                          {
                                *pw=0.7*wm;
                                pw++;
                          }
                          if(Layers[i]->Bias)
                          {
                                *pw=_random(-Nmax*wm,-Nmin*wm);
                                pw++;
                          }
                    }
            }else{
                    k1=k1*(k2+Layers[i]->Bias);
                    for(j=0;j<k1;j++)
                    {
                          *pw=wm*_random(-0.5,0.5);
                          pw++;
                    }
            }
      }
}

//работа  нейронной  сети
void  CNeuralNetwork::Work(double  *Input)
{
      Layers[0]->Input=Input;
      for(int  i=0;i<numLayers;i++)
            Layers[i]->Work();
}

//Обучение  нейронной  сети
int  CNeuralNetwork::Train(int  n,double  *InputN,double  *OutputN)
{
      int  i,  *LS;
      double  e1,e2;
      LS=(int*)malloc((numLayers+1)*sizeof(int));
      LS[0]=numOutputs;
      for(i=0;i<numLayers;i++)
      {
            LS[numLayers-i]=Layers[i]->numInputs;
            Layers[i]->InitDelta();
      }
      _net=new  CCNeuralNetwork(numLayers,LS);
      for(i=0;i<numLayers;i++)
            _net->Layers[numLayers-i-1]->du=Layers[i]->du;
      N=n;
      OutputT=OutputN;
      InputT=InputN;
      OutputR=(double*)malloc(N*numOutputs*sizeof(double));
      Diff=(double*)malloc(N*numOutputs*sizeof(double));
      i=0;
      e2=0;
      do{
            Copy_net();
            Backpropogation();
            G_step();
            e1=e2;
            e2=E();
            if(i%show==0)
            {
                  printf("\n  E=%.6f      %6d",e2,i);
            }
            i++;
      }while(i<max_fall&&e2>e);
      printf("\n  E=%.6f  iteration=%d",e2,i);
      free(LS);
      free(OutputR);
      free(Diff);
      delete  _net;
      return  i;
}

//средняя  квадратичная  ошибка  обучения  нейронной  сети
double  CNeuralNetwork::E()
{
      int  i,k=N*numOutputs;
      double  s=0,*d=Diff;
      for(i=0;i<k;i++)
      {
            s+=(*d)*(*d);
            d++;
      }
      return  s/k;
}

//создание  сопряженной  сети
void  CNeuralNetwork::Copy_net()
{
      int  i,j,k;
      double  *pw;
      for(k=0;k<numLayers;k++)
      {
            pw=Layers[numLayers-k-1]->w;
            for(i=0;i<Layers[numLayers-k-1]->numOutputs;i++)
            {
                  for(j=0;j<Layers[numLayers-k-1]->numInputs;j++)
                  {
                        _net->Layers[k]->Set_w(j,i,*pw);
                        pw++;
                  }
                  pw+=Layers[numLayers-k-1]->Bias;
            }
      }
}

//прогоняем  все  обучающее  множество,  формируем  ошибку  и  ее  градиент
void  CNeuralNetwork::Backpropogation()
{
      int  i,j,k;
      double  *SOutput,*input,  *output,  *dp;
      double  *out1=OutputR,*out2=OutputT;
      SOutput=Layers[numLayers-1]->Output;
      output=OutputR;
      input=InputT;
      dp=Diff;
      Clear_grad();

      for(k=0;k<N;k++)
      {
            Layers[numLayers-1]->Output=output;
            Work(input);
            for(j=0;j<numOutputs;j++)
            {
  *dp=(*out1)-(*out2);
  out1++;
  out2++;
                  dp++;
            }
            _net->Work(dp-numOutputs);
            Gradient();
            input+=numInputs;
            output+=numOutputs;
      }
      Layers[numLayers-1]->Output=SOutput;
}

//формируем  градиент  по  сопряженной  сети
void  CNeuralNetwork::Gradient()
{
      int  k,i,j;
      double  *pg,*_pg;
      for(int  k=0;k<numLayers;k++)
      {
            pg=Layers[k]->grad;
            _pg=_net->Layers[numLayers-k-1]->u;
            for(i=0;i<Layers[k]->numOutputs;i++)
            {
                  for(j=0;j<Layers[k]->numInputs;j++)
                  {
                        *pg=*pg+Layers[k]->Input[j]*(*_pg);
                        pg++;
                  }
                  if(Layers[k]->Bias)
                  {
                        *pg=*pg+*_pg;
                        pg++;
                  }
                  _pg++;
            }
      }
}

//заменеям  старый  градиент  на  новый
void  CNeuralNetwork::Clear_grad()
{
      double  *pg;
      for(int  i=0;i<numLayers;i++)
      {
            pg=Layers[i]->grad2;
            Layers[i]->grad2=Layers[i]->grad;
            Layers[i]->grad=pg;

            Layers[i]->Clear_grad();
      }
}

//шаг  модификации  весов  метода  RPROP
void  CNeuralNetwork::G_step()
{
      int  k,i,l;
      double  *pg1,*pg2,*dg,*pw,sg;
      for(int  k=0;k<numLayers;k++)
      {
            pg1=Layers[k]->grad;
            pg2=Layers[k]->grad2;
            dg=Layers[k]->d_w;
            pw=Layers[k]->w;
            l=Layers[k]->numOutputs*(Layers[k]->numInputs+Layers[k]->Bias);
            for(i=0;i<l;i++)
            {

                  sg=(*pg1)*(*pg2);


                  if(sg>0)
                  {
                            (*dg)*=n_plus;
                            if(*dg>d_max)
                            {
                                *dg=d_max;
                            }
                            *pw=*pw-(*dg)*sign(*pg1);
                  }
                  else
                  {
                            if(sg<0)
                            {
                                    (*dg)*=n_minus;
                                    if(*dg<d_min)
                                    {
                                          *dg=d_min;
                                    }
                                    *pw=*pw-(*dg)*sign(*pg1);
                            }
                            else
                            {
                                    *pw=*pw-(*dg)*sign(*pg1);
                            }
                  }

                  pg1++;
                  pg2++;
                  dg++;
                  pw++;
            }
      }
}


//layer.h
//---------------------------------------------------------------------------
#include"t_func.h"

//класс  слоя  нейронной  сети
class  CLayer
{
      private:
      public:
            int  numInputs  //число  входов
                ,numOutputs  //число  выходов
                ,Bias;    //наличие  веса  смещения
            CTransferFunction  *TransferFunction;  //передаточная  функция
            double
                *w,  //весовые  коэффициенты
                *u,  //результат  суммирования  входов
                *Input,  //вход
                *Output,//выход
                  *grad,//градиент
                  *du,    //сопряженный  коэффициент
                  *grad2,//старый  градиент
                  *d_w;  //приращение  весов
            CLayer(int,int,int,CTransferFunction  *);
            ~CLayer();
            void  Work();  //работа
            void  Clear_grad();//очистка  градиента
            void  InitDelta();  //инициализация  приращения  метода  RPROP
};

CLayer::CLayer(int  ni,int  no,int  Bias,CTransferFunction  *TF)
{
      numInputs=ni;
      numOutputs=no;
      this->Bias=Bias;
      w=(double*)malloc(numOutputs*(numInputs+Bias)*sizeof(double));
      grad=(double*)malloc(numOutputs*(numInputs+Bias)*sizeof(double));
      grad2=(double*)malloc(numOutputs*(numInputs+Bias)*sizeof(double));
      d_w=(double*)malloc(numOutputs*(numInputs+Bias)*sizeof(double));
      u=(double*)malloc(numOutputs*(sizeof(double)));
      du=(double*)malloc(numOutputs*(sizeof(double)));
      Output=(double*)malloc(numOutputs*(sizeof(double)));
      TransferFunction=TF;
}

CLayer::~CLayer()
{
      free(w);
      free(u);
      free(Output);
      free(du);
      free(grad);
      free(grad2);
      free(d_w);
}

//работа  в  прямом  направлении
void  CLayer::Work()
{
      register  double  *pw,  su;
      register  int  i,j;
      pw=w;
      for(i=0;i<numOutputs;i++)
      {
            su=0;
            for(j=0;j<numInputs;j++)
            {
  su+=(*pw)*Input[j];
  pw++;
            }
            if(Bias)
            {
                  su+=(*pw);
                  pw++;
            }
            u[i]=su;
            Output[i]=TransferFunction->f(su);
            du[i]=TransferFunction->_f->f(Output[i]);
      }
}

//очистка  градиета
void  CLayer::Clear_grad()
{
      int  i,k;
      double  *pg;
      k=numOutputs*(numInputs+Bias);
      pg=grad;
      for(i=0;i<k;i++)
      {
            *pg=0;
            pg++;
      }
}

//инициализация  приращения  метода  RPROP
void  CLayer::InitDelta()
{
      int  i,k;
      double  *pg;
      k=numOutputs*(numInputs+Bias);
      pg=d_w;
      for(i=0;i<k;i++)
      {
            *pg=0.05+(random(950))/1000;
            pg++;
      }
}


//t_func.h
//---------------------------------------------------------------------------
#include<stdlib.h>
#include<math.h>

//класс  функция  активации
class  CTransferFunction
{
      public:
            int  type;
            double  min,  max;
            CTransferFunction  *_f;
            virtual  double  __fastcall  f(double)=0;
};

//производная  логарифм-сигмоидальной  функиции
class  CDLogsigTF:public  CTransferFunction
{
      public:
            double  __fastcall  f(double  x)
            {
        double  f=1/(1+exp(-x));
        return    f*(1-f);
            }
};

//логарифм-сигмоидальная  функиция
class  CLogsigTF:public  CTransferFunction
{
      public:
            double  __fastcall  f(double  x){return    1/(1+exp(-x));}
            CLogsigTF()
            {
                  _f=new  CDLogsigTF;
                  min=0;
                  max=1;
                  type=1;
            }
};

//производная  сигмоидальной  функиции
class  CDTansigTF:public  CTransferFunction
{
      public:
            double  __fastcall  f(double  x)
            {
                  return  (1-x*x);
            }
};

//сигмоидальная  функиция
class  CTansigTF:public  CTransferFunction
{
      public:
            double  __fastcall  f(double  x)
            {
                  if(x>50)
                        return  1;
                  if(x<-50)
                        return  -1;

                  double  f1=exp(x);
                  double  f2=exp(-x);
                  return    (f1-f2)/(f1+f2);
            }
            CTansigTF()
            {
                  _f=new  CDTansigTF;
                  min=-1;
                  max=1;
                  type=0;
            }
};

//прозводная  линейной  функции  ==1
class  CDLinerialTF:public  CTransferFunction
{
      public:
            double  __fastcall  f(double  x){  return    1;}
};

//линейная  функция
class  CLinerialTF:public  CTransferFunction
{
      public:
            double  __fastcall  f(double  x){return    x;}
            CLinerialTF()
            {
                  _f=new  CDLinerialTF;
                  min=-100;
                  max=100;
                  type=10;
            }
};

//случайные  числа  из  промежутка
double  __fastcall  _random(double  a,double  b)
{
      return  (b-a)*(random(10001)/10000.0)+a;
}

//случаный  знак
double  __fastcall  _rsign(void)
{
      if(random(2)==0)
        return  1;
      return  -1;
}

//знак
double  __fastcall  sign(double  a)
{
      if(a>0)
        return  1;
      else  if(a<0)
                        return  -1;
                else
                        return  0;
}

//экземпляры  класов  
CLogsigTF  *logsig=new  CLogsigTF();
CTansigTF  *tansig=new  CTansigTF();
CLinerialTF  *purelin=new  CLinerialTF();


//с_net.h
//---------------------------------------------------------------------------
#include"c_layer.h"

//класс  сопряженной  нейронной  сети
class  CCNeuralNetwork
{
      private:
      public:
            int  numLayers  //число  слоев
                ,  numInputs  //число  входов
                ,numOutputs;//число  выходов
            double  *Output;
            CCLayer  **Layers;//слои
            CCNeuralNetwork(int  ni,int  *nl);
            ~CCNeuralNetwork();
            void  Work(double  *Input);//работа  слоя
};

CCNeuralNetwork::CCNeuralNetwork(int  ni,int  *nl)
{
      numLayers=ni;
      numInputs=nl[0];
      numOutputs=nl[numLayers];
      Layers=(CCLayer**)malloc(numLayers*sizeof(void  *));
      Layers[0]=new  CCLayer(nl[0],nl[1]);
      for(int  i=1;i<numLayers;i++)
      {
            Layers[i]=new  CCLayer(nl[i],nl[i+1]);
            Layers[i]->Input=Layers[i-1]->Output;
      }
      Output=Layers[numLayers-1]->Output;
}

CCNeuralNetwork::~CCNeuralNetwork()
{
      for(int  i=0;i<numLayers;i++)
            delete  Layers[i];
      free(Layers);
}

//работа  слоя
void  CCNeuralNetwork::Work(double  *Input)
{
      Layers[0]->Input=Input;
      for(int  i=0;i<numLayers;i++)
            Layers[i]->Work();
}


//с_net.h
//---------------------------------------------------------------------------
#include<stdlib.h>

//класс  сопряженного  слоя
class  CCLayer
{
      private:
      public:
            int  numInputs,  numOutputs;
            double  *w  //веса
                ,*u  //результат  суммирования
                ,*Input  //входы
                ,*Output//выходы
                ,*du;//входные  коэффициенты
            CCLayer(int,int);
            ~CCLayer();
            void  Work();
            void  Set_w(int,int,double);
};

CCLayer::CCLayer(int  ni,int  no)
{
      numInputs=ni;
      numOutputs=no;
      w=(double*)malloc(numOutputs*numInputs*sizeof(double));
      u=(double*)malloc(numInputs*(sizeof(double)));
      Output=(double*)malloc(numOutputs*(sizeof(double)));
}

CCLayer::~CCLayer()
{
      free(w);
      free(u);
      free(Output);
}

void  CCLayer::Work()
{
      register  double  *pw,  su;
      int  i,j;
      for(i=0;i<numInputs;i++)
            u[i]=du[i]*Input[i];
      pw=w;
      for(i=0;i<numOutputs;i++)
      {
            su=0;
            for(j=0;j<numInputs;j++)
            {
              su+=(*pw)*u[j];
              pw++;
            }
            Output[i]=su;
      }
}

//установить  указанный  вес
void  CCLayer::Set_w(int  i,int  j,double  sw)
{
      w[i*numInputs+j]=sw;
}