Class: Ai4r::Som::Som

Inherits:
Object
  • Object
show all
Includes:
Data::Parameterizable
Defined in:
lib/ai4r/som/som.rb

Overview

Introduction

This is an implementation of a Kohonen Self-Organizing Maps

Features

  • Support for any network architecture (number of layers and neurons)

  • Configurable propagation function

  • Optional usage of bias

  • Configurable momentum

  • Configurable learning rate

  • Configurable initial weight function

  • 100% ruby code, no external dependency

Parameters

  • dim => dimension of the input vector

  • number_of_nodes => is the number of nodes per row/column (square som).

  • layer => instante of a layer-algorithm class

About the project

Author

Thomas Kern

License

MPL 1.1

Url

ai4r.org

Instance Method Summary collapse

Methods included from Data::Parameterizable

#get_parameters, included, #set_parameters

Constructor Details

#initialize(dim, number_of_nodes, layer) ⇒ Som

Returns a new instance of Som


61
62
63
64
65
66
67
68
# File 'lib/ai4r/som/som.rb', line 61

def initialize(dim, number_of_nodes, layer)
  @layer = layer
  @dimension = dim
  @number_of_nodes = number_of_nodes
  @nodes = Array.new(number_of_nodes * number_of_nodes)
  @epoch = 0
  @cache = {}
end

Instance Method Details

#adjust_nodes(input, bmu, radius, learning_rate) ⇒ Object

adjusts all nodes within a certain radius to the bmu


87
88
89
90
91
92
93
94
95
96
97
# File 'lib/ai4r/som/som.rb', line 87

def adjust_nodes(input, bmu, radius, learning_rate)
  @nodes.each do |node|
    dist = node.distance_to_node(bmu[0])
    next unless dist < radius

    influence = @layer.influence_decay dist, radius
    node.weights.each_with_index do |weight, index|
      node.weights[index] +=  influence * learning_rate * (input[index] - weight)
    end
  end
end

#find_bmu(input) ⇒ Object

finds the best matching unit (bmu) of a certain input in all the @nodes returns an array of length 2 => [node, distance] (distance is of eucledian type, not a neighborhood distance)


73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/ai4r/som/som.rb', line 73

def find_bmu(input)
  bmu = @nodes.first
  dist = bmu.distance_to_input input
  @nodes[1..-1].each do |node|
    tmp_dist = node.distance_to_input(input)
    if tmp_dist <= dist
      dist = tmp_dist
      bmu = node
    end
  end
  [bmu, dist]
end

#get_node(x, y) ⇒ Object

returns the node at position (x,y) in the square map

Raises:

  • (Exception)

131
132
133
134
# File 'lib/ai4r/som/som.rb', line 131

def get_node(x, y)
  raise(Exception.new) if check_param_for_som(x,y)
  @nodes[y + x * @number_of_nodes]
end

#global_error(data) ⇒ Object

calculates the global distance error for all data entries


107
108
109
# File 'lib/ai4r/som/som.rb', line 107

def global_error(data)
 data.inject(0) {|sum,entry| sum + find_bmu(entry)[1]**2 }
end

#initiate_mapObject

intitiates the map by creating (@number_of_nodes * @number_of_nodes) nodes


137
138
139
140
141
# File 'lib/ai4r/som/som.rb', line 137

def initiate_map
  @nodes.each_with_index do |node, i|
    @nodes[i] = Node.create i, @number_of_nodes, @dimension
  end
end

#train(data) ⇒ Object

main method for the som. trains the map with the passed data vector calls train_step as long as train_step returns false


101
102
103
104
# File 'lib/ai4r/som/som.rb', line 101

def train(data)
  while !train_step(data)
  end
end

#train_step(data) ⇒ Object

trains the map with the data as long as the @epoch is smaller than the epoch-value of returns true if @epoch is greater than the fixed epoch-value in @layer, otherwise false 1 is added to @epoch at each method call the radius and learning rate is decreased at each method call/epoch as well


116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/ai4r/som/som.rb', line 116

def train_step(data)
  return true if @epoch >= @layer.epochs

  radius = @layer.radius_decay @epoch
  learning_rate = @layer.learning_rate_decay @epoch

  data.each do |entry|
    adjust_nodes entry, find_bmu(entry), radius, learning_rate
  end

  @epoch += 1
  false
end