26 RegisterClassifierModule< FiniteStateMachine > FiniteStateMachine::registerModule(
"FiniteStateMachine");
30 this->numParticles = numParticles;
31 this->numClustersPerState = numClustersPerState;
32 this->stateTransitionSmoothingCoeff = stateTransitionSmoothingCoeff;
33 this->measurementNoise = measurementNoise;
34 classType =
"FiniteStateMachine";
35 classifierType = classType;
36 classifierMode = TIMESERIES_CLASSIFIER_MODE;
37 debugLog.setProceedingText(
"[DEBUG FiniteStateMachine]");
38 errorLog.setProceedingText(
"[ERROR FiniteStateMachine]");
39 trainingLog.setProceedingText(
"[TRAINING FiniteStateMachine]");
40 warningLog.setProceedingText(
"[WARNING FiniteStateMachine]");
49 classType =
"FiniteStateMachine";
50 classifierType = classType;
51 classifierMode = STANDARD_CLASSIFIER_MODE;
52 debugLog.setProceedingText(
"[DEBUG FiniteStateMachine]");
53 errorLog.setProceedingText(
"[ERROR FiniteStateMachine]");
54 trainingLog.setProceedingText(
"[TRAINING FiniteStateMachine]");
55 warningLog.setProceedingText(
"[WARNING FiniteStateMachine]");
72 this->numParticles = rhs.numParticles;
73 this->numClustersPerState = rhs.numClustersPerState;
74 this->stateTransitionSmoothingCoeff = rhs.stateTransitionSmoothingCoeff;
75 this->measurementNoise = rhs.measurementNoise;
76 this->particles = rhs.particles;
77 this->stateTransitions = rhs.stateTransitions;
78 this->stateEmissions = rhs.stateEmissions;
81 this->initParticles();
89 if( classifier == NULL )
return false;
99 errorLog <<
"deepCopyFrom(const Classifier *classifier) - Failed to deep copy classifier base class!" << endl;
103 this->numParticles = ptr->numParticles;
104 this->numClustersPerState = ptr->numClustersPerState;
105 this->stateTransitionSmoothingCoeff = ptr->stateTransitionSmoothingCoeff;
106 this->measurementNoise = ptr->measurementNoise;
107 this->particles = ptr->particles;
108 this->stateTransitions = ptr->stateTransitions;
109 this->stateEmissions = ptr->stateEmissions;
112 this->initParticles();
126 errorLog <<
"train_(ClassificationData &trainingData) - Training data has zero samples!" << endl;
135 for(
unsigned int i=0; i<M; i++){
136 timeseries.
addSample(trainingData[i].getClassLabel(), trainingData[i].getSample());
140 if( !
train_( timeseries ) ){
142 errorLog <<
"train_(ClassificationData &trainingData) - Failed to train particle filter!" << endl;
155 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Training data has zero samples!" << endl;
164 for(
unsigned int i=0; i<M; i++){
165 for(
unsigned int j=0; j<trainingData[i].getLength(); j++){
166 timeseries.
addSample(trainingData[i].getClassLabel(), trainingData[i].getData().getRowVector(j));
171 if( !
train_( timeseries ) ){
173 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Failed to train particle filter!" << endl;
193 numInputDimensions = N;
203 stateTransitions.
resize(K, K);
211 UINT currentStateIndex = 0;
214 stateTransitions[ lastStateIndex ][ currentStateIndex ]++;
215 lastStateIndex = currentStateIndex;
220 for(UINT i=0; i<K; i++){
222 for(UINT j=0; j<K; j++){
223 sum += stateTransitions[i][j] + stateTransitionSmoothingCoeff;
225 for(UINT j=0; j<K; j++){
226 stateTransitions[i][j] /= sum;
231 for(UINT k=0; k<K; k++){
235 for(UINT i=0; i<M; i++){
236 if( data[i].getClassLabel() == classLabels[k] ){
237 classData.
push_back( data[i].getSample() );
242 if( classData.
getNumRows() < numClustersPerState ){
243 errorLog <<
"train_(TimeSeriesClassificationDataStream &trainingData) - There are not enough samples in state " << classLabels[k] <<
"! You should reduce the numClustersPerState to: " << classData.
getNumRows() << endl;
255 if( !kmeans.
train_( classData ) ){
256 errorLog <<
"train_(TimeSeriesClassificationDataStream &trainingData) - Failed to train kmeans cluster for class k: " << classLabels[k] << endl;
262 stateEmissions.push_back( kmeans.getClusters() );
282 errorLog <<
"predict_(VectorDouble &inputVector) - Model Not Trained!" << endl;
286 predictedClassLabel = 0;
287 maxLikelihood = -10000;
289 if( inputVector.size() != numInputDimensions ){
290 errorLog <<
"predict_(VectorDouble &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << endl;
295 for(UINT n=0; n<numInputDimensions; n++){
296 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
300 if( classLikelihoods.size() != numClasses ) classLikelihoods.resize(numClasses,0);
301 if( classDistances.size() != numClasses ) classDistances.resize(numClasses,0);
303 std::fill(classLikelihoods.begin(),classLikelihoods.end(),0);
304 std::fill(classDistances.begin(),classDistances.end(),0);
307 particles.
filter( inputVector );
311 for(UINT i=0; i<numParticles; i++){
312 sum += particles[i].w;
313 classLikelihoods[ particles[i].currentState ] += particles[i].w;
314 classDistances[ particles[i].currentState ] += particles[i].w;
319 predictedClassLabel = 0;
320 for(UINT i=0; i<numClasses; i++){
321 classLikelihoods[ i ] /= sum;
323 if( classLikelihoods[i] > maxLikelihood ){
324 maxLikelihood = classLikelihoods[i];
325 predictedClassLabel = classLabels[i];
336 for(UINT i=0; i<numParticles; i++){
351 stateTransitions.
clear();
352 stateEmissions.clear();
362 infoLog <<
"FiniteStateMachineModel" << endl;
363 infoLog <<
"NumParticles: " << numParticles << endl;
364 infoLog <<
"NumClustersPerState: " << numClustersPerState << endl;
365 infoLog <<
"StateTransitionSmoothingCoeff: " << stateTransitionSmoothingCoeff << endl;
368 infoLog <<
"StateTransitions: " << endl;
369 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
370 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
371 infoLog << stateTransitions[i][j] <<
" ";
376 infoLog <<
"StateEmissions: " << endl;
377 for(
unsigned int k=0; k<stateEmissions.size(); k++){
378 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
379 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
380 infoLog << stateEmissions[k][i][j] <<
" ";
394 errorLog <<
"saveModelToFile(fstream &file) - The file is not open!" << endl;
399 file <<
"GRT_FSM_MODEL_FILE_V1.0\n";
403 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << endl;
407 file <<
"NumParticles: " << numParticles << endl;
408 file <<
"NumClustersPerState: " << numClustersPerState << endl;
409 file <<
"StateTransitionSmoothingCoeff: " << stateTransitionSmoothingCoeff << endl;
412 file <<
"StateTransitions:" << endl;
413 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
414 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
415 file << stateTransitions[i][j] <<
" ";
420 file <<
"StateEmissions:" << endl;
421 for(
unsigned int k=0; k<numClasses; k++){
422 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
423 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
424 file << stateEmissions[k][i][j] <<
" ";
431 file <<
"Ranges: " << endl;
432 for(UINT i=0; i<ranges.size(); i++){
433 file << ranges[i].minValue <<
"\t" << ranges[i].maxValue << endl;
448 errorLog <<
"loadModelFromFile(string filename) - Could not open file to load model" << endl;
456 if( word !=
"GRT_FSM_MODEL_FILE_V1.0" ){
457 errorLog <<
"loadModelFromFile(string filename) - Could not find Model File Header" << endl;
463 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << endl;
469 if( word !=
"NumParticles:" ){
470 errorLog <<
"loadModelFromFile(string filename) - Could not find NumParticles Header" << endl;
473 file >> numParticles;
477 if( word !=
"NumClustersPerState:" ){
478 errorLog <<
"loadModelFromFile(string filename) - Could not find NumClustersPerState Header" << endl;
481 file >> numClustersPerState;
485 if( word !=
"StateTransitionSmoothingCoeff:" ){
486 errorLog <<
"loadModelFromFile(string filename) - Could not find stateTransitionSmoothingCoeff Header" << endl;
489 file >> stateTransitionSmoothingCoeff;
495 if( word !=
"StateTransitions:" ){
496 errorLog <<
"loadModelFromFile(string filename) - Could not find StateTransitions Header" << endl;
499 stateTransitions.
resize(numClasses, numClasses);
501 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
502 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
503 file >> stateTransitions[i][j];
509 if( word !=
"StateEmissions:" ){
510 errorLog <<
"loadModelFromFile(string filename) - Could not find StateEmissions Header" << endl;
513 stateEmissions.resize( numClasses );
515 for(
unsigned int k=0; k<numClasses; k++){
516 stateEmissions[k].resize( numClustersPerState, numInputDimensions );
517 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
518 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
519 file >> stateEmissions[k][i][j];
527 if( word !=
"Ranges:" ){
528 errorLog <<
"loadModelFromFile(string filename) - Failed to read Ranges header!" << endl;
532 ranges.resize(numInputDimensions);
534 for(UINT i=0; i<ranges.size(); i++){
535 file >> ranges[i].minValue;
536 file >> ranges[i].maxValue;
546 bool FiniteStateMachine::recomputePT(){
549 warningLog <<
"recomputePT() - Failed to init particles, the model has not been trained!" << endl;
557 for(UINT i=0; i<K; i++){
558 vector< IndexedDouble > model(K);
559 for(UINT j=0; j<K; j++){
561 model[j].value = stateTransitions[i][j];
563 pt.push_back( model );
569 bool FiniteStateMachine::recomputePE(){
572 warningLog <<
"recomputePE() - Failed to init particles, the model has not been trained!" << endl;
578 const UINT K = (UINT)stateEmissions.size();
581 for(UINT k=0; k<K; k++){
584 vector< VectorDouble > model;
585 model.reserve( numClustersPerState );
586 for(UINT i=0; i<stateEmissions[k].getNumRows(); i++){
587 model.push_back( stateEmissions[k].getRowVector(i) );
590 pe.push_back( model );
596 bool FiniteStateMachine::initParticles(){
599 warningLog <<
"initParticles() - Failed to init particles, the model has not been trained!" << endl;
604 vector< VectorDouble > initModel( numInputDimensions, VectorDouble(2,0) );
605 VectorDouble initProcessNoise( numInputDimensions, 0 );
606 VectorDouble initMeasurementNoise( numInputDimensions, 0 );
609 for(
unsigned int i=0; i<numInputDimensions; i++){
610 initModel[i][0] = useScaling ? 0 : ranges[i].minValue;
611 initModel[i][1] = useScaling ? 1 : ranges[i].maxValue;
615 for(
unsigned int i=0; i<numInputDimensions; i++){
616 initMeasurementNoise[i] = measurementNoise;
619 particles.
init(numParticles, initModel, initProcessNoise, initMeasurementNoise);
625 particles.setLookupTables(
pt,
pe );
633 bool FiniteStateMachine::setNumParticles(
const UINT numParticles){
637 this->numParticles = numParticles;
642 bool FiniteStateMachine::setNumClustersPerState(
const UINT numClustersPerState){
646 this->numClustersPerState = numClustersPerState;
651 bool FiniteStateMachine::setStateTransitionSmoothingCoeff(
const double stateTransitionSmoothingCoeff){
655 this->stateTransitionSmoothingCoeff = stateTransitionSmoothingCoeff;
660 bool FiniteStateMachine::setMeasurementNoise(
const double measurementNoise){
664 this->measurementNoise = measurementNoise;
vector< vector< IndexedDouble > > pt
This stores the stateTransitions matrix in a format more efficient for the particle filter...
UINT getNumDimensions() const
virtual bool saveModelToFile(fstream &file) const
UINT getNumClasses() const
vector< vector< VectorDouble > > pe
This stores the stateEmissions model in a format more efficient for the particle filter.
UINT getNumSamples() const
bool setAllValues(const T &value)
bool setMaxNumEpochs(const UINT maxNumEpochs)
bool copyBaseVariables(const Classifier *classifier)
vector< UINT > getClassLabels() const
UINT getNumDimensions() const
UINT getNumDimensions() const
bool push_back(const std::vector< T > &sample)
bool loadBaseSettingsFromFile(fstream &file)
unsigned int getNumCols() const
UINT getNumSamples() const
UINT getNumSamples() const
bool setMinChange(const double minChange)
bool setNumClusters(const UINT numClusters)
virtual bool init(const unsigned int numParticles, const vector< VectorDouble > &initModel, const VectorDouble &processNoise, const VectorDouble &measurementNoise)
bool saveBaseSettingsToFile(fstream &file) const
double scale(const double &x, const double &minSource, const double &maxSource, const double &minTarget, const double &maxTarget, const bool constrain=false)
bool setNumDimensions(const UINT numDimensions)
UINT getClassLabelIndexValue(UINT classLabel) const
int getRandomNumberInt(int minRange, int maxRange)
virtual bool deepCopyFrom(const Classifier *classifier)
vector< MinMax > getRanges() const
virtual bool predict_(VectorDouble &inputVector)
virtual bool train_(MatrixDouble &data)
unsigned int getNumRows() const
bool scale(const double minTarget, const double maxTarget)
FiniteStateMachine(const UINT numParticles=200, const UINT numClustersPerState=20, const double stateTransitionSmoothingCoeff=0.0, const double measurementNoise=10.0)
string getClassifierType() const
virtual bool train_(ClassificationData &trainingData)
bool addSample(const UINT classLabel, const VectorDouble &trainingSample)
virtual bool loadModelFromFile(fstream &file)
virtual bool print() const
virtual ~FiniteStateMachine(void)
bool setMinNumEpochs(const UINT minNumEpochs)
virtual bool resize(const unsigned int r, const unsigned int c)
virtual bool filter(SENSOR_DATA &data)
FiniteStateMachine & operator=(const FiniteStateMachine &rhs)