/**
 * Copyright 2010 Neuroph Project http://neuroph.sourceforge.net
 *
 * 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.
 */
package org.neuroph.nnet.learning;

import java.io.Serializable;
import java.util.List;
import org.neuroph.core.Connection;
import org.neuroph.core.Neuron;
import org.neuroph.core.Weight;
import org.neuroph.core.learning.SupervisedLearning;

/**
 * LMS learning rule for neural networks. This learning rule is used to train
 * Adaline neural network, and this class is base for all LMS based learning
 * rules like PerceptronLearning, DeltaRule, SigmoidDeltaRule, Backpropagation
 * etc.
 *
 * @author Zoran Sevarac 
 */
public class LMS extends SupervisedLearning implements Serializable {

    /**
     * The class fingerprint that is set to indicate serialization
     * compatibility with a previous version of the class.
     */
    private static final long serialVersionUID = 2L;


    /**
     * Creates a new LMS learning rule
     */
    public LMS() {

    }


    /**
     * This method implements the weights update procedure for the whole network
     * for the given output error vector.
     *   
     * @param outputError
     *            output error vector for some network input- the difference between desired and actual output
     * @see SupervisedLearning#learnPattern(org.neuroph.core.data.DataSetRow)  learnPattern
     */
    @Override
    protected void calculateWeightChanges(final double[] outputError) {
        int i = 0;
        // for each neuron in output layer
        List outputNeurons = neuralNetwork.getOutputNeurons();
        for (Neuron neuron : outputNeurons) {
            neuron.setDelta(outputError[i]); // set the neuron error, as difference between desired and actual output 
            calculateWeightChanges(neuron);     // and update neuron weights -- this should be renamed to calculate weight changes
            i++;
        }
        
        // outputNeurons.forEach( neuron -> updateNeuronWeights(neuron));
        
    }

    /**
     * This method calculates weights changes for the single neuron.
     * It iterates through all neuron's input connections, and calculates/set weight change for each weight
     * using formula 
     *      deltaWeight = -learningRate * delta * input
     * 
     * where delta is a neuron error, a difference between desired/target and actual output for specific neuron
     *      neuronError = desiredOutput[i] - actualOutput[i] (see method SuprevisedLearning.calculateOutputError)
     * 
     * @param neuron
     *            neuron to update weights
     * 
     * @see LMS#calculateWeightChanges(double[]) 
     */
    protected void calculateWeightChanges(Neuron neuron) {
        // get the error(delta) for specified neuron,
        double delta = neuron.getDelta();

        // tanh can be used to minimise the impact of big error values, which can cause network instability
        // suggested at https://sourceforge.net/tracker/?func=detail&atid=1107579&aid=3130561&group_id=238532
        // double neuronError = Math.tanh(neuron.getError());
        
        // iterate through all neuron's input connections
        for (Connection connection : neuron.getInputConnections()) {
            // get the input from current connection
            final double input = connection.getInput();
            // calculate the weight change
            final double weightChange = -learningRate * delta * input;

            // get the connection weight
            final Weight weight = connection.getWeight();
            // if the learning is in online mode (not batch) apply the weight change immediately
            if (!this.isBatchMode()) {
                weight.weightChange = weightChange;                
            } else { // otherwise if its in batch mode, accumulate  weight changes and apply them after the current epoch (see SupervisedLearning.doLearningEpoch method)
                weight.weightChange += weightChange;
            }
        }
    }

}
 

Ads help maintain this website.