AI-ANN
view release on metacpan or search on metacpan
lib/AI/ANN.pm view on Meta::CPAN
}
delete $data{'data'};
return $class->$orig(%data);
};
sub execute {
my $self = shift;
my $inputs = $self->{'inputs'} = shift;
# Don't bother dereferencing $inputs only to rereference a lot
my $net = $self->{'network'}; # For less typing
my $lastneuron = $#{$net};
my @neurons = ();
foreach my $i (0..$lastneuron) {
$neurons[$i] = 0;
}
foreach my $i (0..$lastneuron) {
delete $net->[$i]->{'done'};
delete $net->[$i]->{'state'};
}
my $progress = 0;
do {
$progress = 0;
foreach my $i (0..$lastneuron) {
if ($net->[$i]->{'done'}) {next}
if ($net->[$i]->{'object'}->ready($inputs, \@neurons)) {
my $potential = $net->[$i]->{'object'}->execute($inputs, \@neurons);
$self->{'rawpotentials'}->[$i] = $potential;
$potential = $self->{'maxvalue'} if $potential > $self->{'maxvalue'};
$potential = $self->{'minvalue'} if $potential < $self->{'minvalue'};
$potential = &{$self->{'afunc'}}($potential);
$neurons[$i] = $net->[$i]->{'state'} = $potential;
$net->[$i]->{'done'} = 1;
$progress++;
}
}
} while ($progress); # If the network is feed-forward, we are now finished.
my @notdone = grep {not (defined $net->[$_]->{'done'} &&
$net->[$_]->{'done'} == 1)} 0..$lastneuron;
my @neuronstemp = ();
if ($#notdone > 0) { #This is the part where we deal with loops and bad things
my $maxerror = 0;
my $loopcounter = 1;
while (1) {
foreach my $i (@notdone) { # Only bother iterating over the
# ones we couldn't solve exactly
# We don't care if it's ready now, we're just going to interate
# until it stabilizes.
if (not defined $neurons[$i] && $i <= $lastneuron) {
# Fixes warnings about uninitialized values, but we make
# sure $i is valid first.
$neurons[$i] = 0;
}
my $potential = $net->[$i]->{'object'}->execute($inputs, \@neurons);
$self->{'rawpotentials'}->[$i] = $potential;
$potential = &{$self->{'afunc'}}($potential);
$potential = $self->{'maxvalue'} if $potential > $self->{'maxvalue'};
$potential = $self->{'minvalue'} if $potential < $self->{'minvalue'};
$neuronstemp[$i] = $net->[$i]->{'state'} = $potential;
# We want to know the absolute change
if (abs($neurons[$i]-$neuronstemp[$i])>$maxerror) {
$maxerror = abs($neurons[$i]-$neuronstemp[$i]);
}
}
foreach my $i (0..$lastneuron) {
# Update $neurons, since that is what gets passed to execute
$neurons[$i] = $neuronstemp[$i];
}
if (($maxerror < 0.0001 && $loopcounter >= 5) || $loopcounter > 250) {last}
$loopcounter++;
$maxerror=0;
}
}
# Ok, hopefully all the neurons have happy values by now.
# Get the output values for neurons corresponding to outputneurons
my @output = map {$neurons[$_]} @{$self->{'outputneurons'}};
return \@output;
}
sub get_state {
my $self = shift;
my $net = $self->{'network'}; # For less typing
my @neurons = map {$net->[$_]->{'state'}} 0..$#{$self->{'network'}};
my @output = map {$net->[$_]->{'state'}} @{$self->{'outputneurons'}};
return $self->{'inputs'}, \@neurons, \@output;
}
sub get_internals {
my $self = shift;
my $net = $self->{'network'}; # For less typing
my $retval = [];
for (my $i = 0; $i <= $#{$self->{'network'}}; $i++) {
$retval->[$i] = { iamanoutput => 0,
inputs => $net->[$i]->{'object'}->inputs(),
neurons => $net->[$i]->{'object'}->neurons(),
eta_inputs => $net->[$i]->{'object'}->eta_inputs(),
eta_neurons => $net->[$i]->{'object'}->eta_neurons()
};
}
foreach my $i (@{$self->{'outputneurons'}}) {
$retval->[$i]->{'iamanoutput'} = 1;
}
return dclone($retval); # Dclone for safety.
}
sub readable {
my $self = shift;
my $retval = "This network has ". $self->{'inputcount'} ." inputs and ".
scalar(@{$self->{'network'}}) ." neurons.\n";
for (my $i = 0; $i <= $#{$self->{'network'}}; $i++) {
$retval .= "Neuron $i\n";
while (my ($k, $v) = each %{$self->{'network'}->[$i]->{'object'}->inputs()}) {
$retval .= "\tInput from input $k, weight is $v\n";
}
while (my ($k, $v) = each %{$self->{'network'}->[$i]->{'object'}->neurons()}) {
( run in 2.599 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )