package Neuron; use Strict; use Carp; ####################################################################### # # Class: Neuron # # A neuron has an internal state (V), a set of parent # nodes (PARENTS), a set of weights connected with the # parent nodes (W), a set of child nodes (CHILDREN), # and a delta (DELTA) which is computed during backpropogation # and is used by its parent nodes for weight correction. # ####################################################################### ####################################################################### # # Package (class) data # # $beta is a common variable representing the 'harshness' of # the sigmoid function to input data. $beta is set by the # application using the neural network. # ####################################################################### my $beta; sub beta { if (@_) { $beta = shift; } return $beta; } # # Sigmoid function # sub g { my ($h) = @_; return 1.0 / ( 1.0 + exp( -2.0 * $beta * $h ) ); } ####################################################################### # # Instance (object) data # # new(): creates a new Neuron. # V(): accessor for the neuron's state. # delta(): accessor for the neuron's delta. # parents(): read-only accessor to return list of parent nodes. # weights(): read-only accessor to return list of weights. # children(): read-only accessor to return list of children. # addChild(): adds a child node. # toString(): returns basic data about the neuron in a String. # # calculateValue(): calculates state (V) of neuron using # forward propogation. # ####################################################################### # constructor sub new { my $proto = shift; my $class = ref( $proto ) || $proto; my $self = {}; $self->{V} = 0.0; $self->{DELTA} = 0.0; $self->{PARENTS} = []; $self->{W} = []; $self->{CHILDREN}= []; # # Allow methods to be called on this object. # bless( $self, $class ); return $self; } sub V { my $self = shift; if (@_) { $self->{V} = shift; } return $self->{V}; } sub delta { my $self = shift; if (@_) { $self->{DELTA} = shift; } return $self->{DELTA}; } sub parents { my $self = shift; return $self->{PARENTS}; } sub weights { my $self = shift; return $self->{W}; } sub children { my $self = shift; return $self->{CHILDREN}; } sub addChild { my $self = shift; my $child = shift; push( @{$self->{CHILDREN}}, $child ); push( @{$child->{PARENTS}}, $self ); push( @{$child->{W}}, 2 * (rand() - 0.5) ); } sub toString { my $self = shift; return "V : ", $self->V, "\n" , "delta : ", $self->delta, "\n" , "parents : ", scalar @{$self->parents}, "\n" , "children: ", scalar @{$self->children}, "\n", , "weights : ", join( " ", @{$self->weights} ), "\n" ; } # # Calculates V based on parents' V and weights. # sub calculateValue { my $self = shift; my $h = 0.0; #print "parents: ", scalar @{$self->parents}, "\n"; for ( my $i=0; $i<@{$self->parents}; $i++ ) { my $parentRef = ${$self->parents}[$i]; $h += $parentRef->V * ${$self->weights}[$i]; #print "parent V=", $parentRef->V, "\n"; #print "h=$h\n"; } # # Here's the sigmoid. # $self->V( &g($h) ); #print "my V=", $self->V, "\n"; } 1; # so the require or use succeeds