IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 40325 for trunk


Ignore:
Timestamp:
Jan 27, 2018, 1:09:32 PM (8 years ago)
Author:
eugene
Message:

updated nnet to include better init, L2 regularization, cross-entropy cost function

Location:
trunk/Ohana/src/opihi
Files:
5 edited

Legend:

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

    r40320 r40325  
    3636int nnet_create (int argc, char **argv) {
    3737
     38  int N;
     39
     40  int LargeWeightInit = FALSE;
     41  if ((N = get_argument (argc, argv, "-large-weight-initializer"))) {
     42    remove_argument (N, &argc, argv);
     43    LargeWeightInit = TRUE;   
     44  }
     45
    3846  if (argc < 4) {
    3947    gprint (GP_ERR, "USAGE: nnet create (nnet) (Ninput) [Nnodes] [Nnodes] ... (Noutput)\n");
     
    5260
    5361  // allocate the vector and matrix data arrays (and init)
    54   CreateNnetData (nnet);
     62  CreateNnetData (nnet, LargeWeightInit);
    5563
    5664  return TRUE;
  • trunk/Ohana/src/opihi/cmd.data/nnet_train.c

    r40323 r40325  
    77void  nnet_reset_Nabla (Nnet *nnet);
    88void  nnet_update_Nabla (Nnet *nnet);
    9 void  nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta);
     9void  nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta, float lambda, int Ntrial);
    1010void  nnet_backprop (Nnet *nnet, Vector **inVec, Vector **outVec, int N);
    11 void  nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta);
     11void  nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta, float lambda);
     12
     13static int QUADRATIC_COST = 0;
    1214
    1315int nnet_train (int argc, char **argv) {
     
    3436    eta = atof (argv[N]);
    3537    remove_argument (N, &argc, argv);
     38  }
     39
     40  float lambda = 0.0; // XXX how do I set this? does it need to update?
     41  if ((N = get_argument (argc, argv, "-lambda"))) {
     42    remove_argument (N, &argc, argv);
     43    lambda = atof (argv[N]);
     44    remove_argument (N, &argc, argv);
     45  }
     46
     47  QUADRATIC_COST = 0;
     48  if ((N = get_argument (argc, argv, "-quadratic-cost"))) {
     49    remove_argument (N, &argc, argv);
     50    QUADRATIC_COST = 1;   
    3651  }
    3752
     
    121136      // for a given pass select seq elements pass*Nmini to pass*Nmini + Nmini - 1
    122137      // update the weights and biases using the mini batch subset
    123       nnet_descent_step (nnet, inVec, outVec, seq, pass, Nmini, eta);
     138      nnet_descent_step (nnet, inVec, outVec, seq, pass, Nmini, eta, lambda);
    124139      gprint (GP_ERR, "epoch %d of %d, pass %d of %d\n", epoch, Nepoch, pass, Npass);
    125140    }
     
    134149
    135150// this recreates 'update_mini_batch' from http://neuralnetworksanddeeplearning.com/chap1.html
    136 void nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta) {
     151void nnet_descent_step (Nnet *nnet, Vector **inVec, Vector **outVec, int *seq, int pass, int Nmini, float eta, float lambda) {
    137152
    138153  int Ntrial = inVec[0][0].Nelements;
     
    151166  }
    152167
    153   nnet_apply_Nabla (nnet, Nmini, eta);
     168  nnet_apply_Nabla (nnet, Nmini, eta, lambda, Ntrial);
    154169}
    155170
     
    183198        // NOTE: the (1/Npt) factor is pushed to the apply_Nabla step
    184199        // nnet[0].delta[L][j] = cost_derivative(nnet[0].svalue[L][j], outVec[j][0].elements.Flt[N]) * nnet[0].sprime[L][j];
    185         nnet[0].delta[L][j] = (nnet[0].svalue[L][j] - outVec[j][0].elements.Flt[N]) * nnet[0].sprime[L][j];
     200
     201        if (QUADRATIC_COST) {
     202          nnet[0].delta[L][j] = (nnet[0].svalue[L][j] - outVec[j][0].elements.Flt[N]) * nnet[0].sprime[L][j];
     203        } else {
     204          nnet[0].delta[L][j] = (nnet[0].svalue[L][j] - outVec[j][0].elements.Flt[N]);
     205        }
     206
     207        // for quadratic cost, delta = (svalue[L] - output) * sprime[L]
     208        // for cross-entropy, delta = (svalue[L] - output)
     209
    186210      }
    187211    } else {
     
    218242
    219243// support functions to loop over the Nabla entries
    220 void nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta) {
     244void nnet_apply_Nabla (Nnet *nnet, int Nmini, float eta, float lambda, int Ntrial) {
    221245  for (int L = 1; L < nnet[0].Nlayer; L++) {
    222246
     
    226250      for (int i = 0; i < nnet[0].Nnodes[L-1]; i++) {
    227251        int k = i + j*nnet[0].Nnodes[L-1];
    228         nnet[0].weight[L][k] -= (eta / Nmini) * nnet[0].Nabla_w[L][k];
     252        // nnet[0].weight[L][k] -= (eta / Nmini) * nnet[0].Nabla_w[L][k];
     253        // with lambda > 0.0, we have L2 regularization.  if lambda = 0.0, we recover the default implementation
     254        nnet[0].weight[L][k] = nnet[0].weight[L][k]*(1.0 - eta*lambda/Ntrial) - (eta / Nmini) * nnet[0].Nabla_w[L][k];
    229255      }
    230256    }
  • trunk/Ohana/src/opihi/cmd.data/test/nnet.sh

    r40323 r40325  
    161161  nnet apply t1 x0 x1 y0 y1
    162162
    163   nnet create tn 2 2
    164   nnet train tn x0 x1 y0 y1 -Nmini $Nmini -Nepoch $Nepoch -eta $eta
     163# -large-weight-initializer : revert to original implementation
     164  nnet create tn 2 2
     165# nnet create tn 2 2 -large-weight-initializer
     166
     167# -quadratic-cost : revert to original implementation
     168  nnet train tn x0 x1 y0 y1 -Nmini $Nmini -Nepoch $Nepoch -eta $eta -lambda 0.0 -quadratic-cost
     169# nnet train tn x0 x1 y0 y1 -Nmini $Nmini -Nepoch $Nepoch -eta $eta -lambda 0.0
     170# nnet train tn x0 x1 y0 y1 -Nmini $Nmini -Nepoch $Nepoch -eta $eta -lambda 2.0
    165171
    166172  nnet apply tn x0 x1 Y0 Y1
     
    169175  set dy1 = y1 - Y1
    170176
    171   vstat -q dy0
     177  vstat dy0
    172178  $yp = $MAX
    173179  $ym = $MIN
    174180
    175   vstat -q dy1
     181  vstat dy1
    176182  $yp = max ($MAX , $yp)
    177183  $ym = min ($MIN , $ym)
     
    181187end
    182188
     189macro test.bilevel
     190  if ($0 != 4)
     191    echo "USAGE: test.bilevel (Nmini) (Nepoch) (eta)"
     192    break
     193  end
     194
     195  local Nmini Nepoch eta
     196  $Nmini  = $1
     197  $Nepoch = $2
     198  $eta    = $3
     199
     200  # create a nnet with just 2 inputs and 2 outputs
     201  nnet create t1 3 4 3
     202
     203  # biases:
     204  vlist v1 -0.2 0.0 0.2 0.4
     205  vlist v2 -0.5 0.0 0.5
     206
     207  # weights
     208  mcreate m1 3 4
     209  m1[0][0] =  0.2
     210  m1[1][0] = -0.2
     211  m1[2][0] = -0.3
     212
     213  m1[0][1] = -0.6
     214  m1[1][1] =  0.5
     215  m1[2][1] = -0.1
     216
     217  m1[0][2] = -0.2
     218  m1[1][2] =  0.2
     219  m1[2][2] = -0.5
     220
     221  m1[0][3] =  0.4
     222  m1[1][3] = -0.5
     223  m1[2][3] = -0.7
     224
     225  mcreate m2 4 3
     226  m2[0][0] =  0.8
     227  m2[1][0] = -0.4
     228  m2[2][0] = -0.5
     229  m2[3][0] =  0.3
     230
     231  m2[0][1] = -0.2
     232  m2[1][1] = -0.5
     233  m2[2][1] =  0.1
     234  m2[3][1] =  0.1
     235
     236  m2[0][2] =  0.2
     237  m2[1][2] = -0.2
     238  m2[2][2] =  0.5
     239  m2[3][2] = -0.1
     240
     241  # set weights and biases
     242  nnet set t1 m1 v1 m1 v1
     243
     244  # generate an input set spanning the range -5 to +5
     245
     246  create n 0 10000
     247  set x0 = 10*rnd(n) - 5.0
     248  set x1 = 10*rnd(n) - 5.0
     249  set x2 = 10*rnd(n) - 5.0
     250
     251  # get output vectors the these input vectors
     252  nnet apply t1 x0 x1 x2 y0 y1 y2
     253
     254# nnet create tn 3 4 3 -large-weight-initializer
     255  nnet create tn 3 4 3
     256
     257# nnet train tn x0 x1 x2 y0 y1 y2 -Nmini $Nmini -Nepoch $Nepoch -eta $eta -lambda 0.1
     258  nnet train tn x0 x1 x2 y0 y1 y2 -Nmini $Nmini -Nepoch $Nepoch -eta $eta -lambda 0.0 -quadratic-cost
     259
     260  nnet apply tn x0 x1 x2 Y0 Y1 Y2
     261
     262  set dy0 = y0 - Y0
     263  set dy1 = y1 - Y1
     264  set dy2 = y2 - Y2
     265
     266  vstat dy0
     267  $yp = $MAX
     268  $ym = $MIN
     269
     270  vstat dy1
     271  $yp = max ($MAX , $yp)
     272  $ym = min ($MIN , $ym)
     273
     274  vstat dy2
     275  $yp = max ($MAX , $yp)
     276  $ym = min ($MIN , $ym)
     277# $yp = 0.02; $ym = -0.02
     278
     279  style -pt circle -sz 2;
     280  lim x0 $ym $yp; clear; box;
     281  plot -c blue  x0 dy0;
     282  plot -c red   x0 dy1
     283  plot -c black x0 dy2
     284end
     285
  • trunk/Ohana/src/opihi/include/data.h

    r40320 r40325  
    261261Nnet *FindNnet (char *name);
    262262Nnet *CreateNnet (char *name, int Nlayer);
    263 void CreateNnetData (Nnet *nnet);
     263void CreateNnetData (Nnet *nnet, int LargeWeightInit);
    264264
    265265int DeleteNnet (Nnet *nnet);
  • trunk/Ohana/src/opihi/lib.data/nnet.c

    r40320 r40325  
    143143}
    144144
    145 void CreateNnetData (Nnet *nnet) {
     145void CreateNnetData (Nnet *nnet, int LargeWeightInit) {
    146146
    147147  ohana_gaussdev_init ();
     
    168168    }
    169169
     170    float sigma = LargeWeightInit ? 1.0 : 1.0 / sqrt(nnet[0].Nnodes[i-1]);
     171
    170172    ALLOCATE (nnet[0].weight[i], float, nnet[0].Nnodes[i-1]*nnet[0].Nnodes[i]);  // weight connected each node in the previous layer to the current layer (excludes input layer)
    171173    for (int j = 0; j < nnet[0].Nnodes[i-1]*nnet[0].Nnodes[i]; j++) {
    172       nnet[0].weight[i][j] = ohana_gaussdev_rnd (0.0, 1.0);
     174      nnet[0].weight[i][j] = ohana_gaussdev_rnd (0.0, sigma);
    173175    }
    174176
Note: See TracChangeset for help on using the changeset viewer.