/* * Encog(tm) Core v3.4 - Java Version * http://www.heatonresearch.com/encog/ * https://github.com/encog/encog-java-core * Copyright 2008-2016 Heaton Research, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * For more information on Heaton Research copyrights, licenses * and trademarks visit: * http://www.heatonresearch.com/copyright */ package org.encog.neural.som.training.basic; import org.encog.mathutil.BoundMath; import org.encog.mathutil.matrices.Matrix; import org.encog.ml.data.MLData; import org.encog.neural.NeuralNetworkError; import org.encog.neural.som.SOM; /** * The "Best Matching Unit" or BMU is a very important concept in the training * for a SOM. The BMU is the output neuron that has weight connections to the * input neurons that most closely match the current input vector. This neuron * (and its "neighborhood") are the neurons that will receive training. * * This class also tracks the worst distance (of all BMU's). This gives some * indication of how well the network is trained, and thus becomes the "error" * of the entire network. * * @author jeff * */ public class BestMatchingUnit { /** * The owner of this class. */ private final SOM som; /** * What is the worst BMU distance so far, this becomes the error for the * entire SOM. */ private double worstDistance; /** * Construct a BestMatchingUnit class. The training class must be provided. * @param som The SOM to evaluate. */ public BestMatchingUnit(final SOM som) { this.som = som; } /** * Calculate the best matching unit (BMU). This is the output neuron that * has the lowest Euclidean distance to the input vector. * * @param input * The input vector. * @return The output neuron number that is the BMU. */ public int calculateBMU(final MLData input) { int result = 0; if( input.size()>this.som.getInputCount() ) { throw new NeuralNetworkError("Can't train SOM with input size of " + som.getInputCount() + " with input data of count " + input.size()); } // Track the lowest distance so far. double lowestDistance = Double.MAX_VALUE; for (int i = 0; i < this.som.getOutputCount(); i++) { final double distance = calculateEuclideanDistance(this.som.getWeights(), input, i); // Track the lowest distance, this is the BMU. if (distance < lowestDistance) { lowestDistance = distance; result = i; } } // Track the worst distance, this is the error for the entire network. if (lowestDistance > this.worstDistance) { this.worstDistance = lowestDistance; } return result; } /** * Calculate the Euclidean distance for the specified output neuron and the * input vector. This is the square root of the squares of the differences * between the weight and input vectors. * * @param matrix * The matrix to get the weights from. * @param input * The input vector. * @param outputNeuron * The neuron we are calculating the distance for. * @return The Euclidean distance. */ public double calculateEuclideanDistance(final Matrix matrix, final MLData input, final int outputNeuron) { double result = 0; // Loop over all input data. for (int i = 0; i < input.size(); i++) { final double diff = input.getData(i) - matrix.get(outputNeuron, i); result += diff * diff; } return BoundMath.sqrt(result); } /** * @return What is the worst BMU distance so far, this becomes the error * for the entire SOM. */ public double getWorstDistance() { return this.worstDistance; } /** * Reset the "worst distance" back to a minimum value. This should be * called for each training iteration. */ public void reset() { this.worstDistance = Double.MIN_VALUE; } }