AI-NeuralNet-SOM

 view release on metacpan or  search on metacpan

lib/AI/NeuralNet/SOM.pm  view on Meta::CPAN

sub new { die; }

=pod

=head2 Methods

=over

=item I<initialize>

I<$nn>->initialize

You need to initialize all vectors in the map before training. There are several options
how this is done:

=over

=item providing data vectors

If you provide a list of vectors, these will be used in turn to seed the neurons. If the list is
shorter than the number of neurons, the list will be started over. That way it is trivial to
zero everything:

  $nn->initialize ( [ 0, 0, 0 ] );

=item providing no data

Then all vectors will get randomized values (in the range [ -0.5 .. 0.5 ]).

=item using eigenvectors (see L</HOWTOS>)

=back

=item I<train>

I<$nn>->train ( I<$epochs>, I<@vectors> )

I<@mes> = I<$nn>->train ( I<$epochs>, I<@vectors> )

The training uses the list of sample vectors to make the network learn. Each vector is simply a
reference to an array of values.

The C<epoch> parameter controls how many vectors are processed. The vectors are B<NOT> used in
sequence, but picked randomly from the list. For this reason it is wise to run several epochs,
not just one. But within one epoch B<all> vectors are visited exactly once.

Example:

   $nn->train (30, 
               [ 3, 2, 4 ],
               [ -1, -1, -1 ], 
               [ 0, 4, -3]);

=cut

sub train {
    my $self   = shift;
    my $epochs = shift || 1;
    die "no data to learn" unless @_;

    $self->{LAMBDA} = $epochs / log ($self->{_Sigma0});                                 # educated guess?

    my @mes    = ();                                                                    # this will contain the errors during the epochs
    for my $epoch (1..$epochs)  {
	$self->{T} = $epoch;
	my $sigma = $self->{_Sigma0} * exp ( - $self->{T} / $self->{LAMBDA} );          # compute current radius
	my $l     = $self->{_L0}     * exp ( - $self->{T} / $epochs );                  # current learning rate

	my @veggies = @_;                                                               # make a local copy, that will be destroyed in the loop
	while (@veggies) {
	    my $sample = splice @veggies, int (rand (scalar @veggies) ), 1;             # find (and take out)

	    my @bmu = $self->bmu ($sample);                                             # find the best matching unit
	    push @mes, $bmu[2] if wantarray;
	    my $neighbors = $self->neighbors ($sigma, @bmu);                            # find its neighbors
	    map { _adjust ($self, $l, $sigma, $_, $sample) } @$neighbors;               # bend them like Beckham
	}
    }
    return @mes;
}

sub _adjust {                                                                           # http://www.ai-junkie.com/ann/som/som4.html
    my $self  = shift;
    my $l     = shift;                                                                  # the learning rate
    my $sigma = shift;                                                                  # the current radius
    my $unit  = shift;                                                                  # which unit to change
    my ($x, $y, $d) = @$unit;                                                           # it contains the distance
    my $v     = shift;                                                                  # the vector which makes the impact

    my $w     = $self->{map}->[$x]->[$y];                                               # find the data behind the unit
    my $theta = exp ( - ($d ** 2) / (2 * $sigma ** 2));                                 # gaussian impact (using distance and current radius)

    foreach my $i (0 .. $#$w) {                                                         # adjusting values
	$w->[$i] = $w->[$i] + $theta * $l * ( $v->[$i] - $w->[$i] );
    }
}

=pod

=item I<bmu>

(I<$x>, I<$y>, I<$distance>) = I<$nn>->bmu (I<$vector>)

This method finds the I<best matching unit>, i.e. that neuron which is closest to the vector passed
in. The method returns the coordinates and the actual distance.

=cut

sub bmu { die; }

=pod

=item I<mean_error>

I<$me> = I<$nn>->mean_error (I<@vectors>)

This method takes a number of vectors and produces the I<mean distance>, i.e. the average I<error>
which the SOM makes when finding the C<bmu>s for the vectors. At least one vector must be passed in.

Obviously, the longer you let your SOM be trained, the smaller the error should become.



( run in 2.170 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )