Autor Wątek: SSN - prognozowanie ryzyka ubezpieczeniowego  (Przeczytany 3588 razy)

Offline hornet

  • Użytkownik

# Wrzesień 15, 2014, 12:47:46
Zaczynam przygodę z Sieciami Neuronowymi. Mam projekt do rozpoznawania liter, czy XOR. Aczkolwiek teraz pracuję sobie nad prognozowaniem ryzyka ubezpieczeniowego. Założenie jest takie, że sieć ma rozpoznawać 7 klas ryzyka.
Czy dobrze myślę, że w tym przypadku jako aktywację uznaję potencjał membranowy i zważoną sumę neuronu przepuszczam przez funkcję prognozującą?

Dodam, że nie jest to żaden projekt w pracy, tylko się uczę i chociaż teorię ogarniam to w praktyce nie wszystko mi wychodzi.

Program w C++.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline koirat

  • Użytkownik

# Wrzesień 15, 2014, 17:01:31
Zakładam iż używasz sieci typu Multi Layer Perceptron bo zazwyczaj pisząc sieć neuronowa ludzie mają to na myśli.

Cytuj
Czy dobrze myślę, że w tym przypadku jako aktywację uznaję potencjał membranowy i zważoną sumę neuronu przepuszczam przez funkcję prognozującą?
Przepraszam ale to chyba jakiś bełkot.

Offline hornet

  • Użytkownik

# Wrzesień 15, 2014, 17:13:26
To może inaczej.
Jakiej funkcji aktywacji użyć, bądź jak zmodyfikować program, by na wyjściu uzyskać klasę od 0 do 6?

Offline mwojt

  • Użytkownik

# Wrzesień 15, 2014, 18:46:20
Cytuj
by na wyjściu uzyskać klasę od 0 do 6?
Albo 6 wyjść (zera i jedna jedynka) albo jedno wyjście i wartości 6/6, 6/5, 6/4... ale raczej to pierwsze.

Offline koirat

  • Użytkownik

# Wrzesień 15, 2014, 19:49:36
6 wyjść jak już było wspomniane. Zwracające z przedziału 0-1 jako stopień przynależności do danej klasy. Funkcja aktywacji może być np sigmoidalna.

Offline hornet

  • Użytkownik

# Wrzesień 16, 2014, 10:18:00
Dzięki wielkie za odpowiedź ;)

Offline hornet

  • Użytkownik

# Wrzesień 19, 2014, 14:25:48
Mam sieć, ale nie działa to dobrze. Czy może mi ktoś podpowiedzieć co jest jeszcze nie tak?

Mam 3 warstwy w sumie: wejście 10 neuronów, ukryta 10 neuronów, wyjście 1 neuron. Dla dwóch pierwszych warstw mam funkcję aktywacji w postaci f(x)=1/1+exp(-a*x), na wyjściu liczę sumę wyjść w poprzedniej warstwie, czyli mam liniową.

