} //buildModel protected void InitializeSOMWeights(ModelSelfOrganizingMap model, long noOfWeights) { Parallel.For(0, _xdim, new ParallelOptions { MaxDegreeOfParallelism = _maxParallelThreads }, xdim => { Random rnd = new Random(); model.SomMap[xdim] = new SingleSOMNode[_ydim]; //computedDistValues[xdim] = new double[_ydim]; for (int ydim = 0; ydim < _ydim; ydim++) { model.SomMap[xdim][ydim] = new SingleSOMNode(noOfWeights, xdim, ydim); model.SomMap[xdim][ydim].InitWeights(rnd, _weightBaseValue); } }); }
BuildModel(double[][] trainingData, string[] attributeHeaders, int indexTargetAttribute = -1) { if (indexTargetAttribute == -1) { indexTargetAttribute = attributeHeaders.Length - 1; } //Verify data and set variables VerifyData(trainingData, attributeHeaders, indexTargetAttribute); ModelSelfOrganizingMap model = new ModelSelfOrganizingMap(_missingValue, indexTargetAttribute, trainingData.Length); model.SomMap = new SingleSOMNode[_xdim][]; long noOfWeights = trainingData.Length; //Equal to number of features //Choose as lower of dimension as distance diamter long distanceDiameter = (_xdim < _ydim) ? _xdim : _ydim; double origRadius; if (_origRadius == double.MaxValue) //Not set by user { origRadius = distanceDiameter / 2.0; //Radius of influence //Make it circluar so that Maps in immediate grid can be accomodated //origRadius = sqrt(x*x+y*y), x=y=oriRadiud origRadius = origRadius * Math.Sqrt(2.0); } else { origRadius = _origRadius; } double[][] computedDistValues = new double[_xdim][]; //Initialize SOM Weights InitializeSOMWeights(model, noOfWeights); double learningRate = _learningRate; double radius = origRadius; double timeConstant = (double)_maxEpoch / Math.Log(origRadius); //Start Convergence Loops for (int epoch = 0; epoch < _maxEpoch; epoch++) //Do not parallelize { for (int dataRow = 0; dataRow < trainingData[0].Length; dataRow++) { double[] lowestDistance = new double[_xdim]; long[] lowestDistanceY = new long[_xdim]; double[] inputDataRow = GetLinearArray(_trainingData, dataRow, _trainingData.Length - 1); //Find Best Matching Unit (BMU) for training row //Find lowest distance in xdim Parallel.For(0, _xdim, new ParallelOptions { MaxDegreeOfParallelism = _maxParallelThreads }, xdim => //for (long xdim = 0; xdim < _xdim; xdim++) //Parallelize this loop { double computedDistValue = double.MaxValue; lowestDistance[xdim] = double.MaxValue; for (long ydim = 0; ydim < _ydim; ydim++) { //computedDistValues[xdim][ydim] = computedDistValue = model.SomMap[xdim][ydim].GetComputedDistance(inputDataRow); if (computedDistValue < lowestDistance[xdim]) { lowestDistance[xdim] = computedDistValue; lowestDistanceY[xdim] = ydim; } }//ydim });//xdim long bmuX = 0, bmuY = 0; double finalDistanceValue = double.MaxValue; for (int xdim = 0; xdim < _xdim; xdim++) //Parallelize this loop { if (lowestDistance[xdim] < finalDistanceValue) { bmuX = xdim; bmuY = lowestDistanceY[xdim]; finalDistanceValue = lowestDistance[xdim]; } } //Update Weights in neighborhood accounting for distance from BMU for (long xdim = 0; xdim < _xdim; xdim++) //Parallelize this loop { for (long ydim = 0; ydim < _ydim; ydim++) { model.SomMap[xdim][ydim].UpdateWeights(model.SomMap[bmuX][bmuY], inputDataRow, radius, learningRate, _useDistanceInfluence == 1?true:false); } } } //row //Update learning rate and distance //Formula from: http://www.ai-junkie.com/ann/som/som3.html radius = origRadius * Math.Exp(-(double)epoch / timeConstant); // Math.Pow(origRadius,((double)epoch/(double)_maxEpoch)); //; learningRate = _learningRate * Math.Exp(-(double)epoch / timeConstant); } return(model); } //buildModel