IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Mar 16, 2018, 4:06:05 PM (8 years ago)
Author:
eugene
Message:

fix up the nnet code to match behavior of the python version

File:
1 edited

Legend:

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

    r40336 r40371  
    1010void  nnet_backprop (Nnet *nnet, Vector **inVec, Vector **outVec, int N);
    1111void  nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta, float lambda);
     12void  nnet_print_Nabla (Nnet *nnet);
     13void  nnet_write_Nabla (char *filename, Nnet *nnet);
    1214
    1315static int QUADRATIC_COST = 0;
     
    7678    gprint (GP_ERR, "USAGE: nnet train (nnet) [input] [input] ... [output] [output] ...\n");
    7779    gprint (GP_ERR, "OPTIONS: -Nepoch [N] -Nmini [N]\n");
    78     FREE (resid);
     80    // FREE (resid);
    7981    return FALSE;
    8082  }
     
    8385  if (nnet == NULL) {
    8486    gprint (GP_ERR, "nnet %s not found, create it first\n", argv[1]);
    85     FREE (resid);
     87    // FREE (resid);
    8688    return FALSE;
    8789  }
     
    9597  if (argc != Ninput + Noutput + 2) {
    9698    gprint (GP_ERR, "need %d input and %d output vectors, but we have %d total\n", nnet[0].Nnodes[0], nnet[0].Nnodes[Nlayer - 1], argc - 2);
    97     FREE (resid);
     99    // FREE (resid);
    98100    return FALSE;
    99101  }
     
    111113      free (inVec);
    112114      free (outVec);
    113       FREE (resid);
     115      // FREE (resid);
    114116      return FALSE;   
    115117    }
     
    118120      free (inVec);
    119121      free (outVec);
    120       FREE (resid);
     122      // FREE (resid);
    121123      return FALSE;   
    122124    }
     
    126128      free (inVec);
    127129      free (outVec);
    128       FREE (resid);
     130      // FREE (resid);
    129131      return FALSE;   
    130132    }
     
    136138      free (inVec);
    137139      free (outVec);
    138       FREE (resid);
     140      // FREE (resid);
    139141      return FALSE;   
    140142    }
     
    143145      free (inVec);
    144146      free (outVec);
    145       FREE (resid);
     147      // FREE (resid);
    146148      return FALSE;   
    147149    }
     
    181183  }
    182184
     185  // PrintNnet (nnet);
     186
    183187  // train for Nepochs
    184188  // this recreates 'SGD' from http://neuralnetworksanddeeplearning.com/chap1.html
     
    194198      // update the weights and biases using the mini batch subset
    195199      nnet_descent_step (nnet, inVec, outVec, seq, pass, Nmini, eta, lambda);
    196     }
     200      // return TRUE; // XXX short-circuit at one step
     201    }
     202    // PrintNnet (nnet);
    197203
    198204    if (resid) {
     
    218224      float mean = s1 / Npts;
    219225      float sigma = sqrt(s2 / Npts - mean*mean);
    220       if (epoch % 10 == 0) gprint (GP_ERR, "epoch %d of %d, %f +/- %f\n", epoch, Nepoch, mean, sigma);
     226      // if (epoch % 10 == 0) gprint (GP_ERR, "epoch %d of %d, %f +/- %f\n", epoch, Nepoch, mean, sigma);
     227      gprint (GP_ERR, "epoch %d of %d, %f +/- %f\n", epoch, Nepoch, mean, sigma);
    221228      resid[0].elements.Flt[epoch] = sigma;
    222229    } else {
    223       if (epoch % 10 == 0) gprint (GP_ERR, "epoch %d of %d\n", epoch, Nepoch);
     230      // if (epoch % 10 == 0) gprint (GP_ERR, "epoch %d of %d\n", epoch, Nepoch);
     231      gprint (GP_ERR, "epoch %d of %d\n", epoch, Nepoch);
    224232    }
    225233  } 
     234  // PrintNnet (nnet);
    226235
    227236  if (result) {
     
    265274
    266275    // N is the element of the mini batch on which we are currently operating
    267     int N = seq[pass*Nmini + i];
     276    // int N = seq[pass*Nmini + i]; // XXX uncomment to turn on random shuffle
     277    int N = pass*Nmini + i;
    268278
    269279    // backprop generates a dNabla_b, dNabla_w pair for the element N of the input and output vectors
    270280    nnet_backprop (nnet, inVec, outVec, N);
    271 
    272281    nnet_update_Nabla (nnet);
    273   }
    274 
     282    // gprint (GP_ERR, ". ");
     283
     284    // nnet_print_Nabla (nnet); // XXX print nabla for each epoch
     285    // XXX uncomment to dump nablas after one step, one element
     286    // nnet_write_Nabla ("test.nabla.op.dat", nnet); // XXX print nabla for each epoch
     287    // return;
     288  }
     289  // gprint (GP_ERR, " done mini batch\n");
     290
     291  // nnet_print_Nabla (nnet);
    275292  nnet_apply_Nabla (nnet, Nmini, eta, lambda, Ntrial);
     293
     294  // XXX uncomment to dump nablas after one mini batch
     295  // nnet_write_Nabla ("test.nabla.op.dat", nnet); // XXX print nabla for each epoch
     296  // PrintNnet (nnet);
    276297}
    277298
     
    317338      }
    318339    } else {
     340      // XXX TEST PRINTS to catch code errors compared to python implementation
     341      // gprint (GP_ERR, "z: ");
     342      // for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     343      //        gprint (GP_ERR, "%f ",  nnet[0].zvalue[L][j]);
     344      // } gprint (GP_ERR, "\n");
     345      // gprint (GP_ERR, "sp: ");
     346      // for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     347      //        gprint (GP_ERR, "%f ",  nnet[0].sprime[L][j]);
     348      // } gprint (GP_ERR, "\n");
     349
    319350      // delta = DOT(delta, transpose(weight[L+1])) * sprime;
    320351      for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     
    322353        for (int i = 0; i < nnet[0].Nnodes[L+1]; i++) {
    323354          int k = j + i*nnet[0].Nnodes[L]; // note order of (i,j) : j is [L+1] direction
    324           tmpdelta += nnet[0].weight[L][k] * nnet[0].delta[L+1][i];
     355          myAssert (k < nnet[0].Nnodes[L]*nnet[0].Nnodes[L+1], "overflow");
     356          tmpdelta += nnet[0].weight[L+1][k] * nnet[0].delta[L+1][i];
     357          // gprint (GP_ERR, "%e %e\n", nnet[0].weight[L+1][k], nnet[0].delta[L+1][i]);
    325358        }
    326359        nnet[0].delta[L][j] = tmpdelta * nnet[0].sprime[L][j];
     
    335368    // Nabla_b[L] = delta;
    336369    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    337       nnet[0]. Nabla_b[L][j] = nnet[0].delta[L][j];
     370      nnet[0]. dNabla_b[L][j] = nnet[0].delta[L][j];
    338371    }
    339372   
     
    342375      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
    343376        int k = i + j*nnet[0].Nnodes[L-1];
    344         nnet[0]. Nabla_w[L][k] = nnet[0].svalue[L-1][i] * nnet[0].delta[L][j];
     377        myAssert (k < nnet[0].Nnodes[L-1]*nnet[0].Nnodes[L], "overflow");
     378        nnet[0]. dNabla_w[L][k] = nnet[0].svalue[L-1][i] * nnet[0].delta[L][j];
    345379      }
    346380    }
     
    349383
    350384// support functions to loop over the Nabla entries
     385void nnet_reset_Nabla (Nnet *nnet) {
     386  for (int L = 1; L < nnet[0].Nlayer; L++) {
     387
     388    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     389
     390      nnet[0]. Nabla_b[L][j] = 0;
     391      nnet[0].dNabla_b[L][j] = 0;
     392
     393      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
     394        int k = i + j*nnet[0].Nnodes[L-1];
     395        myAssert (k < nnet[0].Nnodes[L-1]*nnet[0].Nnodes[L], "overflow");
     396        nnet[0]. Nabla_w[L][k] = 0;
     397        nnet[0].dNabla_w[L][k] = 0;
     398      }
     399    }
     400  }
     401}
     402void nnet_update_Nabla (Nnet *nnet) {
     403  for (int L = 1; L < nnet[0].Nlayer; L++) {
     404
     405    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
     406      nnet[0]. Nabla_b[L][j] += nnet[0].dNabla_b[L][j];
     407
     408      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
     409        int k = i + j*nnet[0].Nnodes[L-1];
     410        myAssert (k < nnet[0].Nnodes[L-1]*nnet[0].Nnodes[L], "overflow");
     411        nnet[0]. Nabla_w[L][k] += nnet[0].dNabla_w[L][k];
     412      }
     413    }
     414  }
     415}
    351416void nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta, float lambda, int Ntrial) {
    352417  for (int L = 1; L < nnet[0].Nlayer; L++) {
     
    357422      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
    358423        int k = i + j*nnet[0].Nnodes[L-1];
     424        myAssert (k < nnet[0].Nnodes[L-1]*nnet[0].Nnodes[L], "overflow");
    359425        // nnet[0].weight[L][k] -= (eta / Nmini) * nnet[0].Nabla_w[L][k];
    360426        // with lambda > 0.0, we have L2 regularization.  if lambda = 0.0, we recover the default implementation
     
    364430  }
    365431}
    366 void nnet_update_Nabla (Nnet *nnet) {
     432
     433void nnet_print_Nabla (Nnet *nnet) {
     434
    367435  for (int L = 1; L < nnet[0].Nlayer; L++) {
    368 
    369     for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    370       nnet[0]. Nabla_b[L][j] += nnet[0].dNabla_b[L][j];
    371 
     436    gprint (GP_ERR, " ----- Nabla %d -----\n", L);
     437    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    372438      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
    373         int k = i + j*nnet[0].Nnodes[L-1];
    374         nnet[0]. Nabla_w[L][k] += nnet[0].dNabla_w[L][k];
    375       }
    376     }
    377   }
    378 }
    379 void nnet_reset_Nabla (Nnet *nnet) {
     439        int k = j * nnet[0].Nnodes[L-1] + i;
     440        myAssert (k < nnet[0].Nnodes[L-1]*nnet[0].Nnodes[L], "overflow");
     441        gprint (GP_ERR, "%10.3e ", nnet[0].Nabla_w[L][k]);
     442      }
     443      gprint (GP_ERR, " : %10.3e\n", nnet[0].Nabla_b[L][j]);
     444    }
     445  }
     446  return;
     447}
     448
     449void nnet_write_Nabla (char *filename, Nnet *nnet) {
     450
     451  FILE *f = fopen (filename, "w");
     452
     453  fprintf (f, "NLAYER %d\n", nnet[0].Nlayer);
     454  fprintf (f, "LAYERS ");
     455  for (int L = 0; L < nnet[0].Nlayer; L++) {
     456    fprintf (f, "%d ", nnet[0].Nnodes[L]);
     457  }
     458  fprintf (f, "\n");
     459
    380460  for (int L = 1; L < nnet[0].Nlayer; L++) {
    381 
    382     for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    383 
    384       nnet[0]. Nabla_b[L][j] = 0;
    385       nnet[0].dNabla_b[L][j] = 0;
    386 
     461    fprintf (f, "LAYER %d NX %d NY %d\n", L - 1, nnet[0].Nnodes[L-1], nnet[0].Nnodes[L]);
     462    for (int j = 0; j < nnet[0].Nnodes[L]; j++) {
    387463      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
    388         int k = i + j*nnet[0].Nnodes[L-1];
    389         nnet[0]. Nabla_w[L][k] = 0;
    390         nnet[0].dNabla_w[L][k] = 0;
    391       }
    392     }
    393   }
     464        int k = j * nnet[0].Nnodes[L-1] + i;
     465        myAssert (k < nnet[0].Nnodes[L-1]*nnet[0].Nnodes[L], "overflow");
     466        fprintf (f, "%.9f ", nnet[0].Nabla_w[L][k]);
     467      }
     468      fprintf (f, "%.9f\n", nnet[0].Nabla_b[L][j]);
     469    }
     470  }
     471
     472  fclose (f);
     473  return;
    394474}
    395475
     
    410490
    411491  // evaluating a single layer [L], n > 0, n < Nlayer:
    412   int Ninput   = nnet[0].Nnodes[L - 1];
     492  int Ninput   = nnet[0].Nnodes[L-1];
    413493  int Noutput  = nnet[0].Nnodes[L];
    414494
     
    419499      // weight matrix order is (0, 1, ... Ninput-1, Ninput, Ninput + 1, ... Ninput * Noutput - 1)
    420500      int k = j * Ninput + i;
     501      myAssert (k < Ninput*Noutput, "overflow");
    421502      sum += nnet[0].weight[L][k]*nnet[0].svalue[L-1][i];
    422503    }
Note: See TracChangeset for help on using the changeset viewer.