Pochodne+Gradient+Aktualizacja wag:
   //obliczanie pochodnych wszystkich neuronów d[i],d1[i],d2[i] = pochodna
                    for(i=0; i<=9; i++) //pochodna trzeciej warstwy
                        {   
                            d2[i]=0;
                            d2[i]=1;
                            //cout<<"d2= "<<d2[i]<<endl;
                        }
                    for(i=0; i<=9; i++)//pochodna drugiej warstwy
                        {   
                            d1[i]=0;                   
                            d1[i]=a*y[i]*(1-y[i]);
                            //cout<<"d1= "<<d1[i]<<endl;
                        }
                    for(i=0; i<=9; i++)//pochodna pierwszej warstwy
                        {   
                            d[i]=0;
                            d[i]=a*v[i]*(1-v[i]);
                            //cout<<"d= "<<d[i]<<endl;
                        }
                 
                    for(j=0;j<=10;j++)//gradient w trzeciej warstwie
                        {
                            dwd2[j]=(pomocnicza2-z_nom[ie])*d2[j]*pomocnicza2;                           
                            //cout<<"dwd2= "<<dwd2[j]<<endl;
                        }
                    for(j=0;j<=9;j++)//gradient w drugiej warstwie
                        for(i=0;i<=10;i++)
                                         {
                                            dwd1[j][i]=(pomocnicza2-z_nom[ie])*d2[i]*w30[j]*a*d1[i]*e[i];
                                          //cout<<"dwd1= "<<dwd1[i][j]<<endl;
                                          }

                                         
                    for(j=0;j<=9;j++)//gradient w pierwszej warstwie
                        for(i=0;i<=10;i++)
                                          {
                                             dwd[j][i]=(pomocnicza2-z_nom[ie])*d2[i]*w30[i]*alfa*d1[i]*e[i]*w20[j][i]*alfa*d[i]*u[i];                                         
                                          //cout<<"dwd= "<<dwd[i][j]<<endl;
                                          }
                   

                    for(i=0;i<=9;i++)
                        for(j=0;j<=10;j++)
                            w12[i][j]=w11[i][j];
                    for(i=0;i<=9;i++)
                        for(j=0;j<=10;j++)
                            w22[i][j]=w21[i][j];
                    for(i=0;i<=9;i++)
                        for(j=0;j<=10;j++)
                            w11[i][j]=w10[i][j];
                    for(i=0;i<=9;i++)
                        for(j=0;j<=10;j++)
                            w21[i][j]=w20[i][j];
                   
                   for(i=0;i<=10;i++)
                        w32[i]=w31[i];
                   for(i=0;i<=10;i++)
                        w31[i]=w30[i];
                       
                   
                    //aktualizacja wag WSZYTSKICH neuronów
                    //aktualizacja wag dla warstwy WYJŚCIOWEJ
                        for(i=0;i<=9;i++)
                            {       
                                        dW2[i]=beta*(w31[i]-w32[i]);                         
                                        if(error>1.04*ograniczenie_celu)
                                            {
                                                dW2[i]=0;     
                                            }             
                                        w30[i]=w30[i]-(-alfa*dwd2[i]+dW2[i]);
                            }
                    //aktualizacja wag dla drugiej warstwy
                        for(i=0;i<=9;i++)
                            {
                                for(j=0;j<=10;j++)
                                    {   
                                        dW1[i][j]=beta*(w21[i][j]-w22[i][j]);
                                        if(error>1.04*ograniczenie_celu)
                                            {
                                                dW1[i][j]=0;
                                            }
                                        w20[i][j]=w20[i][j]-(-alfa*dwd1[i][j]+dW1[i][j]);
                                    }
                                   
                            }
                    //aktualizacja wag dla pierwszej warstwy
                        for(i=0;i<=9;i++)
                            {
                                for(j=0;j<=10;j++)
                                        dW[i][j]=beta*(w11[i][j]-w12[i][j]);
                                        if(error>1.04*ograniczenie_celu)
                                            {
                                                dW[i][j]=0;
                                            }             
                                        w10[i][j]=w10[i][j]-(-alfa*dwd[i][j]+dW[i][j]);
                                    }
                                   
                            }   

d,d1,d2 - pochodne każdej z funkcji
dwd,dwd1,dwd2 -gradienty dla każdej warstwy
dW,dW1,dW2 -poprzednia zmiana wag
Dane na wejściach to np. 1   48   70   190   0   68   67   0   1   2, wartość oczekiwana 3. Uwzględniałam na neuronach bias=1;
Co ja pokręciłam?
« Ostatnia zmiana: Wrzesień 19, 2014, 14:30:32 wysłana przez hornet »

Offline koirat

  • Użytkownik

# Wrzesień 19, 2014, 15:38:19
Jeśli problemem są wartości liczbowe a nie wyjątki albo źródło które się nie kompiluje. To jesteś w stanie sam sobie to sprawdzić.

Zacznij od pojedynczego perceptronu zobacz czy dobrze liczy, następnie dodaj drugi neuron jako warstwę ukrytą, zobacz czy dobrze liczone są wartości. Później dodaj nowe neurony do tych warstw. A sieć raczej testuj na problemie prostym np: xor gdzie 3 perceptrony wystarczą a nie od razu na 10.

