package org.neuroph.nnet.learning;

import java.util.ArrayList;
import java.util.List;
import org.neuroph.core.Connection;
import org.neuroph.core.Layer;
import org.neuroph.core.Neuron;
import org.neuroph.core.transfer.Gaussian;
import org.neuroph.nnet.learning.kmeans.Cluster;
import org.neuroph.nnet.learning.kmeans.KMeansClustering;
import org.neuroph.nnet.learning.kmeans.KVector;
import org.neuroph.nnet.learning.knn.KNearestNeighbour;

/**
 * Learning rule for Radial Basis Function networks.
 * Use K-Means to determine centroids for hidden units, K-NearestNeighbour to set widths,
 * and LMS to tweak output neurons.
 * 
 * @author Zoran Sevarac sevarac@gmail.com
 */
public class RBFLearning extends LMS {

    /**
     * how many nearest neighbours to use when determining width (sigma) for
     * gaussian functions
     */
    int k=2;
    
    @Override
    protected void onStart() {
        super.onStart();         
        
        // set weights between input and rbf layer using kmeans
        KMeansClustering kmeans = new KMeansClustering(getTrainingSet());
        kmeans.setNumberOfClusters(neuralNetwork.getLayerAt(1).getNeuronsCount()); // set number of clusters as number of rbf neurons
        kmeans.doClustering();
        
        // get clusters (centroids)
        Cluster[] clusters = kmeans.getClusters();
        
        // assign each rbf neuron to one cluster
        // and use centroid vectors to initialize neuron's input weights
        Layer rbfLayer = neuralNetwork.getLayerAt(1);
        int i=0;
        for(Neuron neuron : rbfLayer.getNeurons()) {
            KVector centroid = clusters[i].getCentroid();
            double[] weightValues = centroid.getValues();
            int c=0;
            for(Connection conn : neuron.getInputConnections()) {
                conn.getWeight().setValue(weightValues[c]);
                c++;
            }
            i++;
        }
        
        // get cluster centroids as list
        List centroids = new ArrayList<>();                
        for(Cluster cluster : clusters) {
            centroids.add(cluster.getCentroid());
        }        

        // use KNN to calculate sigma param - gausssian function width for each neuron
        KNearestNeighbour knn = new KNearestNeighbour();
        knn.setDataSet(centroids);
        
        int n = 0;
        for(KVector centroid : centroids) {
        // calculate and set sigma for each neuron in rbf layer
            KVector[] nearestNeighbours = knn.getKNearestNeighbours(centroid, k);
            double sigma = calculateSigma(centroid, nearestNeighbours); // calculate in method 
            Neuron neuron = rbfLayer.getNeuronAt(n);
            ((Gaussian)neuron.getTransferFunction()).setSigma(sigma);
            i++;
            
        }
        
                
    }
    
    /**
     * Calculates and returns  width of a gaussian function
     * @param centroid
     * @param nearestNeighbours
     * @return 
     */
    private double calculateSigma(KVector centroid,  KVector[] nearestNeighbours) {
       double sigma = 0;
              
       for(KVector nn : nearestNeighbours){
           sigma += Math.pow( centroid.distanceFrom(nn), 2 ) ;
       }
       
       sigma = Math.sqrt(1/((double)nearestNeighbours.length)  * sigma);
       
       return sigma;
    }


    
   
    
}

 

Ads help maintain this website.