public SOM(AppSettings appSettings ) { _appSettings = appSettings; _netState = NET_STATE.init; _trainingPhase = TRAINING_PHASE.phase_1; _currentIteration = 1; _totalMapError = 0.0f; _isNeuronSelected = false; _selectedNeuronCoords = new Point( 0, 0 ); _isTrained = false; _timeConstant_P1 = (float)_appSettings.numIterations_P1 / (float)Math.Log( _appSettings.mapRadius ); _learningRate_P1 = _appSettings.startLearningRate_P1; _learningRate_P2 = _appSettings.startLearningRate_P2; // Allocate memory. _competitionLayer = new Neuron[ SOMConstants.NUM_NODES_DOWN, SOMConstants.NUM_NODES_ACROSS ]; for ( int i = 0; i < SOMConstants.NUM_NODES_DOWN; ++i ) { for ( int j = 0; j < SOMConstants.NUM_NODES_ACROSS; ++j ) { _competitionLayer[ i,j ] = new Neuron( i, j ); } } _errorMap = new float[ SOMConstants.NUM_NODES_DOWN, SOMConstants.NUM_NODES_ACROSS, 3 ]; Run(); }
private bool Epoch() { if (_trainingPhase == TRAINING_PHASE.phase_1 && _currentIteration > _appSettings.numIterations_P1) { _trainingPhase = TRAINING_PHASE.phase_2; _currentIteration = 1; } else if (_trainingPhase == TRAINING_PHASE.phase_2 && _currentIteration > _appSettings.numIterations_P2) { return true; } /************************************************************************/ /* STEP 2: Choose a random input vector from the set of training data. /************************************************************************/ int randomNum = SOMHelper.Random_Int(_appSettings.images.Count); ImageData thisImage = (ImageData)_appSettings.images[randomNum]; thisImage.numGotPickup++; InputVector inVec = thisImage.inputVector; /************************************************************************/ /* STEP 3: Find the BMU. /************************************************************************/ Neuron bmu = FindBMU(inVec); // Update this image's most recent BMU for later identification. thisImage.m_BMU.X = bmu.X; thisImage.m_BMU.Y = bmu.Y; /************************************************************************/ /* STEP 4: Calculate the radius of the BMU's neighborhood. /************************************************************************/ if (_trainingPhase == TRAINING_PHASE.phase_1) _neighborhoodRadius = _appSettings.mapRadius * (float)Math.Exp(-(float)_currentIteration / _timeConstant_P1); else if (_trainingPhase == TRAINING_PHASE.phase_2) _neighborhoodRadius = 1.0f; /************************************************************************/ /* STEP 5: Each neighboring node's weights are adjusted to make them more * like the input vector. /************************************************************************/ for (int i = 0; i < SOMConstants.NUM_NODES_DOWN; ++i) { for (int j = 0; j < SOMConstants.NUM_NODES_ACROSS; ++j) { float distToNodeSquared = 0.0f; // Get the Euclidean distance (squared) to this node[i,j] from the BMU. Use // this formula to account for base 0 arrays, and the fact that our neighborhood // radius is actually HALF of the DRAWING WINDOW. float bmuX = (float)(bmu.X + 1) * _appSettings.nodeHeight; float bmuY = (float)(bmu.Y + 1) * _appSettings.nodeWidth; float nodeX = (float)(_competitionLayer[i, j].Y + 1) * _appSettings.nodeHeight; float nodeY = (float)(_competitionLayer[i, j].Y + 1) * _appSettings.nodeWidth; distToNodeSquared = (bmuX - nodeX) * (bmuX - nodeX) + (bmuY - nodeY) * (bmuY - nodeY); float widthSquared = _neighborhoodRadius * _neighborhoodRadius; // If within the neighborhood radius, adjust this nodes' weights. if (distToNodeSquared < widthSquared) { // Calculate how much it's weights are adjusted. float influence = (float)Math.Exp(-distToNodeSquared / (2.0f * widthSquared)); if (_trainingPhase == TRAINING_PHASE.phase_1) _competitionLayer[i, j].AdjustWeights(inVec, _learningRate_P1, influence); else if (_trainingPhase == TRAINING_PHASE.phase_2) _competitionLayer[i, j].AdjustWeights(inVec, _learningRate_P2, influence); } } // End for each column. } // End for each row. // Reduce the learning rate. if (_trainingPhase == TRAINING_PHASE.phase_1) { _learningRate_P1 = _appSettings.startLearningRate_P1 * (float)Math.Exp(-(float)_currentIteration / (float)_appSettings.numIterations_P1); } else if (_trainingPhase == TRAINING_PHASE.phase_2) { _learningRate_P2 = _appSettings.startLearningRate_P2 * (float)Math.Exp(-(float)_currentIteration / (float)_appSettings.numIterations_P2); } ++_currentIteration; return false; }