Wiem że to wszystko jest pracochłonne, sam przez to przechodziłem.

Offline hornet

  • Użytkownik

# Wrzesień 19, 2014, 15:48:32
Wszystkie neurony w każdej warstwie liczą zgodnie z zadaną funkcją.
Jedna próbka to 10 danych.

Czy ta część kodu którą przedstawiłam jest w ogóle prawidłowa? Bo nie jestem pewna czy dobrze liczę gradienty i pochodne. Generalnie problem jest przy aktualizacji wag, wyjście mi się zatrzymuje na np. 6.32.... i różnią się wyłącznie końcówką. Sprawdzałam jak aktualizują się wagi i są to niezwykle małe aktualizacje.

Pracowałam nad tym cały wczorajszy dzień i też jestem zmęczona, dlatego może nie dostrzegam jakiegoś błędu w tych moich wypocinach?

Offline albireo

  • Użytkownik

# Wrzesień 19, 2014, 17:40:06
Problemem jest raczej to, że dałaś na wyjściu 1 neuron, gdzie powinno być ich 7 (oznaczających klasy od 0 do 6), i wynikiem jest ten numer do którego przypisany neuron ma największą wartość wyjściową (ewentualnie jakoś uwzględniasz inne wyjścia, jeśli w sytuacji której np wyjdą wysokie wartości na 2 i 4 a reszta mała i chcesz mieć wtedy 3). Do uczenia dajesz wtedy na wyjściu 1 na neuronie odpowiadającym oczekiwanej klasyfikacji, i 0 dla pozostałych.

Offline hornet

  • Użytkownik

# Wrzesień 19, 2014, 20:46:14
Wielkie dzięki, wszystko jasne, czasami potrzebuję bardziej łopatologicznie. To pracuję nad tym dalej
:)


Offline hornet

  • Użytkownik

# Wrzesień 20, 2014, 13:50:28
Zrobiłam dokładnie tak jak opisałeś, ale niestety, dalej mam coś pomieszanie. Generalnie problem jest w aktualizacji wag według mnie, bo wartości wyjścia wyłącznie rosną, a dodatkowo jeden neuron zawsze ma przewagę nad innymi.
Problem pojawia się przy dowolnej ilości iteracji, i dowolnej ilości próbek uczących.
Aktualizacja wag przebiega u mnie następująco:
//aktualizacja wag dla drugiej warstwy(wyjście)
                        for(i=0;i<=7;i++)
                            {
                                for(j=0;j<=10;j++)
                                    {   
                                        dW1[i][j]=beta*(w21[i][j]-w22[i][j]);
                                        if(error>1.04*ograniczenie_celu)
                                            {
                                                dW1[i][j]=0;
                                                //dW2[i][j]=0;
                                            }           

                                        w20[i][j]=w20[i][j]-(-alfa*dwd1[i][j]+dW1[i][j]);
                                    }
                                 
                            }
                    //aktualizacja wag dla pierwszej warstwy
                        for(i=0;i<=9;i++)
                            {
                                for(j=0;j<=10;j++)
                                    {   
                                        dW[i][j]=beta*(w11[i][j]-w12[i][j]);
                                        if(error>1.04*ograniczenie_celu)
                                            {
                                                dW[i][j]=0;
                                            }           
                                        w10[i][j]=w10[i][j]-(-alfa*dwd[i][j]+dW[i][j]);
                                       
                                    }
                                 
                            }                   

gdzie alfa i beta równają się 0.1
pochodne liczę:
for(i=0; i<=7; i++)
                        { 
                            d1[i]=0;
                            d1[i]=a*y[i]*(1-y[i]);
                        }
                    for(i=0; i<=9; i++)
                        { 
                            d[i]=0;
                            d[i]=a*v[i]*(1-v[i]);
                        }
