| OLD | NEW |
| 1 /* Copyright (c) 2008-2011 Octasic Inc. | 1 /* Copyright (c) 2008-2011 Octasic Inc. |
| 2 Written by Jean-Marc Valin */ | 2 Written by Jean-Marc Valin */ |
| 3 /* | 3 /* |
| 4 Redistribution and use in source and binary forms, with or without | 4 Redistribution and use in source and binary forms, with or without |
| 5 modification, are permitted provided that the following conditions | 5 modification, are permitted provided that the following conditions |
| 6 are met: | 6 are met: |
| 7 | 7 |
| 8 - Redistributions of source code must retain the above copyright | 8 - Redistributions of source code must retain the above copyright |
| 9 notice, this list of conditions and the following disclaimer. | 9 notice, this list of conditions and the following disclaimer. |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include <string.h> | 32 #include <string.h> |
| 33 #include <semaphore.h> | 33 #include <semaphore.h> |
| 34 #include <pthread.h> | 34 #include <pthread.h> |
| 35 #include <time.h> | 35 #include <time.h> |
| 36 #include <signal.h> | 36 #include <signal.h> |
| 37 | 37 |
| 38 int stopped = 0; | 38 int stopped = 0; |
| 39 | 39 |
| 40 void handler(int sig) | 40 void handler(int sig) |
| 41 { | 41 { |
| 42 » stopped = 1; | 42 stopped = 1; |
| 43 » signal(sig, handler); | 43 signal(sig, handler); |
| 44 } | 44 } |
| 45 | 45 |
| 46 MLPTrain * mlp_init(int *topo, int nbLayers, float *inputs, float *outputs, int
nbSamples) | 46 MLPTrain * mlp_init(int *topo, int nbLayers, float *inputs, float *outputs, int
nbSamples) |
| 47 { | 47 { |
| 48 » int i, j, k; | 48 int i, j, k; |
| 49 » MLPTrain *net; | 49 MLPTrain *net; |
| 50 » int inDim, outDim; | 50 int inDim, outDim; |
| 51 » net = malloc(sizeof(*net)); | 51 net = malloc(sizeof(*net)); |
| 52 » net->topo = malloc(nbLayers*sizeof(net->topo[0])); | 52 net->topo = malloc(nbLayers*sizeof(net->topo[0])); |
| 53 » for (i=0;i<nbLayers;i++) | 53 for (i=0;i<nbLayers;i++) |
| 54 » » net->topo[i] = topo[i]; | 54 net->topo[i] = topo[i]; |
| 55 » inDim = topo[0]; | 55 inDim = topo[0]; |
| 56 » outDim = topo[nbLayers-1]; | 56 outDim = topo[nbLayers-1]; |
| 57 » net->in_rate = malloc((inDim+1)*sizeof(net->in_rate[0])); | 57 net->in_rate = malloc((inDim+1)*sizeof(net->in_rate[0])); |
| 58 » net->weights = malloc((nbLayers-1)*sizeof(net->weights)); | 58 net->weights = malloc((nbLayers-1)*sizeof(net->weights)); |
| 59 » net->best_weights = malloc((nbLayers-1)*sizeof(net->weights)); | 59 net->best_weights = malloc((nbLayers-1)*sizeof(net->weights)); |
| 60 » for (i=0;i<nbLayers-1;i++) | 60 for (i=0;i<nbLayers-1;i++) |
| 61 » { | 61 { |
| 62 » » net->weights[i] = malloc((topo[i]+1)*topo[i+1]*sizeof(net->weigh
ts[0][0])); | 62 net->weights[i] = malloc((topo[i]+1)*topo[i+1]*sizeof(net->weights[0][0]
)); |
| 63 » » net->best_weights[i] = malloc((topo[i]+1)*topo[i+1]*sizeof(net->
weights[0][0])); | 63 net->best_weights[i] = malloc((topo[i]+1)*topo[i+1]*sizeof(net->weights[
0][0])); |
| 64 » } | 64 } |
| 65 » double inMean[inDim]; | 65 double inMean[inDim]; |
| 66 » for (j=0;j<inDim;j++) | 66 for (j=0;j<inDim;j++) |
| 67 » { | 67 { |
| 68 » » double std=0; | 68 double std=0; |
| 69 » » inMean[j] = 0; | 69 inMean[j] = 0; |
| 70 » » for (i=0;i<nbSamples;i++) | 70 for (i=0;i<nbSamples;i++) |
| 71 » » { | 71 { |
| 72 » » » inMean[j] += inputs[i*inDim+j]; | 72 inMean[j] += inputs[i*inDim+j]; |
| 73 » » » std += inputs[i*inDim+j]*inputs[i*inDim+j]; | 73 std += inputs[i*inDim+j]*inputs[i*inDim+j]; |
| 74 » » } | 74 } |
| 75 » » inMean[j] /= nbSamples; | 75 inMean[j] /= nbSamples; |
| 76 » » std /= nbSamples; | 76 std /= nbSamples; |
| 77 » » net->in_rate[1+j] = .5/(.0001+std); | 77 net->in_rate[1+j] = .5/(.0001+std); |
| 78 » » std = std-inMean[j]*inMean[j]; | 78 std = std-inMean[j]*inMean[j]; |
| 79 » » if (std<.001) | 79 if (std<.001) |
| 80 » » » std = .001; | 80 std = .001; |
| 81 » » std = 1/sqrt(inDim*std); | 81 std = 1/sqrt(inDim*std); |
| 82 » » for (k=0;k<topo[1];k++) | 82 for (k=0;k<topo[1];k++) |
| 83 » » » net->weights[0][k*(topo[0]+1)+j+1] = randn(std); | 83 net->weights[0][k*(topo[0]+1)+j+1] = randn(std); |
| 84 » } | 84 } |
| 85 » net->in_rate[0] = 1; | 85 net->in_rate[0] = 1; |
| 86 » for (j=0;j<topo[1];j++) | 86 for (j=0;j<topo[1];j++) |
| 87 » { | 87 { |
| 88 » » double sum = 0; | 88 double sum = 0; |
| 89 » » for (k=0;k<inDim;k++) | 89 for (k=0;k<inDim;k++) |
| 90 » » » sum += inMean[k]*net->weights[0][j*(topo[0]+1)+k+1]; | 90 sum += inMean[k]*net->weights[0][j*(topo[0]+1)+k+1]; |
| 91 » » net->weights[0][j*(topo[0]+1)] = -sum; | 91 net->weights[0][j*(topo[0]+1)] = -sum; |
| 92 » } | 92 } |
| 93 » for (j=0;j<outDim;j++) | 93 for (j=0;j<outDim;j++) |
| 94 » { | 94 { |
| 95 » » double mean = 0; | 95 double mean = 0; |
| 96 » » double std; | 96 double std; |
| 97 » » for (i=0;i<nbSamples;i++) | 97 for (i=0;i<nbSamples;i++) |
| 98 » » » mean += outputs[i*outDim+j]; | 98 mean += outputs[i*outDim+j]; |
| 99 » » mean /= nbSamples; | 99 mean /= nbSamples; |
| 100 » » std = 1/sqrt(topo[nbLayers-2]); | 100 std = 1/sqrt(topo[nbLayers-2]); |
| 101 » » net->weights[nbLayers-2][j*(topo[nbLayers-2]+1)] = mean; | 101 net->weights[nbLayers-2][j*(topo[nbLayers-2]+1)] = mean; |
| 102 » » for (k=0;k<topo[nbLayers-2];k++) | 102 for (k=0;k<topo[nbLayers-2];k++) |
| 103 » » » net->weights[nbLayers-2][j*(topo[nbLayers-2]+1)+k+1] = r
andn(std); | 103 net->weights[nbLayers-2][j*(topo[nbLayers-2]+1)+k+1] = randn(std); |
| 104 » } | 104 } |
| 105 » return net; | 105 return net; |
| 106 } | 106 } |
| 107 | 107 |
| 108 #define MAX_NEURONS 100 | 108 #define MAX_NEURONS 100 |
| 109 #define MAX_OUT 10 | 109 #define MAX_OUT 10 |
| 110 | 110 |
| 111 double compute_gradient(MLPTrain *net, float *inputs, float *outputs, int nbSamp
les, double *W0_grad, double *W1_grad, double *error_rate) | 111 double compute_gradient(MLPTrain *net, float *inputs, float *outputs, int nbSamp
les, double *W0_grad, double *W1_grad, double *error_rate) |
| 112 { | 112 { |
| 113 » int i,j; | 113 int i,j; |
| 114 » int s; | 114 int s; |
| 115 » int inDim, outDim, hiddenDim; | 115 int inDim, outDim, hiddenDim; |
| 116 » int *topo; | 116 int *topo; |
| 117 » double *W0, *W1; | 117 double *W0, *W1; |
| 118 » double rms=0; | 118 double rms=0; |
| 119 » int W0_size, W1_size; | 119 int W0_size, W1_size; |
| 120 » double hidden[MAX_NEURONS]; | 120 double hidden[MAX_NEURONS]; |
| 121 » double netOut[MAX_NEURONS]; | 121 double netOut[MAX_NEURONS]; |
| 122 » double error[MAX_NEURONS]; | 122 double error[MAX_NEURONS]; |
| 123 | 123 |
| 124 » for (i=0;i<outDim;i++) | 124 topo = net->topo; |
| 125 » error_rate[i] = 0; | 125 inDim = net->topo[0]; |
| 126 » topo = net->topo; | 126 hiddenDim = net->topo[1]; |
| 127 » inDim = net->topo[0]; | 127 outDim = net->topo[2]; |
| 128 » hiddenDim = net->topo[1]; | 128 W0_size = (topo[0]+1)*topo[1]; |
| 129 » outDim = net->topo[2]; | 129 W1_size = (topo[1]+1)*topo[2]; |
| 130 » W0_size = (topo[0]+1)*topo[1]; | 130 W0 = net->weights[0]; |
| 131 » W1_size = (topo[1]+1)*topo[2]; | 131 W1 = net->weights[1]; |
| 132 » W0 = net->weights[0]; | 132 memset(W0_grad, 0, W0_size*sizeof(double)); |
| 133 » W1 = net->weights[1]; | 133 memset(W1_grad, 0, W1_size*sizeof(double)); |
| 134 » memset(W0_grad, 0, W0_size*sizeof(double)); | 134 for (i=0;i<outDim;i++) |
| 135 » memset(W1_grad, 0, W1_size*sizeof(double)); | 135 netOut[i] = outputs[i]; |
| 136 » for (i=0;i<outDim;i++) | 136 for (i=0;i<outDim;i++) |
| 137 » » netOut[i] = outputs[i]; | 137 error_rate[i] = 0; |
| 138 » for (s=0;s<nbSamples;s++) | 138 for (s=0;s<nbSamples;s++) |
| 139 » { | 139 { |
| 140 » » float *in, *out; | 140 float *in, *out; |
| 141 » » in = inputs+s*inDim; | 141 in = inputs+s*inDim; |
| 142 » » out = outputs + s*outDim; | 142 out = outputs + s*outDim; |
| 143 » » for (i=0;i<hiddenDim;i++) | 143 for (i=0;i<hiddenDim;i++) |
| 144 » » { | 144 { |
| 145 » » » double sum = W0[i*(inDim+1)]; | 145 double sum = W0[i*(inDim+1)]; |
| 146 » » » for (j=0;j<inDim;j++) | 146 for (j=0;j<inDim;j++) |
| 147 » » » » sum += W0[i*(inDim+1)+j+1]*in[j]; | 147 sum += W0[i*(inDim+1)+j+1]*in[j]; |
| 148 » » » hidden[i] = tansig_approx(sum); | 148 hidden[i] = tansig_approx(sum); |
| 149 » » } | 149 } |
| 150 » » for (i=0;i<outDim;i++) | 150 for (i=0;i<outDim;i++) |
| 151 » » { | 151 { |
| 152 » » » double sum = W1[i*(hiddenDim+1)]; | 152 double sum = W1[i*(hiddenDim+1)]; |
| 153 » » » for (j=0;j<hiddenDim;j++) | 153 for (j=0;j<hiddenDim;j++) |
| 154 » » » » sum += W1[i*(hiddenDim+1)+j+1]*hidden[j]; | 154 sum += W1[i*(hiddenDim+1)+j+1]*hidden[j]; |
| 155 » » » netOut[i] = tansig_approx(sum); | 155 netOut[i] = tansig_approx(sum); |
| 156 » » » error[i] = out[i] - netOut[i]; | 156 error[i] = out[i] - netOut[i]; |
| 157 » » » rms += error[i]*error[i]; | 157 rms += error[i]*error[i]; |
| 158 » » » error_rate[i] += fabs(error[i])>1; | 158 error_rate[i] += fabs(error[i])>1; |
| 159 » » » /*error[i] = error[i]/(1+fabs(error[i]));*/ | 159 /*error[i] = error[i]/(1+fabs(error[i]));*/ |
| 160 » » } | 160 } |
| 161 » » /* Back-propagate error */ | 161 /* Back-propagate error */ |
| 162 » » for (i=0;i<outDim;i++) | 162 for (i=0;i<outDim;i++) |
| 163 » » { | 163 { |
| 164 float grad = 1-netOut[i]*netOut[i]; | 164 float grad = 1-netOut[i]*netOut[i]; |
| 165 » » » W1_grad[i*(hiddenDim+1)] += error[i]*grad; | 165 W1_grad[i*(hiddenDim+1)] += error[i]*grad; |
| 166 » » » for (j=0;j<hiddenDim;j++) | 166 for (j=0;j<hiddenDim;j++) |
| 167 » » » » W1_grad[i*(hiddenDim+1)+j+1] += grad*error[i]*hi
dden[j]; | 167 W1_grad[i*(hiddenDim+1)+j+1] += grad*error[i]*hidden[j]; |
| 168 » » } | 168 } |
| 169 » » for (i=0;i<hiddenDim;i++) | 169 for (i=0;i<hiddenDim;i++) |
| 170 » » { | 170 { |
| 171 » » » double grad; | 171 double grad; |
| 172 » » » grad = 0; | 172 grad = 0; |
| 173 » » » for (j=0;j<outDim;j++) | 173 for (j=0;j<outDim;j++) |
| 174 » » » » grad += error[j]*W1[j*(hiddenDim+1)+i+1]; | 174 grad += error[j]*W1[j*(hiddenDim+1)+i+1]; |
| 175 » » » grad *= 1-hidden[i]*hidden[i]; | 175 grad *= 1-hidden[i]*hidden[i]; |
| 176 » » » W0_grad[i*(inDim+1)] += grad; | 176 W0_grad[i*(inDim+1)] += grad; |
| 177 » » » for (j=0;j<inDim;j++) | 177 for (j=0;j<inDim;j++) |
| 178 » » » » W0_grad[i*(inDim+1)+j+1] += grad*in[j]; | 178 W0_grad[i*(inDim+1)+j+1] += grad*in[j]; |
| 179 » » } | 179 } |
| 180 » } | 180 } |
| 181 » return rms; | 181 return rms; |
| 182 } | 182 } |
| 183 | 183 |
| 184 #define NB_THREADS 8 | 184 #define NB_THREADS 8 |
| 185 | 185 |
| 186 sem_t sem_begin[NB_THREADS]; | 186 sem_t sem_begin[NB_THREADS]; |
| 187 sem_t sem_end[NB_THREADS]; | 187 sem_t sem_end[NB_THREADS]; |
| 188 | 188 |
| 189 struct GradientArg { | 189 struct GradientArg { |
| 190 » int id; | 190 int id; |
| 191 » int done; | 191 int done; |
| 192 » MLPTrain *net; | 192 MLPTrain *net; |
| 193 » float *inputs; | 193 float *inputs; |
| 194 » float *outputs; | 194 float *outputs; |
| 195 » int nbSamples; | 195 int nbSamples; |
| 196 » double *W0_grad; | 196 double *W0_grad; |
| 197 » double *W1_grad; | 197 double *W1_grad; |
| 198 » double rms; | 198 double rms; |
| 199 » double error_rate[MAX_OUT]; | 199 double error_rate[MAX_OUT]; |
| 200 }; | 200 }; |
| 201 | 201 |
| 202 void *gradient_thread_process(void *_arg) | 202 void *gradient_thread_process(void *_arg) |
| 203 { | 203 { |
| 204 » int W0_size, W1_size; | 204 int W0_size, W1_size; |
| 205 » struct GradientArg *arg = _arg; | 205 struct GradientArg *arg = _arg; |
| 206 » int *topo = arg->net->topo; | 206 int *topo = arg->net->topo; |
| 207 » W0_size = (topo[0]+1)*topo[1]; | 207 W0_size = (topo[0]+1)*topo[1]; |
| 208 » W1_size = (topo[1]+1)*topo[2]; | 208 W1_size = (topo[1]+1)*topo[2]; |
| 209 » double W0_grad[W0_size]; | 209 double W0_grad[W0_size]; |
| 210 » double W1_grad[W1_size]; | 210 double W1_grad[W1_size]; |
| 211 » arg->W0_grad = W0_grad; | 211 arg->W0_grad = W0_grad; |
| 212 » arg->W1_grad = W1_grad; | 212 arg->W1_grad = W1_grad; |
| 213 » while (1) | 213 while (1) |
| 214 » { | 214 { |
| 215 » » sem_wait(&sem_begin[arg->id]); | 215 sem_wait(&sem_begin[arg->id]); |
| 216 » » if (arg->done) | 216 if (arg->done) |
| 217 » » » break; | 217 break; |
| 218 » » arg->rms = compute_gradient(arg->net, arg->inputs, arg->outputs,
arg->nbSamples, arg->W0_grad, arg->W1_grad, arg->error_rate); | 218 arg->rms = compute_gradient(arg->net, arg->inputs, arg->outputs, arg->nb
Samples, arg->W0_grad, arg->W1_grad, arg->error_rate); |
| 219 » » sem_post(&sem_end[arg->id]); | 219 sem_post(&sem_end[arg->id]); |
| 220 » } | 220 } |
| 221 » fprintf(stderr, "done\n"); | 221 fprintf(stderr, "done\n"); |
| 222 » return NULL; | 222 return NULL; |
| 223 } | 223 } |
| 224 | 224 |
| 225 float mlp_train_backprop(MLPTrain *net, float *inputs, float *outputs, int nbSam
ples, int nbEpoch, float rate) | 225 float mlp_train_backprop(MLPTrain *net, float *inputs, float *outputs, int nbSam
ples, int nbEpoch, float rate) |
| 226 { | 226 { |
| 227 » int i, j; | 227 int i, j; |
| 228 » int e; | 228 int e; |
| 229 » float best_rms = 1e10; | 229 float best_rms = 1e10; |
| 230 » int inDim, outDim, hiddenDim; | 230 int inDim, outDim, hiddenDim; |
| 231 » int *topo; | 231 int *topo; |
| 232 » double *W0, *W1, *best_W0, *best_W1; | 232 double *W0, *W1, *best_W0, *best_W1; |
| 233 » double *W0_old, *W1_old; | 233 double *W0_old, *W1_old; |
| 234 » double *W0_old2, *W1_old2; | 234 double *W0_old2, *W1_old2; |
| 235 » double *W0_grad, *W1_grad; | 235 double *W0_grad, *W1_grad; |
| 236 » double *W0_oldgrad, *W1_oldgrad; | 236 double *W0_oldgrad, *W1_oldgrad; |
| 237 » double *W0_rate, *W1_rate; | 237 double *W0_rate, *W1_rate; |
| 238 » double *best_W0_rate, *best_W1_rate; | 238 double *best_W0_rate, *best_W1_rate; |
| 239 » int W0_size, W1_size; | 239 int W0_size, W1_size; |
| 240 » topo = net->topo; | 240 topo = net->topo; |
| 241 » W0_size = (topo[0]+1)*topo[1]; | 241 W0_size = (topo[0]+1)*topo[1]; |
| 242 » W1_size = (topo[1]+1)*topo[2]; | 242 W1_size = (topo[1]+1)*topo[2]; |
| 243 » struct GradientArg args[NB_THREADS]; | 243 struct GradientArg args[NB_THREADS]; |
| 244 » pthread_t thread[NB_THREADS]; | 244 pthread_t thread[NB_THREADS]; |
| 245 » int samplePerPart = nbSamples/NB_THREADS; | 245 int samplePerPart = nbSamples/NB_THREADS; |
| 246 » int count_worse=0; | 246 int count_worse=0; |
| 247 » int count_retries=0; | 247 int count_retries=0; |
| 248 | 248 |
| 249 » topo = net->topo; | 249 topo = net->topo; |
| 250 » inDim = net->topo[0]; | 250 inDim = net->topo[0]; |
| 251 » hiddenDim = net->topo[1]; | 251 hiddenDim = net->topo[1]; |
| 252 » outDim = net->topo[2]; | 252 outDim = net->topo[2]; |
| 253 » W0 = net->weights[0]; | 253 W0 = net->weights[0]; |
| 254 » W1 = net->weights[1]; | 254 W1 = net->weights[1]; |
| 255 » best_W0 = net->best_weights[0]; | 255 best_W0 = net->best_weights[0]; |
| 256 » best_W1 = net->best_weights[1]; | 256 best_W1 = net->best_weights[1]; |
| 257 » W0_old = malloc(W0_size*sizeof(double)); | 257 W0_old = malloc(W0_size*sizeof(double)); |
| 258 » W1_old = malloc(W1_size*sizeof(double)); | 258 W1_old = malloc(W1_size*sizeof(double)); |
| 259 » W0_old2 = malloc(W0_size*sizeof(double)); | 259 W0_old2 = malloc(W0_size*sizeof(double)); |
| 260 » W1_old2 = malloc(W1_size*sizeof(double)); | 260 W1_old2 = malloc(W1_size*sizeof(double)); |
| 261 » W0_grad = malloc(W0_size*sizeof(double)); | 261 W0_grad = malloc(W0_size*sizeof(double)); |
| 262 » W1_grad = malloc(W1_size*sizeof(double)); | 262 W1_grad = malloc(W1_size*sizeof(double)); |
| 263 » W0_oldgrad = malloc(W0_size*sizeof(double)); | 263 W0_oldgrad = malloc(W0_size*sizeof(double)); |
| 264 » W1_oldgrad = malloc(W1_size*sizeof(double)); | 264 W1_oldgrad = malloc(W1_size*sizeof(double)); |
| 265 » W0_rate = malloc(W0_size*sizeof(double)); | 265 W0_rate = malloc(W0_size*sizeof(double)); |
| 266 » W1_rate = malloc(W1_size*sizeof(double)); | 266 W1_rate = malloc(W1_size*sizeof(double)); |
| 267 » best_W0_rate = malloc(W0_size*sizeof(double)); | 267 best_W0_rate = malloc(W0_size*sizeof(double)); |
| 268 » best_W1_rate = malloc(W1_size*sizeof(double)); | 268 best_W1_rate = malloc(W1_size*sizeof(double)); |
| 269 » memcpy(W0_old, W0, W0_size*sizeof(double)); | 269 memcpy(W0_old, W0, W0_size*sizeof(double)); |
| 270 » memcpy(W0_old2, W0, W0_size*sizeof(double)); | 270 memcpy(W0_old2, W0, W0_size*sizeof(double)); |
| 271 » memset(W0_grad, 0, W0_size*sizeof(double)); | 271 memset(W0_grad, 0, W0_size*sizeof(double)); |
| 272 » memset(W0_oldgrad, 0, W0_size*sizeof(double)); | 272 memset(W0_oldgrad, 0, W0_size*sizeof(double)); |
| 273 » memcpy(W1_old, W1, W1_size*sizeof(double)); | 273 memcpy(W1_old, W1, W1_size*sizeof(double)); |
| 274 » memcpy(W1_old2, W1, W1_size*sizeof(double)); | 274 memcpy(W1_old2, W1, W1_size*sizeof(double)); |
| 275 » memset(W1_grad, 0, W1_size*sizeof(double)); | 275 memset(W1_grad, 0, W1_size*sizeof(double)); |
| 276 » memset(W1_oldgrad, 0, W1_size*sizeof(double)); | 276 memset(W1_oldgrad, 0, W1_size*sizeof(double)); |
| 277 » | 277 |
| 278 » rate /= nbSamples; | 278 rate /= nbSamples; |
| 279 » for (i=0;i<hiddenDim;i++) | 279 for (i=0;i<hiddenDim;i++) |
| 280 » » for (j=0;j<inDim+1;j++) | 280 for (j=0;j<inDim+1;j++) |
| 281 » » » W0_rate[i*(inDim+1)+j] = rate*net->in_rate[j]; | 281 W0_rate[i*(inDim+1)+j] = rate*net->in_rate[j]; |
| 282 » for (i=0;i<W1_size;i++) | 282 for (i=0;i<W1_size;i++) |
| 283 » » W1_rate[i] = rate; | 283 W1_rate[i] = rate; |
| 284 » | 284 |
| 285 » for (i=0;i<NB_THREADS;i++) | 285 for (i=0;i<NB_THREADS;i++) |
| 286 » { | 286 { |
| 287 » » args[i].net = net; | 287 args[i].net = net; |
| 288 » » args[i].inputs = inputs+i*samplePerPart*inDim; | 288 args[i].inputs = inputs+i*samplePerPart*inDim; |
| 289 » » args[i].outputs = outputs+i*samplePerPart*outDim; | 289 args[i].outputs = outputs+i*samplePerPart*outDim; |
| 290 » » args[i].nbSamples = samplePerPart; | 290 args[i].nbSamples = samplePerPart; |
| 291 » » args[i].id = i; | 291 args[i].id = i; |
| 292 » » args[i].done = 0; | 292 args[i].done = 0; |
| 293 » » sem_init(&sem_begin[i], 0, 0); | 293 sem_init(&sem_begin[i], 0, 0); |
| 294 » » sem_init(&sem_end[i], 0, 0); | 294 sem_init(&sem_end[i], 0, 0); |
| 295 » » pthread_create(&thread[i], NULL, gradient_thread_process, &args[
i]); | 295 pthread_create(&thread[i], NULL, gradient_thread_process, &args[i]); |
| 296 » } | 296 } |
| 297 » for (e=0;e<nbEpoch;e++) | 297 for (e=0;e<nbEpoch;e++) |
| 298 » { | 298 { |
| 299 » » double rms=0; | 299 double rms=0; |
| 300 » » double error_rate[2] = {0,0}; | 300 double error_rate[2] = {0,0}; |
| 301 » » for (i=0;i<NB_THREADS;i++) | 301 for (i=0;i<NB_THREADS;i++) |
| 302 » » { | 302 { |
| 303 » » » sem_post(&sem_begin[i]); | 303 sem_post(&sem_begin[i]); |
| 304 » » } | 304 } |
| 305 » » memset(W0_grad, 0, W0_size*sizeof(double)); | 305 memset(W0_grad, 0, W0_size*sizeof(double)); |
| 306 » » memset(W1_grad, 0, W1_size*sizeof(double)); | 306 memset(W1_grad, 0, W1_size*sizeof(double)); |
| 307 » » for (i=0;i<NB_THREADS;i++) | 307 for (i=0;i<NB_THREADS;i++) |
| 308 » » { | 308 { |
| 309 » » » sem_wait(&sem_end[i]); | 309 sem_wait(&sem_end[i]); |
| 310 » » » rms += args[i].rms; | 310 rms += args[i].rms; |
| 311 » » » error_rate[0] += args[i].error_rate[0]; | 311 error_rate[0] += args[i].error_rate[0]; |
| 312 error_rate[1] += args[i].error_rate[1]; | 312 error_rate[1] += args[i].error_rate[1]; |
| 313 » » » for (j=0;j<W0_size;j++) | 313 for (j=0;j<W0_size;j++) |
| 314 » » » » W0_grad[j] += args[i].W0_grad[j]; | 314 W0_grad[j] += args[i].W0_grad[j]; |
| 315 » » » for (j=0;j<W1_size;j++) | 315 for (j=0;j<W1_size;j++) |
| 316 » » » » W1_grad[j] += args[i].W1_grad[j]; | 316 W1_grad[j] += args[i].W1_grad[j]; |
| 317 » » } | 317 } |
| 318 | 318 |
| 319 » » float mean_rate = 0, min_rate = 1e10; | 319 float mean_rate = 0, min_rate = 1e10; |
| 320 » » rms = (rms/(outDim*nbSamples)); | 320 rms = (rms/(outDim*nbSamples)); |
| 321 » » error_rate[0] = (error_rate[0]/(nbSamples)); | 321 error_rate[0] = (error_rate[0]/(nbSamples)); |
| 322 error_rate[1] = (error_rate[1]/(nbSamples)); | 322 error_rate[1] = (error_rate[1]/(nbSamples)); |
| 323 » » fprintf (stderr, "%f %f (%f %f) ", error_rate[0], error_rate[1],
rms, best_rms); | 323 fprintf (stderr, "%f %f (%f %f) ", error_rate[0], error_rate[1], rms, be
st_rms); |
| 324 » » if (rms < best_rms) | 324 if (rms < best_rms) |
| 325 » » { | 325 { |
| 326 » » » best_rms = rms; | 326 best_rms = rms; |
| 327 » » » for (i=0;i<W0_size;i++) | 327 for (i=0;i<W0_size;i++) |
| 328 » » » { | 328 { |
| 329 » » » » best_W0[i] = W0[i]; | 329 best_W0[i] = W0[i]; |
| 330 » » » » best_W0_rate[i] = W0_rate[i]; | 330 best_W0_rate[i] = W0_rate[i]; |
| 331 » » » } | 331 } |
| 332 » » » for (i=0;i<W1_size;i++) | 332 for (i=0;i<W1_size;i++) |
| 333 » » » { | 333 { |
| 334 » » » » best_W1[i] = W1[i]; | 334 best_W1[i] = W1[i]; |
| 335 » » » » best_W1_rate[i] = W1_rate[i]; | 335 best_W1_rate[i] = W1_rate[i]; |
| 336 » » » } | 336 } |
| 337 » » » count_worse=0; | 337 count_worse=0; |
| 338 » » » count_retries=0; | 338 count_retries=0; |
| 339 » » } else { | 339 } else { |
| 340 » » » count_worse++; | 340 count_worse++; |
| 341 » » » if (count_worse>30) | 341 if (count_worse>30) |
| 342 » » » { | 342 { |
| 343 » » » count_retries++; | 343 count_retries++; |
| 344 » » » » count_worse=0; | 344 count_worse=0; |
| 345 » » » » for (i=0;i<W0_size;i++) | 345 for (i=0;i<W0_size;i++) |
| 346 » » » » { | 346 { |
| 347 » » » » » W0[i] = best_W0[i]; | 347 W0[i] = best_W0[i]; |
| 348 » » » » » best_W0_rate[i] *= .7; | 348 best_W0_rate[i] *= .7; |
| 349 » » » » » if (best_W0_rate[i]<1e-15) best_W0_rate[
i]=1e-15; | 349 if (best_W0_rate[i]<1e-15) best_W0_rate[i]=1e-15; |
| 350 » » » » » W0_rate[i] = best_W0_rate[i]; | 350 W0_rate[i] = best_W0_rate[i]; |
| 351 » » » » » W0_grad[i] = 0; | 351 W0_grad[i] = 0; |
| 352 » » » » } | 352 } |
| 353 » » » » for (i=0;i<W1_size;i++) | 353 for (i=0;i<W1_size;i++) |
| 354 » » » » { | 354 { |
| 355 » » » » » W1[i] = best_W1[i]; | 355 W1[i] = best_W1[i]; |
| 356 » » » » » best_W1_rate[i] *= .8; | 356 best_W1_rate[i] *= .8; |
| 357 » » » » » if (best_W1_rate[i]<1e-15) best_W1_rate[
i]=1e-15; | 357 if (best_W1_rate[i]<1e-15) best_W1_rate[i]=1e-15; |
| 358 » » » » » W1_rate[i] = best_W1_rate[i]; | 358 W1_rate[i] = best_W1_rate[i]; |
| 359 » » » » » W1_grad[i] = 0; | 359 W1_grad[i] = 0; |
| 360 » » » » } | 360 } |
| 361 » » » } | 361 } |
| 362 » » } | 362 } |
| 363 » » if (count_retries>10) | 363 if (count_retries>10) |
| 364 » » break; | 364 break; |
| 365 » » for (i=0;i<W0_size;i++) | 365 for (i=0;i<W0_size;i++) |
| 366 » » { | 366 { |
| 367 » » » if (W0_oldgrad[i]*W0_grad[i] > 0) | 367 if (W0_oldgrad[i]*W0_grad[i] > 0) |
| 368 » » » » W0_rate[i] *= 1.01; | 368 W0_rate[i] *= 1.01; |
| 369 » » » else if (W0_oldgrad[i]*W0_grad[i] < 0) | 369 else if (W0_oldgrad[i]*W0_grad[i] < 0) |
| 370 » » » » W0_rate[i] *= .9; | 370 W0_rate[i] *= .9; |
| 371 » » » mean_rate += W0_rate[i]; | 371 mean_rate += W0_rate[i]; |
| 372 » » » if (W0_rate[i] < min_rate) | 372 if (W0_rate[i] < min_rate) |
| 373 » » » » min_rate = W0_rate[i]; | 373 min_rate = W0_rate[i]; |
| 374 » » » if (W0_rate[i] < 1e-15) | 374 if (W0_rate[i] < 1e-15) |
| 375 » » » » W0_rate[i] = 1e-15; | 375 W0_rate[i] = 1e-15; |
| 376 » » » /*if (W0_rate[i] > .01) | 376 /*if (W0_rate[i] > .01) |
| 377 » » » » W0_rate[i] = .01;*/ | 377 W0_rate[i] = .01;*/ |
| 378 » » » W0_oldgrad[i] = W0_grad[i]; | 378 W0_oldgrad[i] = W0_grad[i]; |
| 379 » » » W0_old2[i] = W0_old[i]; | 379 W0_old2[i] = W0_old[i]; |
| 380 » » » W0_old[i] = W0[i]; | 380 W0_old[i] = W0[i]; |
| 381 » » » W0[i] += W0_grad[i]*W0_rate[i]; | 381 W0[i] += W0_grad[i]*W0_rate[i]; |
| 382 » » } | 382 } |
| 383 » » for (i=0;i<W1_size;i++) | 383 for (i=0;i<W1_size;i++) |
| 384 » » { | 384 { |
| 385 » » » if (W1_oldgrad[i]*W1_grad[i] > 0) | 385 if (W1_oldgrad[i]*W1_grad[i] > 0) |
| 386 » » » » W1_rate[i] *= 1.01; | 386 W1_rate[i] *= 1.01; |
| 387 » » » else if (W1_oldgrad[i]*W1_grad[i] < 0) | 387 else if (W1_oldgrad[i]*W1_grad[i] < 0) |
| 388 » » » » W1_rate[i] *= .9; | 388 W1_rate[i] *= .9; |
| 389 » » » mean_rate += W1_rate[i]; | 389 mean_rate += W1_rate[i]; |
| 390 » » » if (W1_rate[i] < min_rate) | 390 if (W1_rate[i] < min_rate) |
| 391 » » » » min_rate = W1_rate[i]; | 391 min_rate = W1_rate[i]; |
| 392 » » » if (W1_rate[i] < 1e-15) | 392 if (W1_rate[i] < 1e-15) |
| 393 » » » » W1_rate[i] = 1e-15; | 393 W1_rate[i] = 1e-15; |
| 394 » » » W1_oldgrad[i] = W1_grad[i]; | 394 W1_oldgrad[i] = W1_grad[i]; |
| 395 » » » W1_old2[i] = W1_old[i]; | 395 W1_old2[i] = W1_old[i]; |
| 396 » » » W1_old[i] = W1[i]; | 396 W1_old[i] = W1[i]; |
| 397 » » » W1[i] += W1_grad[i]*W1_rate[i]; | 397 W1[i] += W1_grad[i]*W1_rate[i]; |
| 398 » » } | 398 } |
| 399 » » mean_rate /= (topo[0]+1)*topo[1] + (topo[1]+1)*topo[2]; | 399 mean_rate /= (topo[0]+1)*topo[1] + (topo[1]+1)*topo[2]; |
| 400 » » fprintf (stderr, "%g %d", mean_rate, e); | 400 fprintf (stderr, "%g %d", mean_rate, e); |
| 401 » » if (count_retries) | 401 if (count_retries) |
| 402 » » fprintf(stderr, " %d", count_retries); | 402 fprintf(stderr, " %d", count_retries); |
| 403 » » fprintf(stderr, "\n"); | 403 fprintf(stderr, "\n"); |
| 404 » » if (stopped) | 404 if (stopped) |
| 405 » » » break; | 405 break; |
| 406 » } | 406 } |
| 407 » for (i=0;i<NB_THREADS;i++) | 407 for (i=0;i<NB_THREADS;i++) |
| 408 » { | 408 { |
| 409 » » args[i].done = 1; | 409 args[i].done = 1; |
| 410 » » sem_post(&sem_begin[i]); | 410 sem_post(&sem_begin[i]); |
| 411 » » pthread_join(thread[i], NULL); | 411 pthread_join(thread[i], NULL); |
| 412 » » fprintf (stderr, "joined %d\n", i); | 412 fprintf (stderr, "joined %d\n", i); |
| 413 » } | 413 } |
| 414 » free(W0_old); | 414 free(W0_old); |
| 415 » free(W1_old); | 415 free(W1_old); |
| 416 » free(W0_grad); | 416 free(W0_grad); |
| 417 » free(W1_grad); | 417 free(W1_grad); |
| 418 » free(W0_rate); | 418 free(W0_rate); |
| 419 » free(W1_rate); | 419 free(W1_rate); |
| 420 » return best_rms; | 420 return best_rms; |
| 421 } | 421 } |
| 422 | 422 |
| 423 int main(int argc, char **argv) | 423 int main(int argc, char **argv) |
| 424 { | 424 { |
| 425 » int i, j; | 425 int i, j; |
| 426 » int nbInputs; | 426 int nbInputs; |
| 427 » int nbOutputs; | 427 int nbOutputs; |
| 428 » int nbHidden; | 428 int nbHidden; |
| 429 » int nbSamples; | 429 int nbSamples; |
| 430 » int nbEpoch; | 430 int nbEpoch; |
| 431 » int nbRealInputs; | 431 int nbRealInputs; |
| 432 » unsigned int seed; | 432 unsigned int seed; |
| 433 » int ret; | 433 int ret; |
| 434 » float rms; | 434 float rms; |
| 435 » float *inputs; | 435 float *inputs; |
| 436 » float *outputs; | 436 float *outputs; |
| 437 » if (argc!=6) | 437 if (argc!=6) |
| 438 » { | 438 { |
| 439 » » fprintf (stderr, "usage: mlp_train <inputs> <hidden> <outputs> <
nb samples> <nb epoch>\n"); | 439 fprintf (stderr, "usage: mlp_train <inputs> <hidden> <outputs> <nb sampl
es> <nb epoch>\n"); |
| 440 » » return 1; | 440 return 1; |
| 441 » } | 441 } |
| 442 » nbInputs = atoi(argv[1]); | 442 nbInputs = atoi(argv[1]); |
| 443 » nbHidden = atoi(argv[2]); | 443 nbHidden = atoi(argv[2]); |
| 444 » nbOutputs = atoi(argv[3]); | 444 nbOutputs = atoi(argv[3]); |
| 445 » nbSamples = atoi(argv[4]); | 445 nbSamples = atoi(argv[4]); |
| 446 » nbEpoch = atoi(argv[5]); | 446 nbEpoch = atoi(argv[5]); |
| 447 » nbRealInputs = nbInputs; | 447 nbRealInputs = nbInputs; |
| 448 » inputs = malloc(nbInputs*nbSamples*sizeof(*inputs)); | 448 inputs = malloc(nbInputs*nbSamples*sizeof(*inputs)); |
| 449 » outputs = malloc(nbOutputs*nbSamples*sizeof(*outputs)); | 449 outputs = malloc(nbOutputs*nbSamples*sizeof(*outputs)); |
| 450 » | 450 |
| 451 » seed = time(NULL); | 451 seed = time(NULL); |
| 452 /*seed = 1361480659;*/ | 452 /*seed = 1361480659;*/ |
| 453 » fprintf (stderr, "Seed is %u\n", seed); | 453 fprintf (stderr, "Seed is %u\n", seed); |
| 454 » srand(seed); | 454 srand(seed); |
| 455 » build_tansig_table(); | 455 build_tansig_table(); |
| 456 » signal(SIGTERM, handler); | 456 signal(SIGTERM, handler); |
| 457 » signal(SIGINT, handler); | 457 signal(SIGINT, handler); |
| 458 » signal(SIGHUP, handler); | 458 signal(SIGHUP, handler); |
| 459 » for (i=0;i<nbSamples;i++) | 459 for (i=0;i<nbSamples;i++) |
| 460 » { | 460 { |
| 461 » » for (j=0;j<nbRealInputs;j++) | 461 for (j=0;j<nbRealInputs;j++) |
| 462 » » » ret = scanf(" %f", &inputs[i*nbInputs+j]); | 462 ret = scanf(" %f", &inputs[i*nbInputs+j]); |
| 463 » » for (j=0;j<nbOutputs;j++) | 463 for (j=0;j<nbOutputs;j++) |
| 464 » » » ret = scanf(" %f", &outputs[i*nbOutputs+j]); | 464 ret = scanf(" %f", &outputs[i*nbOutputs+j]); |
| 465 » » if (feof(stdin)) | 465 if (feof(stdin)) |
| 466 » » { | 466 { |
| 467 » » » nbSamples = i; | 467 nbSamples = i; |
| 468 » » » break; | 468 break; |
| 469 » » } | 469 } |
| 470 » } | 470 } |
| 471 » int topo[3] = {nbInputs, nbHidden, nbOutputs}; | 471 int topo[3] = {nbInputs, nbHidden, nbOutputs}; |
| 472 » MLPTrain *net; | 472 MLPTrain *net; |
| 473 | 473 |
| 474 » fprintf (stderr, "Got %d samples\n", nbSamples); | 474 fprintf (stderr, "Got %d samples\n", nbSamples); |
| 475 » net = mlp_init(topo, 3, inputs, outputs, nbSamples); | 475 net = mlp_init(topo, 3, inputs, outputs, nbSamples); |
| 476 » rms = mlp_train_backprop(net, inputs, outputs, nbSamples, nbEpoch, 1); | 476 rms = mlp_train_backprop(net, inputs, outputs, nbSamples, nbEpoch, 1); |
| 477 » printf ("#include \"mlp.h\"\n\n"); | 477 printf ("#include \"mlp.h\"\n\n"); |
| 478 » printf ("/* RMS error was %f, seed was %u */\n\n", rms, seed); | 478 printf ("/* RMS error was %f, seed was %u */\n\n", rms, seed); |
| 479 » printf ("static const float weights[%d] = {\n", (topo[0]+1)*topo[1] + (t
opo[1]+1)*topo[2]); | 479 printf ("static const float weights[%d] = {\n", (topo[0]+1)*topo[1] + (topo[
1]+1)*topo[2]); |
| 480 » printf ("\n/* hidden layer */\n"); | 480 printf ("\n/* hidden layer */\n"); |
| 481 » for (i=0;i<(topo[0]+1)*topo[1];i++) | 481 for (i=0;i<(topo[0]+1)*topo[1];i++) |
| 482 » { | 482 { |
| 483 » » printf ("%gf, ", net->weights[0][i]); | 483 printf ("%gf, ", net->weights[0][i]); |
| 484 » » if (i%5==4) | 484 if (i%5==4) |
| 485 » » » printf("\n"); | 485 printf("\n"); |
| 486 » } | 486 } |
| 487 » printf ("\n/* output layer */\n"); | 487 printf ("\n/* output layer */\n"); |
| 488 » for (i=0;i<(topo[1]+1)*topo[2];i++) | 488 for (i=0;i<(topo[1]+1)*topo[2];i++) |
| 489 » { | 489 { |
| 490 » » printf ("%g, ", net->weights[1][i]); | 490 printf ("%g, ", net->weights[1][i]); |
| 491 » » if (i%5==4) | 491 if (i%5==4) |
| 492 » » » printf("\n"); | 492 printf("\n"); |
| 493 » } | 493 } |
| 494 » printf ("};\n\n"); | 494 printf ("};\n\n"); |
| 495 » printf ("static const int topo[3] = {%d, %d, %d};\n\n", topo[0], topo[1]
, topo[2]); | 495 printf ("static const int topo[3] = {%d, %d, %d};\n\n", topo[0], topo[1], to
po[2]); |
| 496 » printf ("const MLP net = {\n"); | 496 printf ("const MLP net = {\n"); |
| 497 » printf ("\t3,\n"); | 497 printf ("\t3,\n"); |
| 498 » printf ("\ttopo,\n"); | 498 printf ("\ttopo,\n"); |
| 499 » printf ("\tweights\n};\n"); | 499 printf ("\tweights\n};\n"); |
| 500 » return 0; | 500 return 0; |
| 501 } | 501 } |
| OLD | NEW |