IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jan 23, 2018, 10:11:50 AM (9 years ago)
Author:
eugene
Message:

working on nnet

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Ohana/src/opihi/cmd.data/nnet_train.c

    r40318 r40319  
    11# include "data.h"
    2 void sortseq (float *X, int *Y, int N);
     2
     3// these are local only
     4float nnet_sigmoid (float value);
     5void  nnet_sortseq (float *X, int *Y, int N);
     6int   nnet_onelayer (Nnet *nnet, int L);
     7void  nnet_reset_Nabla (Nnet *nnet);
     8void  nnet_update_Nabla (Nnet *nnet);
     9void  nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta);
     10void  nnet_backprop (Nnet *nnet, Vector **inVec, Vector **outVec, int N);
     11void  nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta);
    312
    413int nnet_train (int argc, char **argv) {
     14
     15  int N;
    516
    617  int Nepoch = 10;
     
    1829  }
    1930 
     31  float eta = 1.0; // XXX how do I set this? does it need to update?
     32
    2033  if (argc < 4) {
    2134    gprint (GP_ERR, "USAGE: nnet train (nnet) [input] [input] ... [output] [output] ...\n");
     
    97110    // generate a random sequence : used to select random mini batches
    98111    for (int i = 0; i < Ntrial; i++) { seq[i] = i; rnd[i] = drand48(); }
    99     sortseq (rnd, seq, Ntrial);
     112    nnet_sortseq (rnd, seq, Ntrial);
    100113
    101114    int Npass = Ntrial / Nmini;
     
    116129
    117130// this recreates 'update_mini_batch' from http://neuralnetworksanddeeplearning.com/chap1.html
    118 void nnet_descent_step (NNet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta) {
     131void nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta) {
    119132
    120133  int Ntrial = inVec[0][0].Nelements;
     
    122135  nnet_reset_Nabla (nnet);
    123136
    124   for (i = 0; (i < Nmini) && (pass*Nmini + i < Ntrial); i++) {
     137  for (int i = 0; (i < Nmini) && (pass*Nmini + i < Ntrial); i++) {
    125138
    126139    // N is the element of the mini batch on which we are currently operating
    127     N = seq[pass*Nmini + i];
     140    int N = seq[pass*Nmini + i];
    128141
    129142    // backprop generates a dNabla_b, dNabla_w pair for the element N of the input and output vectors
     
    136149}
    137150
    138 void nnet_backprop (NNet *nnet, Vector **inVec, Vector **outVec, int N) {
     151void nnet_backprop (Nnet *nnet, Vector **inVec, Vector **outVec, int N) {
    139152
    140153  // start with the input values
    141 
    142   // store the input values for this row (trial) in the input value vector
    143154  int Nlayer   = nnet[0].Nlayer;
    144   int Ninput   = nnet[0].Nnodes[0];
    145   int Noutput  = nnet[0].Nnodes[Nlayer - 1];  // number of input + output nodes
    146 
    147   for (int j = 0; j < Ninput; j++) {
     155
     156  // store the input values for this row (trial) in the input vector "svalue[0]"
     157  for (int j = 0; j < nnet[0].Nnodes[0]; j++) {
    148158    nnet[0].svalue[0][j] = inVec[j][0].elements.Flt[N];
    149159  }
     
    153163  // activation = sigmoid (z)
    154164
     165  // feedforward operates on the vector saved in svalue[0]
     166  // feedforward saves the zvalues [w * input + bias], svalues [sigmoid(z)], sprimes [sigmoid'(z)] as it runs
    155167  nnet_feedforward (nnet);
    156168
    157   // backward pass (note for now these are vector operations:
    158   for (L = Nlayer - 1; L > 0; L--) {
    159 
    160     // sp is array of same size as zvalue for each layer
    161     // sp = sigmoid_prime (nnet[0].zvalue[L]); sprime is precalculated in feedforward
     169  // backward pass
     170  for (int L = Nlayer - 1; L > 0; L--) {
    162171
    163172    if (L == Nlayer - 1) {
    164173      // starting point uses cost_derivative to compare last svalue set with truth output
    165       // delta = cost_derivative(nnet[0].svalue[L], outVec, N) * sprime[L];
     174      // delta = cost_derivative(svalue[L], output) * sprime[L];
    166175      for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    167         nnet[0].delta[L][j] = cost_derivative(nnet[0].svalue[L][j], outVec[j][0].elements.Flt[N]) * nnet[0].sprime[L][j];
     176        // cost_derivative (svalue[L][j], output[j]) = svalue[L][j] - output[j]
     177        // (because cost = (1/2)(svalue[L][j] - output[j])^2)
     178        // NOTE: the (1/Npt) factor is pushed to the apply_Nabla step
     179        // nnet[0].delta[L][j] = cost_derivative(nnet[0].svalue[L][j], outVec[j][0].elements.Flt[N]) * nnet[0].sprime[L][j];
     180        nnet[0].delta[L][j] = (nnet[0].svalue[L][j] - outVec[j][0].elements.Flt[N]) * nnet[0].sprime[L][j];
    168181      }
    169182    } else {
    170       // delta = (delta DOT transpose(weights[L+1])) * sp;
     183      // delta = DOT(delta, transpose(weight[L+1])) * sprime;
    171184      for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    172         tmpdelta = 0;
     185        float tmpdelta = 0.0;
    173186        for (int i = 0; i < nnet[0].Nnodes[L+1]; i++) {
    174           int k = j + i*nnet[0].Nnodes[L];
    175           tmpdelta += nnet[0].weight[L][k] * nnet[0].delta[L+1][i]; // XXX check on the index values
     187          int k = j + i*nnet[0].Nnodes[L]; // note order of (i,j) : j is [L+1] direction
     188          tmpdelta += nnet[0].weight[L][k] * nnet[0].delta[L+1][i];
    176189        }
    177190        nnet[0].delta[L][j] = tmpdelta * nnet[0].sprime[L][j];
     
    179192    }                                         
    180193
    181     // UPDATE
    182     Nabla_b[L] = delta;
     194    // NOTE on weight array: for a given layer, L, the matrix weight[L] maps the nodes in
     195    // the previous layer (L-1) to those in L: Nnodes[L-1] -> Nnodes[L].  This is a matrix
     196    // with dimensions (Nnodes[L-1] x Nnodes[L]).  The Nnodes[L-1] is the fast dimension,
     197    // so for an element (i,j), the index k = i + j*Nnodes[L-1].   
     198
     199    // Nabla_b[L] = delta;
     200    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     201      nnet[0]. Nabla_b[L][j] = nnet[0].delta[L][j];
     202    }
    183203   
    184     // Nabla_w[L] = delta DOT transpose(nnet[0].svalue[L-1]);
     204    // Nabla_w[L] = DOT(delta, transpose(svalue[L-1]));
    185205    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    186206      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
    187         int k = i + j*nnet[0].Nnodes[n-1];
    188         nnet[0]. Nabla_w[n][k] = nnet[0].svalue[L-1][i] * nnet[0].delta[L][j];
    189       }
    190     }
    191 
     207        int k = i + j*nnet[0].Nnodes[L-1];
     208        nnet[0]. Nabla_w[L][k] = nnet[0].svalue[L-1][i] * nnet[0].delta[L][j];
     209      }
     210    }
    192211  }
    193212}
    194213
    195214// support functions to loop over the Nabla entries
    196 void nnet_apply_Nabla (NNet *nnet, int Nmini, float eta) {
    197   for (int n = 1; n < nnet[0].Nlayer; n++) {
    198 
    199     for (int j = 0; j < nnet[0].Nnodes[n]; j++) {
    200       nnet[0].biases[n][j] -= (eta / Nmini) * nnet[0].Nabla_b[n][j];
    201 
    202       for (int i = 0; i < nnet[0].Nnodes[n-1]; i++) {
    203         int k = i + j*nnet[0].Nnodes[n-1];
    204         nnet[0].weights[n][k] -= (eta / Nmini) * nnet[0].Nabla_w[n][k];
    205       }
    206     }
    207   }
    208 }
    209 void nnet_update_Nabla (NNet *nnet) {
    210   for (int n = 1; n < nnet[0].Nlayer; n++) {
    211 
    212     for (int j = 0; j < nnet[0].Nnodes[n]; j++) {
    213       nnet[0]. Nabla_b[n][j] += nnet[0].dNabla_b[n][j];
    214 
    215       for (int i = 0; i < nnet[0].Nnodes[n-1]; i++) {
    216         int k = i + j*nnet[0].Nnodes[n-1];
    217         nnet[0]. Nabla_w[n][k] += nnet[0].dNabla_w[n][k];
    218       }
    219     }
    220   }
    221 }
    222 void nnet_reset_Nabla (NNet *nnet) {
    223   for (int n = 1; n < nnet[0].Nlayer; n++) {
    224 
    225     for (int j = 0; j < nnet[0].Nnodes[n]; j++) {
    226 
    227       nnet[0]. Nabla_b[n][j] = 0;
    228       nnet[0].dNabla_b[n][j] = 0;
    229 
    230       for (int i = 0; i < nnet[0].Nnodes[n-1]; i++) {
    231         int k = i + j*nnet[0].Nnodes[n-1];
    232         nnet[0]. Nabla_w[n][k] = 0;
    233         nnet[0].dNabla_w[n][k] = 0;
     215void nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta) {
     216  for (int L = 1; L < nnet[0].Nlayer; L++) {
     217
     218    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     219      nnet[0].biases[L][j] -= (eta / Nmini) * nnet[0].Nabla_b[L][j];
     220
     221      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
     222        int k = i + j*nnet[0].Nnodes[L-1];
     223        nnet[0].weight[L][k] -= (eta / Nmini) * nnet[0].Nabla_w[L][k];
     224      }
     225    }
     226  }
     227}
     228void nnet_update_Nabla (Nnet *nnet) {
     229  for (int L = 1; L < nnet[0].Nlayer; L++) {
     230
     231    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     232      nnet[0]. Nabla_b[L][j] += nnet[0].dNabla_b[L][j];
     233
     234      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
     235        int k = i + j*nnet[0].Nnodes[L-1];
     236        nnet[0]. Nabla_w[L][k] += nnet[0].dNabla_w[L][k];
     237      }
     238    }
     239  }
     240}
     241void nnet_reset_Nabla (Nnet *nnet) {
     242  for (int L = 1; L < nnet[0].Nlayer; L++) {
     243
     244    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     245
     246      nnet[0]. Nabla_b[L][j] = 0;
     247      nnet[0].dNabla_b[L][j] = 0;
     248
     249      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
     250        int k = i + j*nnet[0].Nnodes[L-1];
     251        nnet[0]. Nabla_w[L][k] = 0;
     252        nnet[0].dNabla_w[L][k] = 0;
    234253      }
    235254    }
     
    238257
    239258// the input values must already be copied to the input layer svalue[]
    240 void nnet_feedforward (NNet *nnet) {
     259void nnet_feedforward (Nnet *nnet) {
    241260
    242261  for (int i = 1; i < nnet[0].Nlayer; i++) {
     
    246265}
    247266
    248 // calcularte z, sigmoid(z) for each layer (z = w*value + bias)
    249 int nnet_onelayer (NNet *nnet, int n) {
    250 
    251   if (n < 1) return FALSE; // abort here?
    252   if (n >= nnet[0].Nlayer) return FALSE; // abort here?
    253 
    254   // evaluating a single layer [n], n > 0, n < Nlayer:
    255   int Ninput   = nnet[0].Nnodes[n - 1];
    256   int Noutput  = nnet[0].Nnodes[n];
    257 
    258   // input layer is [n-1], output layer is [n]
     267// calculate z, sigmoid(z) for each layer (z = w*value + bias)
     268int nnet_onelayer (Nnet *nnet, int L) {
     269
     270  if (L < 1) return FALSE; // abort here?
     271  if (L >= nnet[0].Nlayer) return FALSE; // abort here?
     272
     273  // evaluating a single layer [L], n > 0, n < Nlayer:
     274  int Ninput   = nnet[0].Nnodes[L - 1];
     275  int Noutput  = nnet[0].Nnodes[L];
     276
     277  // input layer is [L-1], output layer is [L]
    259278  for (int j = 0; j < Noutput; j ++) {
    260279    float sum = 0;
     
    262281      // weight matrix order is (0, 1, ... Ninput-1, Ninput, Ninput + 1, ... Ninput * Noutput - 1)
    263282      int k = j * Ninput + i;
    264       sum += nnet[0].weight[n][k]*nnet[0].svalue[n-1][i];
    265     }
    266     sum += nnet[0].biases[n][j];
    267     nnet[0].zvalue[n][j] = sum;
    268     nnet[0].svalue[n][j] = nnet_sigmoid(sum);
    269     nnet[0].sprime[n][j] = nnet[0].svalue[n][j] * (1 - nnet[0].svalue[n][j]);
     283      sum += nnet[0].weight[L][k]*nnet[0].svalue[L-1][i];
     284    }
     285    sum += nnet[0].biases[L][j];
     286    nnet[0].zvalue[L][j] = sum;
     287    nnet[0].svalue[L][j] = nnet_sigmoid(sum);
     288    nnet[0].sprime[L][j] = nnet[0].svalue[L][j] * (1 - nnet[0].svalue[L][j]);
    270289    // note that d sigmoid / dz = sigmoid * (1 - sigmoid)
    271290  }
     
    274293
    275294float nnet_sigmoid (float value) {
    276   return 1.0 / (1.0 + exp(-sum));
    277 }
    278 
    279 void sortseq (float *X, int *Y, int N) {
     295  return 1.0 / (1.0 + exp(-value));
     296}
     297
     298void nnet_sortseq (float *X, int *Y, int N) {
    280299
    281300# define SWAPFUNC(A,B){ float ftmp; int itmp; \
Note: See TracChangeset for help on using the changeset viewer.