a gradienty:
for(i=0;i<=7;i++)
                        for(j=0;j<=9;j++)
                                         { dwd1[i][j]=(y[i]-tablica_z[ie][j])*d1[i]*e[j];
                                          }

                                         
                    for(i=0;i<=9;i++)
                        for(j=0;j<=9;j++)
                                          {
dwd[i][j]=(y[i]-tablica_z[ie][j])*a*d1[i]*e[i]*w20[i][j]*a*d[i]*u[i];
                                          }

tablica_z[ie][j] - tablica wartości zadanych

Możecie mi pomóc?

Offline koirat

  • Użytkownik

# Wrzesień 20, 2014, 14:21:23
Obawiam się że nikt ci tego nie sprawdzi

A zapiski tego typu:
dwd[i][j]=(y[i]-tablica_z[ie][j])*a*d1[i]*e[i]*w20[i][j]*a*d[i]*u[i];
Nie zachęcają.

Pierwsze co powinnaś zrobić to ogarnąć źródło bo cały ten program wygląda na napisany dość słabo.
Na twoim miejscu zrobił bym np tak.

Pobranie wagi pomiędzy neuronem w poprzedniej i następnej warstwie, realizowane przez funkcję
float GetWeight(int layer,int layerNeuronIndex, int nextLayerNeuronIndex);

ustawienie wagi
void SetWeight(int layer,int layerNeuronIndex, int nextLayerNeuronIndex,float value);

podobnie zrobił bym dla innych danych takich jak np błędy.


Ściągnołem z netu na szybko jakąś wersje pobaw się tym:
////////////////////////////////////////////////////////////////////////////
//MLP neural network in C++
//Original source code by Dr Phil Brierley
//www.philbrierley.com
//Translated to C++ - dspink Sep 2005
//This code may be freely used and modified at will
//C++ Compiled using Bloodshed Dev-C++ free compiler http://www.bloodshed.net/
//C Compiled using Pelles C free windows compiler http://smorgasbordet.com/
////////////////////////////////////////////////////////////////////////////

//#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>


//// Data dependent settings ////
#define numInputs  3
#define numPatterns  4


//// User defineable settings ////
#define numHidden 4
const int numEpochs = 500;
const double LR_IH = 0.7;
const double LR_HO = 0.07;


//// functions ////
void initWeights();
void initData();
void calcNet();
void WeightChangesHO();
void WeightChangesIH();
void calcOverallError();
void displayResults();
double getRand();


//// variables ////
int patNum = 0;
double errThisPat = 0.0;
double outPred = 0.0;
double RMSerror = 0.0;

// the outputs of the hidden neurons
double hiddenVal[numHidden];

// the weights
double weightsIH[numInputs][numHidden];
double weightsHO[numHidden];

// the data
int trainInputs[numPatterns][numInputs];
int trainOutput[numPatterns];


//==============================================================
//************** function definitions **************************
//==============================================================


//***********************************
// calculates the network output
void calcNet(void)
{
    //calculate the outputs of the hidden neurons
    //the hidden neurons are tanh
    int i = 0;
    for(i = 0;i<numHidden;i++)
    {
  hiddenVal[i] = 0.0;

        for(int j = 0;j<numInputs;j++)
        {
   hiddenVal[i] = hiddenVal[i] + (trainInputs[patNum][j] * weightsIH[j][i]);
        }

        hiddenVal[i] = tanh(hiddenVal[i]);
    }

   //calculate the output of the network
   //the output neuron is linear
   outPred = 0.0;

   for(i = 0;i<numHidden;i++)
   {
    outPred = outPred + hiddenVal[i] * weightsHO[i];
   }
    //calculate the error
    errThisPat = outPred - trainOutput[patNum];

}


//************************************
//adjust the weights hidden-output
void WeightChangesHO(void)
{
   for(int k = 0;k<numHidden;k++)
   {
    double weightChange = LR_HO * errThisPat * hiddenVal[k];
    weightsHO[k] = weightsHO[k] - weightChange;

    //regularisation on the output weights
    if (weightsHO[k] < -5)
    {
     weightsHO[k] = -5;
    }
    else if (weightsHO[k] > 5)
    {
     weightsHO[k] = 5;
    }
   }

 }


//************************************
// adjust the weights input-hidden
void WeightChangesIH(void)
{

  for(int i = 0;i<numHidden;i++)
  {
   for(int k = 0;k<numInputs;k++)
   {
    double x = 1 - (hiddenVal[i] * hiddenVal[i]);
    x = x * weightsHO[i] * errThisPat * LR_IH;
    x = x * trainInputs[patNum][k];
    double weightChange = x;
    weightsIH[k][i] = weightsIH[k][i] - weightChange;
   }
  }

}


//************************************
// generates a random number
double getRand(void)
{
 return ((double)rand())/(double)RAND_MAX;
}



//************************************
// set weights to random numbers
void initWeights(void)
{

 for(int j = 0;j<numHidden;j++)
 {
    weightsHO[j] = (getRand() - 0.5)/2;
    for(int i = 0;i<numInputs;i++)
    {
     weightsIH[i][j] = (getRand() - 0.5)/5;
     printf("Weight = %f\n", weightsIH[i][j]);
    }
  }

}


//************************************
// read in the data
void initData(void)
{
    printf("initialising data\n");

    // the data here is the XOR data
    // it has been rescaled to the range
    // [-1][1]
    // an extra input valued 1 is also added
    // to act as the bias
    // the output must lie in the range -1 to 1

    trainInputs[0][0]  = 1;
    trainInputs[0][1]  = -1;
    trainInputs[0][2]  = 1;    //bias
    trainOutput[0] = 1;

    trainInputs[1][0]  = -1;
    trainInputs[1][1]  = 1;
    trainInputs[1][2]  = 1;       //bias
    trainOutput[1] = 1;

    trainInputs[2][0]  = 1;
    trainInputs[2][1]  = 1;
    trainInputs[2][2]  = 1;        //bias
    trainOutput[2] = -1;

    trainInputs[3][0]  = -1;
    trainInputs[3][1]  = -1;
    trainInputs[3][2]  = 1;     //bias
    trainOutput[3] = -1;

}


//************************************
// display results
void displayResults(void)
{
 for(int i = 0;i<numPatterns;i++)
 {
  patNum = i;
  calcNet();
  printf("pat = %d actual = %d neural model = %f\n",patNum+1,trainOutput[patNum],outPred);
 }
}


//************************************
// calculate the overall error
void calcOverallError(void)
{
     RMSerror = 0.0;
     for(int i = 0;i<numPatterns;i++)
        {
         patNum = i;
         calcNet();
         RMSerror = RMSerror + (errThisPat * errThisPat);
        }
     RMSerror = RMSerror/numPatterns;
     RMSerror = sqrt(RMSerror);
}



//==============================================================
//********** THIS IS THE MAIN PROGRAM **************************
//==============================================================


int main(void)
{
 // seed random number function
 srand ( time(NULL) );

 // initiate the weights
 initWeights();

 // load in the data
 initData();

 // train the network
    for(int j = 0;j <= numEpochs;j++)
    {
        for(int i = 0;i<numPatterns;i++)
        {
          //select a pattern at random
          patNum = rand()%numPatterns;

          //calculate the current network output
          //and error for this pattern
          calcNet();

          //change network weights
          WeightChangesHO();
          WeightChangesIH();
        }

        //display the overall network error
        //after each epoch
        calcOverallError();

        printf("epoch = %d RMS Error = %f\n",j,RMSerror);
    }

 //training has finished
 //display the results
 displayResults();


 system("PAUSE");
 return 0;
}



Offline hornet

  • Użytkownik

# Wrzesień 20, 2014, 14:32:15
Ehh, no nie wiem czy na początku robienia każdy zajmował się tym, żeby kod był piękny.
Mój kod jest przejrzysty, nie zachęca, bo pracuję na tablicach głównie, a nie na funkcjach.

Chciałabym jednak skupić się na tym, co mam i doprowadzić to do jakiegoś konkretnego działania, nie musi być idealnie, ale ewidentnie mam gdzieś błąd i nie mogę go znaleźć.

Dzięki za wersję, którą podesłałeś, ale nie takie było moje pytanie, bo proszę o pomoc w tym moim konkretnym przypadku.