AI-Perceptron
view release on metacpan or search on metacpan
examples/and.pl view on Meta::CPAN
print "\nBefore Training\n";
dump_perceptron( $p );
print "\nTraining...\n";
$p->train( @training_exs );
print "\nAfter Training\n";
dump_perceptron( $p );
sub dump_perceptron {
my $p = shift;
print "\tThreshold: ", $p->threshold, " Weights: ", join(', ', @{ $p->weights }), "\n";
foreach my $inputs (@training_exs) {
my $target = $inputs->[0];
print "\tInputs = {", join(',', @$inputs[1..2]), "}, target=$target, output=", $p->compute_output( @$inputs[1..2] ), "\n";
}
}
lib/AI/Perceptron.pm view on Meta::CPAN
package AI::Perceptron;
use strict;
use accessors qw( num_inputs learning_rate _weights threshold
training_examples max_iterations );
our $VERSION = '1.0';
our $Debug = 0;
sub new {
my $class = shift;
my $self = bless {}, $class;
return $self->init( @_ );
}
sub init {
my $self = shift;
my %args = @_;
$self->num_inputs( $args{Inputs} || 1 )
->learning_rate( $args{N} || 0.05 )
->max_iterations( -1 )
->threshold( $args{T} || 0.0 )
->training_examples( [] )
->weights( [] );
# DEPRECATED: backwards compat
if ($args{W}) {
$self->threshold( shift @{ $args{W} } )
->weights( [ @{ $args{W} } ] );
}
return $self;
}
sub verify_weights {
my $self = shift;
for my $i (0 .. $self->num_inputs-1) {
$self->weights->[$i] ||= 0.0;
}
return $self;
}
# DEPRECATED: backwards compat
sub weights {
my $self = shift;
my $ret = $self->_weights(@_);
return wantarray ? ( $self->threshold, @{ $self->_weights } ) : $ret;
}
sub add_examples {
my $self = shift;
foreach my $ex (@_) {
die "training examples must be arrayrefs!" unless (ref $ex eq 'ARRAY');
my @inputs = @{$ex}; # be nice, take a copy
my $target = shift @inputs;
die "expected result must be either -1 or 1, not $target!"
unless (abs $target == 1);
# TODO: avoid duplicate entries
push @{ $self->training_examples }, [$target, @inputs];
}
return $self;
}
sub add_example {
shift->add_examples(@_);
}
sub compute_output {
my $self = shift;
my @inputs = @_;
my $sum = $self->threshold; # start at threshold
for my $i (0 .. $self->num_inputs-1) {
$sum += $self->weights->[$i] * $inputs[$i];
}
# binary (returning the real $sum is not part of this model)
return ($sum > 0) ? 1 : -1;
}
##
# $p->train( [ @training_examples ] )
# \--> [ $target_output, @inputs ]
sub train {
my $self = shift;
$self->add_examples( @_ ) if @_;
$self->verify_weights;
# adjust the weights for each training example until the output
# function correctly classifies all the training examples.
my $iter = 0;
while(! $self->classifies_examples_correctly ) {
lib/AI/Perceptron.pm view on Meta::CPAN
->adjust_weights( \@inputs, $expected_output, $output );
}
}
$self->emit( "completed in $iter iterations." );
return $self;
}
# return true unless all training examples are correctly classified
sub classifies_examples_correctly {
my $self = shift;
my $training_examples = $self->training_examples;
foreach my $training_example (@$training_examples) {
my ($output, @inputs) = @{$training_example};
return if ($self->compute_output( @inputs ) != $output);
}
return 1;
}
sub adjust_threshold {
my $self = shift;
my $expected_output = shift;
my $output = shift;
my $n = $self->learning_rate;
my $delta = $n * ($expected_output - $output);
$self->threshold( $self->threshold + $delta );
return $self;
}
sub adjust_weights {
my $self = shift;
my $inputs = shift;
my $expected_output = shift;
my $output = shift;
my $n = $self->learning_rate;
for my $i (0 .. $self->num_inputs-1) {
my $delta = $n * ($expected_output - $output) * $inputs->[$i];
$self->weights->[$i] += $delta;
}
return $self;
}
sub emit {
return unless $Debug;
my $self = shift;
push @_, "\n" unless grep /\n/, @_;
warn( @_ );
}
1;
__END__
( run in 0.241 second using v1.01-cache-2.11-cpan-a5abf4f5562 )