21 #define GRT_DLL_EXPORTS
31 this->numParticles = numParticles;
32 this->numClustersPerState = numClustersPerState;
33 this->stateTransitionSmoothingCoeff = stateTransitionSmoothingCoeff;
34 this->measurementNoise = measurementNoise;
35 classType =
"FiniteStateMachine";
36 classifierType = classType;
37 classifierMode = TIMESERIES_CLASSIFIER_MODE;
38 debugLog.setProceedingText(
"[DEBUG FiniteStateMachine]");
39 errorLog.setProceedingText(
"[ERROR FiniteStateMachine]");
40 trainingLog.setProceedingText(
"[TRAINING FiniteStateMachine]");
41 warningLog.setProceedingText(
"[WARNING FiniteStateMachine]");
50 classType =
"FiniteStateMachine";
51 classifierType = classType;
52 classifierMode = STANDARD_CLASSIFIER_MODE;
53 debugLog.setProceedingText(
"[DEBUG FiniteStateMachine]");
54 errorLog.setProceedingText(
"[ERROR FiniteStateMachine]");
55 trainingLog.setProceedingText(
"[TRAINING FiniteStateMachine]");
56 warningLog.setProceedingText(
"[WARNING FiniteStateMachine]");
73 this->numParticles = rhs.numParticles;
74 this->numClustersPerState = rhs.numClustersPerState;
75 this->stateTransitionSmoothingCoeff = rhs.stateTransitionSmoothingCoeff;
76 this->measurementNoise = rhs.measurementNoise;
77 this->particles = rhs.particles;
78 this->stateTransitions = rhs.stateTransitions;
79 this->stateEmissions = rhs.stateEmissions;
82 this->initParticles();
90 if( classifier == NULL )
return false;
100 errorLog <<
"deepCopyFrom(const Classifier *classifier) - Failed to deep copy classifier base class!" << std::endl;
104 this->numParticles = ptr->numParticles;
105 this->numClustersPerState = ptr->numClustersPerState;
106 this->stateTransitionSmoothingCoeff = ptr->stateTransitionSmoothingCoeff;
107 this->measurementNoise = ptr->measurementNoise;
108 this->particles = ptr->particles;
109 this->stateTransitions = ptr->stateTransitions;
110 this->stateEmissions = ptr->stateEmissions;
113 this->initParticles();
127 errorLog <<
"train_(ClassificationData &trainingData) - Training data has zero samples!" << std::endl;
136 for(
unsigned int i=0; i<M; i++){
137 timeseries.
addSample(trainingData[i].getClassLabel(), trainingData[i].getSample());
141 if( !
train_( timeseries ) ){
143 errorLog <<
"train_(ClassificationData &trainingData) - Failed to train particle filter!" << std::endl;
156 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Training data has zero samples!" << std::endl;
165 for(
unsigned int i=0; i<M; i++){
166 for(
unsigned int j=0; j<trainingData[i].getLength(); j++){
167 timeseries.
addSample(trainingData[i].getClassLabel(), trainingData[i].getData().getRow(j));
172 if( !
train_( timeseries ) ){
174 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Failed to train particle filter!" << std::endl;
194 numInputDimensions = N;
204 stateTransitions.
resize(K, K);
212 UINT currentStateIndex = 0;
215 stateTransitions[ lastStateIndex ][ currentStateIndex ]++;
216 lastStateIndex = currentStateIndex;
221 for(UINT i=0; i<K; i++){
223 for(UINT j=0; j<K; j++){
224 sum += stateTransitions[i][j] + stateTransitionSmoothingCoeff;
226 for(UINT j=0; j<K; j++){
227 stateTransitions[i][j] /= sum;
232 for(UINT k=0; k<K; k++){
236 for(UINT i=0; i<M; i++){
237 if( data[i].getClassLabel() == classLabels[k] ){
238 classData.
push_back( data[i].getSample() );
243 if( classData.
getNumRows() < numClustersPerState ){
244 errorLog <<
"train_(TimeSeriesClassificationDataStream &trainingData) - There are not enough samples in state " << classLabels[k] <<
"! You should reduce the numClustersPerState to: " << classData.
getNumRows() << std::endl;
256 if( !kmeans.
train_( classData ) ){
257 errorLog <<
"train_(TimeSeriesClassificationDataStream &trainingData) - Failed to train kmeans cluster for class k: " << classLabels[k] << std::endl;
263 stateEmissions.push_back( kmeans.getClusters() );
283 errorLog <<
"predict_(VectorFloat &inputVector) - Model Not Trained!" << std::endl;
287 predictedClassLabel = 0;
288 maxLikelihood = -10000;
290 if( inputVector.size() != numInputDimensions ){
291 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
296 for(UINT n=0; n<numInputDimensions; n++){
297 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
301 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
302 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
304 std::fill(classLikelihoods.begin(),classLikelihoods.end(),0);
305 std::fill(classDistances.begin(),classDistances.end(),0);
308 particles.
filter( inputVector );
312 for(UINT i=0; i<numParticles; i++){
313 sum += particles[i].w;
314 classLikelihoods[ particles[i].currentState ] += particles[i].w;
315 classDistances[ particles[i].currentState ] += particles[i].w;
320 predictedClassLabel = 0;
321 for(UINT i=0; i<numClasses; i++){
322 classLikelihoods[ i ] /= sum;
324 if( classLikelihoods[i] > maxLikelihood ){
325 maxLikelihood = classLikelihoods[i];
326 predictedClassLabel = classLabels[i];
337 for(UINT i=0; i<numParticles; i++){
352 stateTransitions.
clear();
353 stateEmissions.clear();
363 infoLog <<
"FiniteStateMachineModel" << std::endl;
364 infoLog <<
"NumParticles: " << numParticles << std::endl;
365 infoLog <<
"NumClustersPerState: " << numClustersPerState << std::endl;
366 infoLog <<
"StateTransitionSmoothingCoeff: " << stateTransitionSmoothingCoeff << std::endl;
369 infoLog <<
"StateTransitions: " << std::endl;
370 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
371 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
372 infoLog << stateTransitions[i][j] <<
" ";
374 infoLog << std::endl;
377 infoLog <<
"StateEmissions: " << std::endl;
378 for(
unsigned int k=0; k<stateEmissions.size(); k++){
379 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
380 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
381 infoLog << stateEmissions[k][i][j] <<
" ";
383 infoLog << std::endl;
395 errorLog <<
"save(fstream &file) - The file is not open!" << std::endl;
400 file <<
"GRT_FSM_MODEL_FILE_V1.0\n";
404 errorLog <<
"save(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
408 file <<
"NumParticles: " << numParticles << std::endl;
409 file <<
"NumClustersPerState: " << numClustersPerState << std::endl;
410 file <<
"StateTransitionSmoothingCoeff: " << stateTransitionSmoothingCoeff << std::endl;
413 file <<
"StateTransitions:" << std::endl;
414 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
415 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
416 file << stateTransitions[i][j] <<
" ";
421 file <<
"StateEmissions:" << std::endl;
422 for(
unsigned int k=0; k<numClasses; k++){
423 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
424 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
425 file << stateEmissions[k][i][j] <<
" ";
432 file <<
"Ranges: " << std::endl;
433 for(UINT i=0; i<ranges.size(); i++){
434 file << ranges[i].minValue <<
"\t" << ranges[i].maxValue << std::endl;
449 errorLog <<
"load(string filename) - Could not open file to load model" << std::endl;
457 if( word !=
"GRT_FSM_MODEL_FILE_V1.0" ){
458 errorLog <<
"load(string filename) - Could not find Model File Header" << std::endl;
464 errorLog <<
"load(string filename) - Failed to load base settings from file!" << std::endl;
470 if( word !=
"NumParticles:" ){
471 errorLog <<
"load(string filename) - Could not find NumParticles Header" << std::endl;
474 file >> numParticles;
478 if( word !=
"NumClustersPerState:" ){
479 errorLog <<
"load(string filename) - Could not find NumClustersPerState Header" << std::endl;
482 file >> numClustersPerState;
486 if( word !=
"StateTransitionSmoothingCoeff:" ){
487 errorLog <<
"load(string filename) - Could not find stateTransitionSmoothingCoeff Header" << std::endl;
490 file >> stateTransitionSmoothingCoeff;
496 if( word !=
"StateTransitions:" ){
497 errorLog <<
"load(string filename) - Could not find StateTransitions Header" << std::endl;
500 stateTransitions.
resize(numClasses, numClasses);
502 for(
unsigned int i=0; i<stateTransitions.
getNumRows(); i++){
503 for(
unsigned int j=0; j<stateTransitions.
getNumCols(); j++){
504 file >> stateTransitions[i][j];
510 if( word !=
"StateEmissions:" ){
511 errorLog <<
"load(string filename) - Could not find StateEmissions Header" << std::endl;
514 stateEmissions.
resize( numClasses );
516 for(
unsigned int k=0; k<numClasses; k++){
517 stateEmissions[k].
resize( numClustersPerState, numInputDimensions );
518 for(
unsigned int i=0; i<stateEmissions[k].getNumRows(); i++){
519 for(
unsigned int j=0; j<stateEmissions[k].getNumCols(); j++){
520 file >> stateEmissions[k][i][j];
528 if( word !=
"Ranges:" ){
529 errorLog <<
"load(string filename) - Failed to read Ranges header!" << std::endl;
533 ranges.
resize(numInputDimensions);
535 for(UINT i=0; i<ranges.size(); i++){
536 file >> ranges[i].minValue;
537 file >> ranges[i].maxValue;
547 bool FiniteStateMachine::recomputePT(){
550 warningLog <<
"recomputePT() - Failed to init particles, the model has not been trained!" << std::endl;
558 for(UINT i=0; i<K; i++){
560 for(UINT j=0; j<K; j++){
562 model[j].value = stateTransitions[i][j];
564 pt.push_back( model );
570 bool FiniteStateMachine::recomputePE(){
573 warningLog <<
"recomputePE() - Failed to init particles, the model has not been trained!" << std::endl;
579 const UINT K = stateEmissions.
getSize();
582 for(UINT k=0; k<K; k++){
586 model.reserve( numClustersPerState );
587 for(UINT i=0; i<stateEmissions[k].getNumRows(); i++){
588 model.push_back( stateEmissions[k].getRow(i) );
591 pe.push_back( model );
597 bool FiniteStateMachine::initParticles(){
600 warningLog <<
"initParticles() - Failed to init particles, the model has not been trained!" << std::endl;
606 VectorFloat initProcessNoise( numInputDimensions, 0 );
607 VectorFloat initMeasurementNoise( numInputDimensions, 0 );
610 for(
unsigned int i=0; i<numInputDimensions; i++){
611 initModel[i][0] = useScaling ? 0 : ranges[i].minValue;
612 initModel[i][1] = useScaling ? 1 : ranges[i].maxValue;
616 for(
unsigned int i=0; i<numInputDimensions; i++){
617 initMeasurementNoise[i] = measurementNoise;
620 particles.
init(numParticles, initModel, initProcessNoise, initMeasurementNoise);
626 particles.setLookupTables(
pt,
pe );
634 bool FiniteStateMachine::setNumParticles(
const UINT numParticles){
638 this->numParticles = numParticles;
643 bool FiniteStateMachine::setNumClustersPerState(
const UINT numClustersPerState){
647 this->numClustersPerState = numClustersPerState;
652 bool FiniteStateMachine::setStateTransitionSmoothingCoeff(
const Float stateTransitionSmoothingCoeff){
656 this->stateTransitionSmoothingCoeff = stateTransitionSmoothingCoeff;
661 bool FiniteStateMachine::setMeasurementNoise(
const Float measurementNoise){
665 this->measurementNoise = measurementNoise;
bool saveBaseSettingsToFile(std::fstream &file) const
virtual bool filter(SENSOR_DATA &data)
UINT getNumSamples() const
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
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
UINT getClassLabelIndexValue(UINT classLabel) 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)
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)
FiniteStateMachine & operator=(const FiniteStateMachine &rhs)
bool setNumClusters(const UINT numClusters)