Kohonenová neurónová sieť
Neurónová sieť, ktorá slúži na nájdenie zhlukov vo vstupnom obrázku (špirále).
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.
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);
}