Class Label Filter

Description

The Class Label Filter is a useful post-processing module which can remove erroneous or sporadic prediction spikes that may be made by a classifier on a continuous input stream of data.

For instance, imagine a classifier that correctly outputs the predicted class label of 1 for a large majority of the time that a user is performing gesture 1, but every so often (perhaps due to sensor noise), the classifier outputs the class label of 2. In this instance the class label filter can be used to remove these sporadic prediction values, with the output of the class label filter in this instance being 1 (see the image below which illustrates this example).

The Class Label Filter module is controlled through two parameters: the minimum count value and buffer size value. The minimum count sets the minimum number of class label values that must be present in the class labels buffer for that class label value to be output by the Class Label Filter. The size of the class labels buffer is set by the buffer size parameter. If there is more than one type of class label in the buffer then the class label with the maximum number of instances will be output. If the maximum number of instances for any class label in the buffer is less than the minimum count parameter then the Class Label Filter will output the default null rejection class label of 0. The minimum count and buffer size parameters can be set using the setMinimumCount(UINT minimumCount) and setBufferSize(UINT bufferSize) methods.

The Class Label Filter module is part of the GRT post-processing modules.

Advantages

The Class Label Filter is a useful post-processing module for removing sporadic prediction spikes on a continuous stream of data.

Disadvantages

The main limitation of the Class Label Filter is that is causes a small delay in the classification of a new gesture, as the gesture must be seen N times before it will be recognized, where N is set by the Class Label Filter's minimum count parameter. This disadvantage is not a major limitation if your sensor runs at a high sample rate (i.e. 100Hz) or if the minimum count parameter is small, but this can be an issue if you require a very responsive (i.e. low latency) recognition system.

Example Code

This example demonstrates how to create a new gesture recognition pipeline and add an ANBC module for classification along with a Class Label Filter as a post-processing module. The ANBC classifier is trained with some dummy data (which consists of 3 simple classes generated from 3 different Gaussian distributions). Some test data is then used to demonstrate the result of using the Class Label Filter to post process the predicted class label from the ANBC algorithm. The test data contains a continuous stream of data from class 1, with a few sporadic class 2 and 3 labels added randomly to the stream. The image below illustrates the results of the example. You can download the actual example code and datasets in the Code & Resources section below.

Class Label Filter Results
The results of running the test dataset through the Class Label Filter (with a minimum count of 5 and a buffer size of 10). The processed class label (i.e. the output of the Class Label Filter) can be seen in red with the unprocessed predicted class label (i.e. the output of the ANBC algorithm) shown in green. Note that although the Class Label Filter correctly removes all the sporadic prediction values, there is a small lag in the actual class label being correctly predicted at the start of the test. This is due to the minimum count value, which was set to 5. ClassLabelFilterResultsExampleImage1.jpg
/*
 GRT Class Label Filter Example
 This examples demonstrates how to use the Class Label Filter to filter the predicted class label of any classification module
 using the gesture recognition pipeline.

 The Class Label Filter is a useful post-processing module which can remove erroneous or sporadic prediction spikes that may be
 made by a classifier on a continuous input stream of data.  For instance, imagine a classifier that correctly outputs the predicted
 class label of 1 for a large majority of the time that a user is performing gesture 1, but every so often (perhaps due to sensor noise),
 the classifier outputs the class label of 2.  In this instance the class label filter can be used to remove these sporadic prediction
 values, with the output of the class label filter in this instance being 1.

 In this example we create a new gesture recognition pipeline and add an ANBC module for classification along with a Class Label Filter
 as a post-processing module.  The ANBC classifier is then trained with some dummy data (which consists of 3 simple classes generated
 from 3 different Gaussian distributions).  Some test data is then used to demonstrate the result of using the Class Label Filter to
 post process the predicted class label from the ANBC algorithm.  The test data contains a continuous stream of data from class 1, with
 a few sporadic class 2 and 3 labels added randomly to the stream.

 This example shows you how to:
 - Create an initialize a GestureRecognitionPipeline and add an ANBC module and a ClassLabelFilter module
 - Load some LabelledClassificationData from a file and train the classifier
 - Use some test data to demonstrate the effect of using a Class Label Filter
 - Print the Processed and Unprocessed Predicted Class Label
 - Write these results to a file
*/


//You might need to set the specific path of the GRT header relative to your project
#include "GRT.h"
using namespace GRT;

int main (int argc, const char * argv[])
{
    //Create a new gesture recognition pipeline
    GestureRecognitionPipeline pipeline;

    //Add an ANBC module
    pipeline.setClassifier( ANBC() );

    //Add a ClassLabelFilter as a post processing module with a minCount of 5 and a buffer size of 10
    pipeline.addPostProcessingModule( ClassLabelFilter(5,10) );

    //Load some training data to train and test the classifier
    LabelledClassificationData trainingData;
    LabelledClassificationData testData;

    if( !trainingData.loadDatasetFromFile("ClassLabelFilterTrainingData.txt") ){
        cout << "Failed to load training data!\n";
        return EXIT_FAILURE;
    }

    if( !testData.loadDatasetFromFile("ClassLabelFilterTestData.txt") ){
        cout << "Failed to load training data!\n";
        return EXIT_FAILURE;
    }

    //Train the classifier
    if( !pipeline.train( trainingData ) ){
        cout << "Failed to train classifier!\n";
        return EXIT_FAILURE;
    }

    //Use the test dataset to demonstrate the output of the ClassLabelFilter
    fstream file;
    file.open("ClassLabelFilterResults.txt",fstream::out);

    if( !file.is_open() ){
        cout << "Failed to open file to save results!\n";
        return EXIT_FAILURE;
    }

    for(UINT i=0; i<testData.getNumSamples(); i++){
        vector< double > inputVector = testData[i].getSample();

        if( !pipeline.predict( inputVector ) ){
            cout << "Failed to perform prediction for test sampel: " << i <<"\n";
            return EXIT_FAILURE;
        }

        //Get the predicted class label (this will be the processed class label)
        UINT predictedClassLabel = pipeline.getPredictedClassLabel();

        //Get the unprocessed class label (i.e. the direct output of the classifier)
        UINT unprocessedClassLabel = pipeline.getUnProcessedPredictedClassLabel();

        //Save the results to a file
        file << predictedClassLabel << "\t" << unprocessedClassLabel << endl;

        //Also print the results to the screen
        cout << "Processed Class Label: \t" << predictedClassLabel << "\tUnprocessed Class Label: \t" << unprocessedClassLabel << endl;

    }

    file.close();

    return EXIT_SUCCESS;
}

Code & Resources

ClassLabelFilterExample.cpp ClassLabelFilterTrainingData.txt ClassLabelFilterTestData.txt

Documentation

You can find the documentation for this class at ClassLabelFilter documentation.