kohonen-net
Version:
simple implementation of a self organizing map
72 lines (51 loc) • 2.13 kB
JavaScript
var num = require('numeric');
var utils = require('./utils.js');
function SelfOrganizingMap(nFeatures, outputLayer, distanceFn, wraparound, learningRate){
this.nFeatures = nFeatures;
this.outputLayer = outputLayer;
this.learningRate_t0 = learningRate;
this.nOutputnodes = outputLayer.reduce((s, p) => s*p, 1);
this.neighbourhoodMatrix = utils.neighbourMatrix(outputLayer, distanceFn, wraparound);
this.neighbourhoodMean = this.neighbourhoodMatrix.map(v => {return num.sum(v)/v.length});
this.neighbourhoodMatrixNeg = num.neg(num.pow(this.neighbourhoodMatrix, 2));
this.weights = utils.random_tensor([this.nOutputnodes, nFeatures]);
this.t = 0;
this.lrDecay = Math.pow(2, 20);
this.neighbourDecay = Math.pow(2, 14);
this.neighbourhoodCutoff = 5;
this.trainStep = function(feature){
let fwDiff = this.computeFeatureWeightDifference(feature);
let discriminantV = this.computeDiscriminantVector(fwDiff);
let winner = utils.argMin(discriminantV);
let nf = this.neighbourhoodFactor(winner);
let lr = this.learningRate();
let deltaW = fwDiff.map((val, i) => val.map(val=> val*nf[i]*lr));
num.addeq(this.weights, deltaW);
this.t++;
}
this.computeFeatureWeightDifference = function(features){
return this.weights.map(v => num.sub(features, v));
}
this.computeDiscriminantVector = function(fwDiff){
return num.abs(fwDiff).map(v=>num.sum(v));
}
this.learningRate = function(winner){
return this.learningRate_t0 * Math.exp(-this.t/this.lrDecay);
}
this.neighbourhoodFactor = function(winner){
let sigma = this.neighbourhoodMean[winner] * Math.exp(-this.t/this.neighbourDecay);
ret = num.exp(num.div(this.neighbourhoodMatrixNeg[winner], sigma));
//console.log(ret);
return ret;
}
}
data = [[1, 1], [1, 100], [100, 1], [100, 100]];
let som = new SelfOrganizingMap(2, [16], utils.manhattanDistance, true, 0.2);
for (let i=0;i<1000;i++){
for (let j=0;j<data.length;j++){
som.trainStep(data[j]);
}
}
console.log(som.weights);
module.exports.SelfOrganizingMap = SelfOrganizingMap;
module.exports.utils = utils;