File Coverage

blib/lib/Neuron.pm
Criterion Covered Total %
statement 135 223 60.5
branch 3 18 16.6
condition 3 16 18.7
subroutine 14 20 70.0
pod 0 7 0.0
total 155 284 54.5


line stmt bran cond sub pod time code
1              
2              
3             package Neuron;
4              
5             $VERSION = "0.0.1";
6              
7             =head1 NAME
8             Neuron networks
9              
10             =head1
11              
12             =head1 AUTHOR
13              
14             Yuri Kostylev
15             based on stuff by
16             Daniel Franklin (d.franklin@computer.org)
17              
18             =cut
19              
20             # -------------------------------------------------------------------------
21              
22             sub sigma {
23             # my $d = shift;
24 46352     46352 0 131911 return 1.0 / (1.0 + exp(- shift));
25             }
26              
27             # -------------------------------------------------------------------------
28              
29             sub new {
30 26     26 0 42 my $self = {};
31 26         60 $self->{NAME} = shift;
32 26         40 $self->{NUMIN} = shift;
33 26         42 $self->{IN} = [];
34 26         40 $self->{OUT} = 0;
35 26         30 bless $self;
36 26         52 $self -> init();
37 26         93 return $self;
38             }
39              
40             # ------------------------------------------------------------------------
41             # not used
42              
43             sub numin {
44 0     0 0 0 my $self = shift;
45 0 0       0 if (@_) { $self -> {NUMIN} = shift;}
  0         0  
46 0         0 return $self->{NUMIN};
47             }
48              
49             # ------------------------------------------------------------------------
50              
51             sub out {
52             # my $self = shift;
53             # return $self -> {OUT};
54 158047     158047 0 424159 return shift -> {OUT};
55             }
56              
57             # ------------------------------------------------------------------------
58             # not used
59              
60             sub show_in {
61 0     0 0 0 my $self = shift;
62 0         0 my $i;
63 0         0 for($i = 0; $i < $self->{NUMIN}; $i ++) {
64 0         0 print $self->{IN}[$i], " ";
65             }
66 0         0 print "\n";
67             }
68              
69             # ------------------------------------------------------------------------
70             # not used for now
71              
72             sub compute {
73 11     11 0 19 my $self = shift;
74 11         25 my @data = @_;
75 11         14 my $sum = 0;
76 11         9 my $i;
77 11         27 for($i = 0; $i < $self -> {NUMIN}; $i ++) {
78 210         538 $sum += $data[$i] * $self->{IN}[$i];
79             # print $data[$i], "\n";
80             }
81 11         28 $out = sigma($sum/$self->{NUMIN});
82             # print $out, "\n";
83 11         18 $self -> {OUT} = $out;
84 11         42 return $out;
85             }
86              
87             # -----------------------------------------------------------------------
88             # constructor
89              
90             sub init {
91 26     26 0 38 my $self = shift;
92 26         28 my($i);
93 26         74 for($i = 0; $i < $self -> {NUMIN}; $i ++) {
94 892         2612 $self->{IN}[$i] = 0.5 - rand;
95             # $self->{IN}[$i] = 0;
96             }
97             }
98              
99             # -----------------------------------------------------------------------
100              
101             package NLayer;
102              
103             sub new {
104 6     6   31 my $self = {};
105 6         17 $self -> {NAME} = shift;
106 6         11 $self -> {SIZE} = shift;
107 6         13 $self -> {BOT_SIZE} = shift;
108 6         23 $self -> {NEURONS} = [];
109            
110 6         9 bless $self;
111            
112 6         19 $self -> init;
113            
114 6         23 return $self;
115             }
116              
117             # -----------------------------------------------------------------------
118              
119             sub init {
120 6     6   9 my $self = shift;
121 6         8 my $i;
122 6         36 for($i = 0; $i < $self -> {SIZE}; $i ++) {
123 26         71 $self -> {NEURONS}[$i] = Neuron -> new($self -> {BOT_SIZE});
124             }
125             }
126              
127             # -----------------------------------------------------------------------
128             # not used
129              
130             sub show_neurons {
131 0     0   0 my $self = shift;
132 0         0 my $i;
133 0         0 for($i = 0; $i < $self -> {SIZE}; $i ++) {
134 0         0 $self -> {NEURONS}[$i] -> show_in;
135             }
136             }
137              
138             # -----------------------------------------------------------------------
139             # retrieves single neuron by index
140              
141             sub neuron {
142 4065806     4065806   4049235 my $self = shift;
143             # my $n = shift; # index of neuron
144 4065806         12395548 return $self -> {NEURONS}[ shift ];
145             }
146              
147             # -----------------------------------------------------------------------
148             # not used
149              
150             sub show_out {
151 0     0   0 my $self = shift;
152 0         0 my $i;
153 0         0 for($i = 0; $i < $self -> {SIZE}; $i ++) {
154 0         0 print $self -> {NEURONS}[$i] -> out, "\n";
155             }
156             }
157              
158             # ------------------------------------------------------------------------
159             # not used for now
160              
161             sub compute {
162 2     2   13 my $self = shift;
163 2         6 my @data = @_; # size of data == $self -> {BOT_SIZE} !!!
164 2         2 my $i;
165            
166 2         6 for($i = 0; $i < $self -> {SIZE}; $i ++) {
167 11         30 $self -> {NEURONS}[$i] -> compute(@data);
168             }
169             }
170              
171             # -------------------------------------------------------------------------
172              
173             package NNet;
174              
175             sub new {
176 2     2   59 my $self = {};
177            
178 2         19 $self -> {NAME} = shift;
179 2         6 $self -> {IN_SIZE} = shift;
180 2         5 $self -> {HIDDEN_SIZE} = shift;
181 2         9 $self -> {OUT_SIZE} = shift;
182            
183 2         5 $self -> {OUT_LAYER} = undef;
184 2         6 $self -> {HIDDEN_LAYER} = undef;
185            
186 2 50 33     28 if(! $self -> {IN_SIZE} || ! $self -> {HIDDEN_SIZE}
      33        
187             || ! $self -> {OUT_SIZE} ) {
188 0         0 die "Bad network sizes";
189             }
190 2         5 bless $self;
191 2         11 $self -> init;
192 2         6 return $self;
193             }
194              
195             # --------------------------------------------------------------------------
196              
197             sub init {
198 2     2   4 my $self = shift;
199 2         25 $self -> {HIDDEN_LAYER} = NLayer ->
200             new($self -> {HIDDEN_SIZE}, $self -> {IN_SIZE});
201 2         11 $self -> {OUT_LAYER} = NLayer ->
202             new($self -> {OUT_SIZE}, $self -> {HIDDEN_SIZE});
203             }
204              
205             # ---------------------------------------------------------------------------
206              
207             sub load {
208 0     0   0 my $self = {};
209 0         0 $self -> {NAME} = shift;
210 0         0 my $fname = shift;
211              
212 0         0 $self -> {OUT_LAYER} = undef;
213 0         0 $self -> {HIDDEN_LAYER} = undef;
214              
215 0         0 my ($s, $i, $j);
216 0         0 my $line = 1;
217 0         0 my @a;
218              
219 0   0     0 open FILE, "<$fname" || die "Cant open file";
220              
221 0         0 $s = ; chomp($s);
  0         0  
222 0 0       0 if($s =~ /^Insize /) {
223 0         0 $self -> {IN_SIZE} = $';
224             } else {
225 0         0 die "Bad file format in $line";
226             }
227 0         0 $line ++;
228 0         0 $s = ; chomp($s);
  0         0  
229 0 0       0 if($s =~ /^Hiddensize /) {
230 0         0 $self -> {HIDDEN_SIZE} = $';
231             } else {
232 0         0 die "Bad file format in $line";
233             }
234 0         0 $line ++;
235 0         0 $s = ; chomp($s);
  0         0  
236 0 0       0 if($s =~ /^Outsize /) {
237 0         0 $self -> {OUT_SIZE} = $';
238             } else {
239 0         0 die "Bad file format in $line";
240             }
241 0         0 $line ++;
242 0 0 0     0 if(! $self -> {IN_SIZE} || ! $self -> {HIDDEN_SIZE}
      0        
243             || ! $self -> {OUT_SIZE} ) {
244 0         0 die "Bad network sizes";
245             }
246 0         0 bless $self;
247              
248 0         0 $self -> {HIDDEN_LAYER} = NLayer ->
249             new($self -> {HIDDEN_SIZE}, $self -> {IN_SIZE});
250 0         0 $self -> {OUT_LAYER} = NLayer ->
251             new($self -> {OUT_SIZE}, $self -> {HIDDEN_SIZE});
252              
253             # read data
254 0         0 $s = ; chomp($s);
  0         0  
255 0 0       0 if(! $s =~ /^Hiddenlayer:/) {
256 0         0 die "Bad file format in $line";
257             }
258 0         0 $line ++;
259              
260 0         0 for($i = 0; $i < $self -> {HIDDEN_SIZE}; $i ++) {
261 0         0 $s = ; chomp($s);
  0         0  
262 0         0 @a = split(/ /, $s);
263 0         0 for($j = 0; $j < $self -> {IN_SIZE}; $j ++) {
264 0         0 $self -> {HIDDEN_LAYER} -> neuron($i) -> {IN}[$j] =
265             $a[$j];
266             }
267              
268 0         0 $line ++;
269             }
270              
271 0         0 $s = ; chomp($s);
  0         0  
272 0 0       0 if(! $s =~ /^Outlayer:/) {
273 0         0 die "Bad file format in $line";
274             }
275 0         0 $line ++;
276              
277 0         0 for($i = 0; $i < $self -> {OUT_SIZE}; $i ++) {
278 0         0 $s = ; chomp($s);
  0         0  
279 0         0 @a = split(/ /, $s);
280 0         0 for($j = 0; $j < $self -> {HIDDEN_SIZE}; $j ++) {
281 0         0 $self -> {OUT_LAYER} -> neuron($i) -> {IN}[$j] =
282             $a[$j];
283             }
284              
285 0         0 $line ++;
286             }
287              
288              
289 0         0 close FILE;
290 0         0 return $self;
291             }
292              
293             # ---------------------------------------------------------------------------
294              
295             sub show {
296 0     0   0 my $self = shift;
297 0         0 print "Hiden in:\n";
298 0         0 $self -> {HIDDEN_LAYER} -> show_neurons;
299 0         0 print "Hidden out:\n";
300 0         0 $self -> {HIDDEN_LAYER} -> show_out;
301 0         0 print "Out in:\n";
302 0         0 $self -> {OUT_LAYER} -> show_neurons;
303 0         0 print "Out out:\n";
304 0         0 $self -> {OUT_LAYER} -> show_out;
305             }
306              
307             # --------------------------------------------------------------------------
308              
309             sub run {
310 5684     5684   7530 my $self = shift;
311 5684         34153 my @data = @_;
312 5684         9064 my ($i, $j, $k, $sum);
313 5684         6743 my @result = ();
314 5684         6515 my ($hidden_size, $in_size, $out_size);
315 0         0 my ($hidden_layer, $out_layer);
316              
317 5684         8609 $hidden_size = $self -> {HIDDEN_SIZE};
318 5684         7451 $in_size = $self -> {IN_SIZE};
319 5684         7132 $out_size = $self -> {OUT_SIZE};
320              
321 5684         6903 $hidden_layer = $self -> {HIDDEN_LAYER};
322 5684         6892 $out_layer = $self -> {OUT_LAYER};
323            
324 5684         12596 for($j = 0; $j < $hidden_size; $j ++) {
325 36578         42680 $sum = 0;
326 36578         69818 for($i = 0; $i < $in_size; $i ++) {
327 1912697         2984310 $sum += $hidden_layer -> neuron($j) -> {IN}[$i]
328             * $data[$i];
329             }
330 36578         59932 $hidden_layer -> neuron($j) -> {OUT} = Neuron::sigma($sum);
331             }
332 5684         12595 for($k = 0; $k < $out_size; $k ++) {
333 9763         9988 $sum = 0;
334 9763         19284 for($j = 0; $j < $hidden_size; $j ++) {
335 65131         107392 $sum += $out_layer -> neuron($k) -> {IN}[$j]
336             * $hidden_layer -> neuron($j) -> out;
337             }
338 9763         18610 $result[$k] = $out_layer -> neuron($k) -> {OUT}
339             = Neuron::sigma($sum);
340             }
341 5684         30503 return @result;
342             }
343              
344             # -----------------------------------------------------------------------
345              
346             sub train {
347 434     434   4748 my $self = shift;
348 434         546 my $max_mse = shift;
349 434         470 my $eta = shift;
350 434         2069 my @data = @_;
351 434         813 my $N = $self -> {IN_SIZE};
352            
353 434         579 my ($mse, $mse_max, $sum, $i, $j, $k);
354 434         654 my @output = ();
355 434         568 my @owd = ();
356 434         581 my @hwd = ();
357 434         567 my $count = 0;
358              
359 434         482 my ($out_size, $hidden_size, $in_size);
360 0         0 my ($hidden_layer, $out_layer);
361 0         0 my $aux;
362              
363 434         680 $hidden_layer = $self -> {HIDDEN_LAYER};
364 434         621 $out_layer = $self -> {OUT_LAYER};
365            
366 434         523 $mse_max = $max_mse * 2;
367 434         566 $in_size = $self -> {IN_SIZE};
368 434         747 $out_size = $self -> {OUT_SIZE};
369 434         519 $hidden_size = $self -> {HIDDEN_SIZE};
370              
371 434         402 while(1) {
372 5681         18002 @output = $self -> run(@data);
373 5681         8933 $mse = 0;
374 5681         13130 for($k = 0; $k < $out_size; $k ++) {
375 9757         12676 $aux = $output[$k];
376 9757         16820 $owd[$k] = $data[$k + $N] - $aux;
377            
378 9757         13666 $mse += $owd[$k] * $owd[$k];
379            
380 9757         23051 $owd[$k] *= $aux * (1 - $aux);
381             }
382            
383             #if($count % 100 == 0) {
384             # print "$count\t", $mse, "\n";
385             #}
386            
387 5681 100       10935 last if($mse < $mse_max);
388            
389 5247         10569 for($j = 0; $j < $hidden_size; $j ++) {
390 33587         34302 $sum = 0;
391 33587         60146 for($k = 0; $k < $out_size; $k ++) {
392 59319         102482 $sum += $owd[$k] * $out_layer -> neuron($k) -> {IN}[$j];
393             }
394 33587         51881 $aux = $hidden_layer -> neuron($j) -> out;
395 33587         91646 $hwd[$j] = $sum * $aux * (1 - $aux);
396             }
397 5247         10466 for($k = 0; $k < $out_size; $k ++) {
398 8923         17287 for($j = 0; $j < $hidden_size; $j ++) {
399 59319         89580 $out_layer -> neuron($k) -> {IN}[$j] +=
400             $eta * $owd[$k] * $hidden_layer -> neuron($j) -> out;
401             }
402             }
403 5247         10831 for($j = 0; $j < $hidden_size; $j ++) {
404 33587         63498 for($i = 0; $i < $in_size; $i ++) {
405 1763588         2620869 $hidden_layer -> neuron($j) -> {IN}[$i] +=
406             $eta * $hwd[$j] * $data[$i];
407             }
408             }
409 5247         6297 $count ++;
410             }
411             # print $count, "\n";
412 434         3002 return $count;
413             }
414              
415             # --------------------------------------------------------------------------
416              
417             sub save {
418 4     4   26 my $self = shift;
419 4         7 my $fname = shift;
420 4         6 my ($i, $j);
421 4   50     1614 open FILE, ">$fname" || die "Cant open file\n";
422              
423 4         170 print FILE "Insize ", $self -> {IN_SIZE}, "\n";
424 4         17 print FILE "Hiddensize ", $self -> {HIDDEN_SIZE}, "\n";
425 4         13 print FILE "Outsize ", $self -> {OUT_SIZE}, "\n";
426              
427 4         9 print FILE "Hiddenlayer:\n";
428 4         19 for($i = 0; $i < $self -> {HIDDEN_SIZE}; $i ++) {
429 24         67 for($j = 0; $j < $self -> {IN_SIZE}; $j ++) {
430 1326         3186 print FILE $self -> {HIDDEN_LAYER} -> neuron($i) ->
431             {IN}[$j], " ";
432             }
433 24         80 print FILE "\n";
434             }
435 4         10 print FILE "Outlayer:\n";
436 4         19 for($i = 0; $i < $self -> {OUT_SIZE}; $i ++) {
437 6         32 for($j = 0; $j < $self -> {HIDDEN_SIZE}; $j ++) {
438 38         94 print FILE $self -> {OUT_LAYER} -> neuron($i) ->
439             {IN}[$j], " ";
440             }
441 6         74 print FILE "\n";
442             }
443              
444 4         685 close FILE;
445             }
446              
447             1;