Автобиография | Магистерская работа | Библиотека |
Ссылки | Индивидуальное задание | Отчет о поиске |
Ткаченко Александр Валерьевич
Разработка нейросетевой системы управления котлом энергоблока |
//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;
}