21 #define GRT_DLL_EXPORTS 27 const std::string FiniteStateMachine::id =
"FiniteStateMachine";
35 this->numParticles = numParticles;
36 this->numClustersPerState = numClustersPerState;
37 this->stateTransitionSmoothingCoeff = stateTransitionSmoothingCoeff;
38 this->measurementNoise = measurementNoise;
39 classifierMode = TIMESERIES_CLASSIFIER_MODE;
49 classifierMode = STANDARD_CLASSIFIER_MODE;
66 this->numParticles = rhs.numParticles;
67 this->numClustersPerState = rhs.numClustersPerState;
68 this->stateTransitionSmoothingCoeff = rhs.stateTransitionSmoothingCoeff;
69 this->measurementNoise = rhs.measurementNoise;
70 this->particles = rhs.particles;
71 this->stateTransitions = rhs.stateTransitions;
72 this->stateEmissions = rhs.stateEmissions;
75 this->initParticles();
83 if( classifier == NULL )
return false;
93 errorLog <<
"deepCopyFrom(const Classifier *classifier) - Failed to deep copy classifier base class!" << std::endl;
97 this->numParticles = ptr->numParticles;
98 this->numClustersPerState = ptr->numClustersPerState;
99 this->stateTransitionSmoothingCoeff = ptr->stateTransitionSmoothingCoeff;
100 this->measurementNoise = ptr->measurementNoise;
101 this->particles = ptr->particles;
102 this->stateTransitions = ptr->stateTransitions;
103 this->stateEmissions = ptr->stateEmissions;
106 this->initParticles();
120 errorLog <<
"train_(ClassificationData &trainingData) - Training data has zero samples!" << std::endl;
129 for(
unsigned int i=0; i<M; i++){
130 timeseries.
addSample(trainingData[i].getClassLabel(), trainingData[i].getSample());
134 if( !
train_( timeseries ) ){
136 errorLog <<
"train_(ClassificationData &trainingData) - Failed to train particle filter!" << std::endl;
149 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Training data has zero samples!" << std::endl;
158 for(
unsigned int i=0; i<M; i++){
159 for(
unsigned int j=0; j<trainingData[i].getLength(); j++){
160 timeseries.
addSample(trainingData[i].getClassLabel(), trainingData[i].getData().getRow(j));
165 if( !
train_( timeseries ) ){
167 errorLog << __GRT_LOG__ <<
" Failed to train particle filter!" << std::endl;
187 numInputDimensions = N;
197 stateTransitions.
resize(K, K);
205 UINT currentStateIndex = 0;
208 stateTransitions[ lastStateIndex ][ currentStateIndex ]++;
209 lastStateIndex = currentStateIndex;
214 for(UINT i=0; i<K; i++){
216 for(UINT j=0; j<K; j++){
217 sum += stateTransitions[i][j] + stateTransitionSmoothingCoeff;
219 for(UINT j=0; j<K; j++){
220 stateTransitions[i][j] /= sum;
225 for(UINT k=0; k<K; k++){
229 for(UINT i=0; i<M; i++){
230 if( data[i].getClassLabel() == classLabels[k] ){
231 classData.
push_back( data[i].getSample() );
236 if( classData.
getNumRows() < numClustersPerState ){
237 errorLog << __GRT_LOG__ <<
" There are not enough samples in state " << classLabels[k] <<
"! You should reduce the numClustersPerState to: " << classData.
getNumRows() << std::endl;
249 if( !kmeans.
train_( classData ) ){
250 errorLog << __GRT_LOG__ <<
" Failed to train kmeans cluster for class k: " << classLabels[k] << std::endl;
256 stateEmissions.push_back( kmeans.getClusters() );
277 errorLog << __GRT_LOG__ <<
" Model Not Trained!" << std::endl;
281 predictedClassLabel = 0;
282 maxLikelihood = -10000;
284 if( inputVector.
getSize() != numInputDimensions ){
285 errorLog << __GRT_LOG__ <<
" The size of the input vector (" << inputVector.
getSize() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
290 for(UINT n=0; n<numInputDimensions; n++){
291 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
295 if( classLikelihoods.
getSize() != numClasses ) classLikelihoods.
resize(numClasses,0);
296 if( classDistances.
getSize() != numClasses ) classDistances.
resize(numClasses,0);
298 std::fill(classLikelihoods.begin(),classLikelihoods.end(),0);
299 std::fill(classDistances.begin(),classDistances.end(),0);
302 particles.
filter( inputVector );
306 for(UINT i=0; i<numParticles; i++){
307 sum += particles[i].w;
308 classLikelihoods[ particles[i].currentState ] += particles[i].w;
309 classDistances[ particles[i].currentState ] += particles[i].w;
314 predictedClassLabel = 0;
315 for(UINT i=0; i<numClasses; i++){
316 classLikelihoods[ i ] /= sum;
318 if( classLikelihoods[i] > maxLikelihood ){
319 maxLikelihood = classLikelihoods[i];
320 predictedClassLabel = classLabels[i];
331 for(UINT i=0; i<numParticles; i++){
346 stateTransitions.
clear();
347 stateEmissions.clear();
357 infoLog <<
"FiniteStateMachineModel" << std::endl;
358 infoLog <<
"NumParticles: " << numParticles << std::endl;
359 infoLog <<
"NumClustersPerState: " << numClustersPerState << std::endl;
360 infoLog <<
"StateTransitionSmoothingCoeff: " << stateTransitionSmoothingCoeff << std::endl;
363 infoLog <<
"StateTransitions: " << std::endl;
364 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
365 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
366 infoLog << stateTransitions[i][j] <<
" ";
368 infoLog << std::endl;
371 infoLog <<
"StateEmissions: " << std::endl;
372 for(
unsigned int k=0; k<stateEmissions.size(); k++){
373 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
374 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
375 infoLog << stateEmissions[k][i][j] <<
" ";
377 infoLog << std::endl;
389 errorLog << __GRT_LOG__ <<
" The file is not open!" << std::endl;
394 file <<
"GRT_FSM_MODEL_FILE_V1.0\n";
398 errorLog << __GRT_LOG__ <<
" Failed to save classifier base settings to file!" << std::endl;
402 file <<
"NumParticles: " << numParticles << std::endl;
403 file <<
"NumClustersPerState: " << numClustersPerState << std::endl;
404 file <<
"StateTransitionSmoothingCoeff: " << stateTransitionSmoothingCoeff << std::endl;
407 file <<
"StateTransitions:" << std::endl;
408 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
409 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
410 file << stateTransitions[i][j] <<
" ";
415 file <<
"StateEmissions:" << std::endl;
416 for(
unsigned int k=0; k<numClasses; k++){
417 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
418 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
419 file << stateEmissions[k][i][j] <<
" ";
426 file <<
"Ranges: " << std::endl;
427 for(UINT i=0; i<ranges.
getSize(); i++){
428 file << ranges[i].minValue <<
"\t" << ranges[i].maxValue << std::endl;
443 errorLog << __GRT_LOG__ <<
" Could not open file to load model" << std::endl;
451 if( word !=
"GRT_FSM_MODEL_FILE_V1.0" ){
452 errorLog << __GRT_LOG__ <<
" Could not find Model File Header" << std::endl;
458 errorLog << __GRT_LOG__ <<
" Failed to load base settings from file!" << std::endl;
464 if( word !=
"NumParticles:" ){
465 errorLog << __GRT_LOG__ <<
" Could not find NumParticles Header" << std::endl;
468 file >> numParticles;
472 if( word !=
"NumClustersPerState:" ){
473 errorLog << __GRT_LOG__ <<
" Could not find NumClustersPerState Header" << std::endl;
476 file >> numClustersPerState;
480 if( word !=
"StateTransitionSmoothingCoeff:" ){
481 errorLog << __GRT_LOG__ <<
" Could not find stateTransitionSmoothingCoeff Header" << std::endl;
484 file >> stateTransitionSmoothingCoeff;
490 if( word !=
"StateTransitions:" ){
491 errorLog << __GRT_LOG__ <<
" Could not find StateTransitions Header" << std::endl;
494 stateTransitions.
resize(numClasses, numClasses);
496 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
497 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
498 file >> stateTransitions[i][j];
504 if( word !=
"StateEmissions:" ){
505 errorLog << __GRT_LOG__ <<
" Could not find StateEmissions Header" << std::endl;
508 stateEmissions.
resize( numClasses );
510 for(
unsigned int k=0; k<numClasses; k++){
511 stateEmissions[k].
resize( numClustersPerState, numInputDimensions );
512 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
513 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
514 file >> stateEmissions[k][i][j];
522 if( word !=
"Ranges:" ){
523 errorLog << __GRT_LOG__ <<
" Failed to read Ranges header!" << std::endl;
527 ranges.
resize(numInputDimensions);
529 for(UINT i=0; i<ranges.size(); i++){
530 file >> ranges[i].minValue;
531 file >> ranges[i].maxValue;
541 bool FiniteStateMachine::recomputePT(){
544 warningLog << __GRT_LOG__ <<
" Failed to init particles, the model has not been trained!" << std::endl;
552 for(UINT i=0; i<K; i++){
554 for(UINT j=0; j<K; j++){
556 model[j].value = stateTransitions[i][j];
558 pt.push_back( model );
564 bool FiniteStateMachine::recomputePE(){
567 warningLog << __GRT_LOG__ <<
" Failed to init particles, the model has not been trained!" << std::endl;
573 const UINT K = stateEmissions.
getSize();
576 for(UINT k=0; k<K; k++){
580 model.reserve( numClustersPerState );
581 for(UINT i=0; i<stateEmissions[k].getNumRows(); i++){
582 model.push_back( stateEmissions[k].getRow(i) );
585 pe.push_back( model );
591 bool FiniteStateMachine::initParticles(){
594 warningLog << __GRT_LOG__ <<
" Failed to init particles, the model has not been trained!" << std::endl;
600 VectorFloat initProcessNoise( numInputDimensions, 0 );
601 VectorFloat initMeasurementNoise( numInputDimensions, 0 );
604 for(
unsigned int i=0; i<numInputDimensions; i++){
605 initModel[i][0] = useScaling ? 0 : ranges[i].minValue;
606 initModel[i][1] = useScaling ? 1 : ranges[i].maxValue;
610 for(
unsigned int i=0; i<numInputDimensions; i++){
611 initMeasurementNoise[i] = measurementNoise;
614 particles.
init(numParticles, initModel, initProcessNoise, initMeasurementNoise);
620 particles.setLookupTables(
pt,
pe );
628 bool FiniteStateMachine::setNumParticles(
const UINT numParticles){
632 this->numParticles = numParticles;
637 bool FiniteStateMachine::setNumClustersPerState(
const UINT numClustersPerState){
641 this->numClustersPerState = numClustersPerState;
646 bool FiniteStateMachine::setStateTransitionSmoothingCoeff(
const Float stateTransitionSmoothingCoeff){
650 this->stateTransitionSmoothingCoeff = stateTransitionSmoothingCoeff;
655 bool FiniteStateMachine::setMeasurementNoise(
const Float measurementNoise){
659 this->measurementNoise = measurementNoise;
bool saveBaseSettingsToFile(std::fstream &file) const
virtual bool filter(SENSOR_DATA &data)
UINT getNumSamples() const
std::string getClassifierType() const
FiniteStateMachine(const UINT numParticles=200, const UINT numClustersPerState=20, const Float stateTransitionSmoothingCoeff=0.0, const Float measurementNoise=10.0)
virtual bool resize(const unsigned int size)
virtual bool train_(MatrixFloat &data)
virtual bool print() const
bool scale(const Float minTarget, const Float maxTarget)
bool setMinChange(const Float minChange)
Vector< UINT > getClassLabels() const
bool setAllValues(const T &value)
UINT getNumDimensions() const
UINT getNumSamples() const
virtual ~FiniteStateMachine(void)
virtual bool deepCopyFrom(const Classifier *classifier)
bool copyBaseVariables(const Classifier *classifier)
Vector< Vector< IndexedDouble > > pt
This stores the stateTransitions matrix in a format more efficient for the particle filter...
bool loadBaseSettingsFromFile(std::fstream &file)
virtual bool load(std::fstream &file)
unsigned int getNumRows() const
UINT getNumDimensions() const
unsigned int getNumCols() const
bool addSample(const UINT classLabel, const VectorFloat &sample)
bool setMinNumEpochs(const UINT minNumEpochs)
virtual bool train_(ClassificationData &trainingData)
UINT getClassLabelIndexValue(const UINT classLabel) const
virtual bool save(std::fstream &file) const
UINT getNumDimensions() const
UINT getNumClasses() const
bool setNumDimensions(const UINT numDimensions)
int getRandomNumberInt(int minRange, int maxRange)
virtual bool predict_(VectorFloat &inputVector)
virtual bool resize(const unsigned int r, const unsigned int c)
Vector< MinMax > getRanges() const
UINT getNumSamples() const
Vector< Vector< VectorFloat > > pe
This stores the stateEmissions model in a format more efficient for the particle filter.
virtual bool init(const unsigned int numParticles, const Vector< VectorFloat > &initModel, const VectorFloat &processNoise, const VectorFloat &measurementNoise)
bool setMaxNumEpochs(const UINT maxNumEpochs)
bool push_back(const Vector< T > &sample)
This is the main base class that all GRT Classification algorithms should inherit from...
FiniteStateMachine & operator=(const FiniteStateMachine &rhs)
bool setNumClusters(const UINT numClusters)
static std::string getId()
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)