Návod na spustenie

Do programu je potrebné vložiť obrázok vo formáte BMP (napr. špirála), na ktorom sa bude neuronová sieť učiť.

V programe je možné nastaviť veľkosť Kohonenovej vrstvy, čo je počet neurónov na tejto vrstve. Veľkosť trénovacej množiny predstavuje počet náhodne vybraných bodov, ktoré patria do obrázka (v našom prípade do špirály). Ostatné parametre súvisia prijamo s učením a nastavujú sa experimentálne.

Po kliknutí na tlačidlo "Štart" sa neurónová sieť začne učiť. To môže trvať niekoľko minút, v závislosti od rýchlosti vášho počítača. Po skončení učenia sa výsledok zobrazí na stránke. Modré body reprezentujú trénovacie množinu. Červené body sú hodnoty váh neurónov na Kohonenovej vrstve, ktoré reprezentujú centrá zhlukov.

Váš prehliadač nepodporuje element canvas. Váš prehliadač nepodporuje element canvas.

Kohonená vrstva

x

Trénovacia množina

Obrázok v BMP formáte

BMP obrázok špirály: obrázok


Učenie

Funkcie susednosti
Výsledná funkcia susednosti

Program

Program je skrátený a znázornuje len učiacu funkciu.


// all data
var train_data;

// training data
var train_set;

function main()
{
	x_size = parseInt(x_size_input.value);
	y_size = parseInt(y_size_input.value);

	var init_type = 0;
	for(var i=0, len=init_type_inputs.length; i<len; i++)
	{
		if(init_type_inputs[i].checked)
			init_type = init_type_inputs[i].value;
	}

	// clear canvas
	context.clearRect(0, 0, canvas.width, canvas.height);

	// inicialize weights
	if(weights === undefined)
		inicialize();

	// get training set
	if(train_set === undefined)
		train_set = get_train_set(train_size.value);

	draw_train_set();

	redrawNFCanvas();

	// learn NN
	learn(num_cycles.value, learning_rate.value, h_function.value, r_function.value, x_size, y_size);

	draw_neurons();
}

// weights
var weights;

// size of kohonen layer
var x_size = 0;
var y_size = 0;

function inicialize()
{
	var init_type = 0;
	for(var i=0, len=init_type_inputs.length; i<len; i++)
	{
		if(init_type_inputs[i].checked)
			init_type = init_type_inputs[i].value;
	}

	weights = [];
	var num_neurons = x_size * y_size;
	var random = (parseInt(init_type) !== 0);

	if(!random)
	{
		// weights to grid
		var x_step = Math.floor(460 / (x_size - 1));
		var y_step = Math.floor(460 / (y_size - 1));
		var x = 20;
		var y = 20;
		var max_x = (x_size - 1) * x_step + 20;
	}

	for(var i=0; i < num_neurons; i++)
	{
		weights[i] = [];

		if(random)
		{
			// random weights
			weights[i]['x'] = normalize(Math.round(Math.random() * 460 + 20));
			weights[i]['y'] = normalize(Math.round(Math.random() * 460 + 20));
		}
		else
		{
			// weights to grid
			if(x > max_x)
			{
				x = 20;
				y += y_step;
			}

			weights[i]['x'] = normalize(x);
			weights[i]['y'] = normalize(y);

			x += x_step;
		}
	}
}

function get_train_set(train_size)
{
	var ret = new Array();
	var train_data_length = train_data.length;

	for(var i=0; i<train_size; i++)
	{
		var index = Math.round(Math.random()*train_data_length);

		if(train_data[index]['o'] == 1)
			ret.push(train_data[index]);
	}

	return ret;
}

// normalize value to rande from -1 to 1
function normalize(value)
{
	return (value - 250) / 250;
}

// back to pixels
function to_pixels(value)
{
	return (value * 250) + 250;
}

function learn(num_cycles, gamma, h, r, x_size, y_size)
{
	var train_set_length = train_set.length;
	var weights_length = weights.length;
	var gamma_step = gamma/num_cycles;
	var h_step = h/num_cycles;
	var r_step = r/num_cycles;

	for(var i=0; i<num_cycles; i++)
	{
		for(var j=0; j<train_set_length; j++)
		{
			var x = train_set[j]['x'];
			var y = train_set[j]['y'];

			// compute output for each neuron
			for(var k=0; k<weights_length; k++)
			{
				weights[k]['o'] = Math.sqrt(Math.pow((x  + 1) - (weights[k]['x'] + 1), 2) + Math.pow((y + 1) - (weights[k]['y'] + 1), 2));
			}

			// find winner
			var min = 9999;
			var win_id = 0;
			for(var k=0; k<weights_length; k++)
			{
				if(weights[k]['o'] < min)
				{
					win_id = k;
					min = weights[k]['o'];
				}
			}

			var grid_x = win_id % x_size;
			var grid_y = Math.floor(win_id / x_size);

			// change weights
			for(var k=0; k<weights_length; k++)
			{
				var x_dist = Math.abs(grid_x - (k % x_size));
				var y_dist = Math.abs(grid_y - Math.floor(k / x_size));
				var dist = Math.sqrt(Math.pow(x_dist, 2) + Math.pow(y_dist, 2));

				var sigma = get_NF(dist, h, r);

				weights[k]['x'] += gamma * sigma * (x - weights[k]['x']);
				weights[k]['y'] += gamma * sigma * (y - weights[k]['y']);
			}
		}

		// make parameters smaller
		gamma -= gamma_step;
		h -= h_step;
		r -= r_step;
	}
}

// calculate neighborhood function
function get_NF(x, h, r)
{
	return h*Math.exp(-Math.pow(x, 2)/r);
}