1 <?php
2 3 4 5 6 7 8 9 10 11 12 13 14
15 class nmesh
16 {
17
18 public $layer = array();
19
20 public $inputs;
21
22 public $outputs;
23
24 static public $momentumrate = 0.5;
25
26 static public $cache;
27
28 function sigmoid($value) {
29 return 1 / (1+exp(-1*$value));
30 }
31
32 33 34 35 36
37 function run($inputarray)
38 {
39 $output = array();
40 $l_count = count($this->layer);
41
42 for($l = 0; $l < $l_count; ++$l) {
43
44 foreach($this->layer[$l]->neuron as $neuron) {
45 $inputs = ($l===0) ? $inputarray : $output[$l];
46
47 $x = 0; $sum = 0;
48 foreach($neuron->synapse as $synapse) {
49 $synapse->input = $inputs[$x];
50 $sum += $synapse->weight * $synapse->input;
51 ++$x;
52 }
53
54 $value = 1/(1+exp(-1*($sum+$neuron->bias)));
55 $neuron->value = $value;
56 $output[$l+1][] = $value;
57 }
58 }
59 $data = $output[$l];
60 self::$cache = $data;
61 return $data;
62 }
63
64 65 66 67 68 69 70 71
72 function quick_train($id,$epochs,$lr,$inputs,$outputs) {
73 $inputarray = str_split($inputs);
74 $outputarray = str_split($outputs);
75
76 $start = microtime(true);
77 for($i=0;$i<$epochs;$i++) {
78 $end_mse = $this->train($inputarray,$outputarray,$lr);
79 if($i===1) $start_mse = $end_mse;
80 }
81 $exectime = microtime(true)-$start;
82 return array("startmse"=>$start_mse,"endmse"=>$end_mse,"time"=>$exectime);
83 }
84
85 86 87 88 89 90 91 92
93 function train($inputarray,$outputarray,$learningrate)
94 {
95 $this->run($inputarray);
96 return $this->calculate_deltas($outputarray,$learningrate);
97 }
98
99 100 101 102 103 104
105 function calculate_deltas($outputarray,$lr)
106 {
107 $mse_sum = 0;
108 $l_count = count($this->layer)-1;
109 $m = nmesh::$momentumrate;
110 $error = array();
111 $output_count = count($this->layer[$l_count]->neuron);
112
113 for($l = $l_count; $l >= 0; --$l) {
114
115 $error[$l] = array_fill(0,count($this->layer[$l]->neuron[0]->synapse),0);
116
117 foreach($this->layer[$l]->neuron as $n=>$neuron)
118 {
119 if($l===$l_count) {
120 $n_error = $outputarray[$n] - $neuron->value;
121 $mse_sum += $n_error * $n_error;
122 } else $n_error = $error[$l+1][$n];
123
124 $delta = $n_error * $neuron->value * (1 - $neuron->value);
125
126 foreach($neuron->synapse as $s=>$synapse)
127 {
128 $wc = $delta * $synapse->input * $lr + $synapse->momentum * $m;
129 $synapse->momentum = $wc;
130 $synapse->weight += $wc;
131 $error[$l][$s] += $delta * $synapse->weight;
132 }
133
134 $biaschange = $delta * $lr + $neuron->momentum * $m;
135 $neuron->momentum = $biaschange;
136 $neuron->bias += $biaschange;
137 }
138 }
139 return $mse_sum / $output_count;
140 }
141
142 143 144
145 function sigmoid_derivative($value)
146 {
147 return $value * (1 - $value);
148 }
149
150 151 152 153
154 function remove_inputs($inputs) {
155 if($this->inputs - $inputs < 1)
156 throw new Exception("Cannot remove neurons!");
157
158 $this->inputs -= $inputs;
159 for($i=0;$i<$inputs;$i++) {
160 $n_count = count($this->layer[0]->neuron);
161 for($n=0;$n<$n_count;$n++) {
162 $this->layer[0]->neuron[$n]->remove_synapse();
163 }
164 }
165 }
166
167 168 169 170
171 function add_inputs($inputs) {
172 $this->inputs += $inputs;
173 for($i=0;$i<$inputs;$i++) {
174 $n_count = count($this->layer[0]->neuron);
175 for($n=0;$n<$n_count;$n++) {
176 $this->layer[0]->neuron[$n]->add_synapse();
177 }
178 }
179 }
180
181 182 183 184
185 function remove_outputs($outputs) {
186 if($this->outputs - $outputs < 1) throw new Exception("Cannot remove that many outputs!");
187 $this->outputs -= $outputs;
188 for($i=0;$i<$outputs;$i++) {
189 $this->layer[count($this->layer)-1]->remove_neuron();
190 }
191 }
192
193 194 195 196
197 function add_outputs($outputs) {
198 $this->outputs += $outputs;
199 for($i=0;$i<$outputs;$i++) {
200 $this->layer[count($this->layer)-1]->add_neuron();
201 }
202 }
203
204 205 206 207 208
209 function add_layer($neuronal_bias=1,$initial_weightrange=1) {
210 $hidden_neurons = count($this->layer[0]->neuron);
211 array_splice($this->layer,
212 count($this->layer)-1,
213 0,
214
215 array(new layer($hidden_neurons,$hidden_neurons,$neuronal_bias,$initial_weightrange)));
216 }
217
218 219 220 221 222 223
224 function add_neuron($count=1,$bias=1,$weightrange=1) {
225 for($i=0;$i<$count;$i++) {
226 for($l=0;$l<count($this->layer)-1;$l++) {
227 $this->layer[$l]->add_neuron($bias,$weightrange);
228 for($n=0;$n<count($this->layer[$l+1]->neuron);$n++) {
229
230 $this->layer[$l+1]->neuron[$n]->add_synapse();
231 }
232 }
233 }
234 }
235
236 237 238 239
240 function remove_layer($layer=null) {
241
242 $layer = is_null($layer) ? count($this->layer)-2 : $layer;
243 if(count($this->layer) > 2 && $this->is_hidden_layer($layer)) {
244 array_splice($this->layer,$layer,1);
245 }
246 }
247
248 249 250 251
252 function remove_neuron($count=0) {
253 if(count($this->layer[0]->neuron) - $count < 1)
254 throw new Exception("Cannot remove neurons!");
255
256 for($l=0;$l<count($this->layer)-1;$l++) {
257
258 for($c=0;$c<$count;$c++) $this->layer[$l]->remove_neuron();
259
260 for($n=0;$n<count($this->layer[$l+1]->neuron);$n++) {
261
262 for($c=0;$c<$count;$c++) $this->layer[$l+1]->neuron[$n]->remove_synapse($count);
263 }
264 }
265 }
266
267 268 269
270 function nmesh($input_neurons,$output_neurons,$hidden_neurons_per_layer,$hidden_layers,$neuronal_bias=1,$initial_weightrange=1)
271 {
272 $this->inputs = $input_neurons;
273 $this->outputs= $output_neurons;
274 $firstlayerflag = 0;
275 $total_layers = $hidden_layers+1;
276
277 $this->layer[0] = new layer($hidden_neurons_per_layer,$input_neurons,$neuronal_bias,$initial_weightrange);
278 for($i=1;$i<$total_layers-1;$i++)
279 {
280 $inputs = $input_neurons;
281 if($firstlayerflag==1)
282 {
283 $inputs = $hidden_neurons_per_layer;
284 }
285 $this->layer[$i] = new layer($hidden_neurons_per_layer,$inputs,$neuronal_bias,$initial_weightrange);
286 $firstlayerflag=1;
287 }
288 $this->layer[$total_layers-1] = new layer($output_neurons,$hidden_neurons_per_layer,$neuronal_bias,$initial_weightrange);
289 }
290 }
291
292 293 294 295
296 class layer
297 {
298
299 public $neuron = array();
300
301 302 303
304 function add_neuron($bias=1,$weightrange=1) {
305 $this->neuron[count($this->neuron)] = new neuron(count($this->neuron[0]->synapse),$bias,$weightrange);
306 }
307
308 309 310
311 function remove_neuron() {
312 array_splice($this->neuron,0,1);
313 }
314
315 316 317 318 319
320 function layer($neurons,$inputs,$bias,$weightrange)
321 {
322 for($i=0;$i<$neurons;$i++)
323 {
324 $this->neuron[$i] = new neuron($inputs,$bias,$weightrange);
325 }
326 }
327 }
328
329 330 331 332
333 class neuron
334 {
335
336 public $value;
337
338 public $bias;
339
340
341
342 public $momentum;
343
344 public $synapse = array();
345
346 347 348
349 function cleanup()
350 {
351 unset($this->error);
352 unset($this->value);
353 }
354
355 356 357 358 359
360 function adjust_weights_clean($learningrate,$delta)
361 {
362 $m = nmesh::$momentumrate;
363
364 foreach($this->synapse as $synapse)
365 {
366 $weightchange = $delta * $synapse->input * $learningrate + $synapse->momentum * $m;
367 $synapse->momentum = $weightchange;
368 $synapse->weight += $weightchange;
369
370 unset($synapse->input); unset($synapse->delta);
371 }
372
373 $biaschange = $delta * $learningrate + $this->momentum * $m;
374 $this->momentum = $biaschange;
375 $this->bias += $biaschange;
376 }
377
378 379 380 381 382
383 function adjust_weights($learningrate,$delta)
384 {
385 $m = nmesh::$momentumrate;
386
387 foreach($this->synapse as $synapse)
388 {
389 $synapse->delta = $delta;
390 $weightchange = $delta * $synapse->input * $learningrate + $synapse->momentum * $m;
391 $synapse->momentum = $weightchange;
392 $synapse->weight += $weightchange;
393 }
394
395 $biaschange = $delta * $learningrate + $this->momentum * $m;
396 $this->momentum = $biaschange;
397 $this->bias += $biaschange;
398 }
399
400 401 402 403
404 function randomize_weights($weightrange)
405 {
406 $s_count = count($this->synapse);
407 for($i=0;$i<$s_count;$i++)
408 {
409 $this->synapse[$i]->randomize_weight($weightrange);
410 }
411 }
412
413 414 415 416 417
418 function sigmoid($value)
419 {
420 return 1 / (1+exp(-1*$value));
421 }
422
423 424 425 426
427 function add_synapse($weightrange=1) {
428 $this->synapse[count($this->synapse)] = new synapse($weightrange);
429 }
430
431 432 433
434 function remove_synapse() {
435 array_splice($this->synapse,0,1);
436 }
437
438 439 440 441
442 function neuron($inputs,$bias,$weightrange)
443 {
444 unset($this->value);
445 unset($this->error);
446 $this->bias = $bias;
447 $this->momentum = 0;
448
449 for($i=0;$i<$inputs;$i++)
450 {
451 $this->synapse[$i] = new synapse($weightrange);
452 }
453 }
454 }
455
456 457 458 459
460 class synapse
461 {
462
463 public $input;
464
465 public $weight;
466
467
468
469 public $momentum;
470
471 472 473
474 function cleanup()
475 {
476 unset($this->input);
477 unset($this->delta);
478 }
479
480 481 482 483
484 function randomize_weight($weightrange)
485 {
486 $this->weight = (mt_rand(0,$weightrange*2000)/1000)-$weightrange;
487 }
488
489 490 491 492
493 function synapse($weightrange)
494 {
495 unset($this->input);
496 unset($this->delta);
497 $this->momentum = 0;
498 $this->randomize_weight($weightrange);
499 }
500 }
501 ?>