Kohonen Map

From Robowiki
Revision as of 16:44, 1 November 2009 by Chase-san (talk | contribs)
Jump to navigation Jump to search

Nat contacted me wanting to know bout Kohonen Maps. To be honest there isn't actually a whole lot to them. I wrote some psudocode for you all to convert into something usable in java. Its been a long time since I wrote java.

This is all from memory, prototype gained score based on the weights and the way I updated the weights and the dimensionality of my map, and probably some other things. I use a 1 dimensional map in this snippet, but you can use as many dimensions as you like, the higher you go the more interlinks the data gets when it preforms its distribution.

Also keep in mind you can also 'wrap' the 'edges' of the map, and you can get better data that way, however make sure to limit the size of your gauss function, otherwise you will be calculating the wrap forever. (I find once the neighborhood functions dips below 0.01 to 0.1 its mostly unneeded to try and update it). Edge wrappings gets exceedingly computationally expensive as you go up in dimensions.

I found around 10,000 to 100,000 total nodes didn't do half bad, and really due to the nature of kohonen maps, you probably do not need to go much higher.

I would love to see someone integrate this into movement. :)

ALSO: Initialize those nodes with random static if possible.

Chase 15:44, 1 November 2009 (UTC)

//KOHONEN MAP, PSUDOCODE FOR YOU AND ME!

//Making an array, 25 line in this case
int gridSize = 25;
array Node grid[gridSize];


//IMPORTANT: As much I would love to see a pattern matcher version of this, its kinda unrealistic
//based on how kohonen maps work.
class Node {
	static int nearest; //1 instance of
	float gf; //Guess Factor
	
	float weight0; //Distance?
	float weight1; //Velocity?
	float weight2; //Angle
	//...
}

//There are much better ways to do this aswell

//I do not include the GF because thats the target
//'dimension' for reduced resolution :)
float distance(Node a, Node b) {
	return abs(a.weight0 - b.weight0) +
		abs(a.weight1 - b.weight1) +
		abs(a.weight2 - b.weight2);
}

Node getNearestNode(Node n) {
	Node near;
	float dist = INFINITY;

	//find nearest Node to the given data
	//Do this however you like
	for(int i=0; i<gridSize; ++i) {
		float newDist = distance(n,grid[i]);
		if(newDist < dist) {
			near = grid[i];
			dist = newDist;
			near.nearest = i;
		}
	}

	//You could also make a short list of 'nearest' nodes
	//and run some kind of other function to determine the
	//best amoung them for updating or for firing
	return near;
}

float recalcWeight(float current, float target, float neighborhood, float time) {
	return current + neighborhood * time * (target - current);
}

void updateMap(Node new, int time) {
	//find nearest Node to our new data
	Node nearest = getNearestNode(new);

	//Save the nearest index for later
	int n = nearest.nearest;
	
	//Now we have two options, we can either set the given node to our
	//new data, or use some kinda of 'weighting' system to 'tune' it

	//I am just going to set it
	//This is psudocode so I can cheat
	nearest = new;

	//now we run a guassian function on 'nearby' nodes to 'pull' their values
	//to be closer to the value of this node. The guassian depends on the other
	//nodes 'distance' from the given node on the grid.

	//Also its a good idea to weight the strength of this pull by the number of elapsed
	//rounds, so it would learn faster early on and only slightly tune the data
	//later. This is a very important concept, otherwise the map is mostly useless.

	//Note that my neighborhood function isn't actually guassian at all, but
	//linear, guassian however works much better. :)
	for(int i = 0; i<gridSize; ++i) {
		int dist = abs(n-i);    
		grid[i].gf = recalcWeight( grid[i].gf, new.gf, (0.75/dist), 1.0/ln(time) );
		//Do this for the other weights aswell...
	}
}

float getBestGF(Node current) {
	return getNearestNode(current).gf;
}

//That is about all there is to it.