28 Softmax::Softmax(
const bool useScaling,
const Float learningRate,
const Float minChange,
const UINT maxNumEpochs)
30 this->useScaling = useScaling;
31 this->learningRate = learningRate;
32 this->minChange = minChange;
33 this->maxNumEpochs = maxNumEpochs;
34 classType =
"Softmax";
35 classifierType = classType;
36 classifierMode = STANDARD_CLASSIFIER_MODE;
37 debugLog.setProceedingText(
"[DEBUG Softmax]");
38 errorLog.setProceedingText(
"[ERROR Softmax]");
39 trainingLog.setProceedingText(
"[TRAINING Softmax]");
40 warningLog.setProceedingText(
"[WARNING Softmax]");
44 classType =
"Softmax";
45 classifierType = classType;
46 classifierMode = STANDARD_CLASSIFIER_MODE;
47 debugLog.setProceedingText(
"[DEBUG Softmax]");
48 errorLog.setProceedingText(
"[ERROR Softmax]");
49 trainingLog.setProceedingText(
"[TRAINING Softmax]");
50 warningLog.setProceedingText(
"[WARNING Softmax]");
60 this->learningRate = rhs.learningRate;
61 this->minChange = rhs.minChange;
62 this->maxNumEpochs = rhs.maxNumEpochs;
63 this->models = rhs.models;
73 if( classifier == NULL )
return false;
78 this->learningRate = ptr->learningRate;
79 this->minChange = ptr->minChange;
80 this->maxNumEpochs = ptr->maxNumEpochs;
81 this->models = ptr->models;
99 errorLog <<
"train_(ClassificationData &labelledTrainingData) - Training data has zero samples!" << std::endl;
103 numInputDimensions = N;
112 trainingData.
scale(0, 1);
116 for(UINT k=0; k<numClasses; k++){
122 if( !trainSoftmaxModel(classLabels[k],models[k],trainingData) ){
123 errorLog <<
"train(ClassificationData labelledTrainingData) - Failed to train model for class: " << classLabels[k] << std::endl;
136 errorLog <<
"predict_(VectorFloat &inputVector) - Model Not Trained!" << std::endl;
140 predictedClassLabel = 0;
141 maxLikelihood = -10000;
143 if( !trained )
return false;
145 if( inputVector.size() != numInputDimensions ){
146 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
151 for(UINT n=0; n<numInputDimensions; n++){
152 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
156 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
157 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
163 for(UINT k=0; k<numClasses; k++){
164 Float estimate = models[k].compute( inputVector );
166 if( estimate > bestEstimate ){
167 bestEstimate = estimate;
171 classDistances[k] = estimate;
172 classLikelihoods[k] = estimate;
177 for(UINT k=0; k<numClasses; k++){
178 classLikelihoods[k] /= sum;
182 maxLikelihood = bestEstimate;
183 predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
186 maxLikelihood = classLikelihoods[bestIndex];
187 predictedClassLabel = classLabels[bestIndex];
196 Float lastErrorSum = 0;
201 bool keepTraining =
true;
207 model.init( classLabel, N );
210 for(UINT i=0; i<M; i++){
211 y[i] = data[i].getClassLabel()==classLabel ? 1.0 : 0;
217 for(UINT i=0; i<M; i++){
218 randomTrainingOrder[i] = i;
220 std::random_shuffle(randomTrainingOrder.begin(), randomTrainingOrder.end());
223 while( keepTraining ){
227 for(UINT m=0; m<M; m++){
230 UINT i = randomTrainingOrder[m];
233 error = y[i] - model.compute( data[i].getSample() );
237 for(UINT j=0; j<N; j++){
238 model.w[j] += learningRate * error * data[i][j];
240 model.w0 += learningRate * error;
244 delta = fabs( errorSum-lastErrorSum );
245 lastErrorSum = errorSum;
248 if( delta <= minChange ){
249 keepTraining =
false;
252 if( ++iter >= maxNumEpochs ){
253 keepTraining =
false;
256 trainingLog <<
"Epoch: " << iter <<
" TotalError: " << errorSum <<
" Delta: " << delta << std::endl;
277 errorLog <<
"loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
282 file<<
"GRT_SOFTMAX_MODEL_FILE_V2.0\n";
286 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
292 for(UINT k=0; k<numClasses; k++){
293 file <<
"ClassLabel: " << models[k].classLabel << std::endl;
294 file <<
"Weights: " << models[k].w0;
295 for(UINT n=0; n<numInputDimensions; n++){
296 file <<
" " << models[k].w[n];
308 numInputDimensions = 0;
315 errorLog <<
"loadModelFromFile(string filename) - Could not open file to load model" << std::endl;
324 if( word ==
"GRT_SOFTMAX_MODEL_FILE_V1.0" ){
329 if(word !=
"GRT_SOFTMAX_MODEL_FILE_V2.0"){
330 errorLog <<
"loadModelFromFile(string filename) - Could not find Model File Header" << std::endl;
336 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << std::endl;
342 models.
resize(numClasses);
343 classLabels.
resize(numClasses);
347 if(word !=
"Models:"){
348 errorLog <<
"loadModelFromFile(string filename) - Could not find the Models!" << std::endl;
352 for(UINT k=0; k<numClasses; k++){
354 if(word !=
"ClassLabel:"){
355 errorLog <<
"loadModelFromFile(string filename) - Could not find the ClassLabel for model: " << k <<
"!" << std::endl;
358 file >> models[k].classLabel;
359 classLabels[k] = models[k].classLabel;
362 if(word !=
"Weights:"){
363 errorLog <<
"loadModelFromFile(string filename) - Could not find the Weights for model: " << k <<
"!" << std::endl;
366 file >> models[k].w0;
368 models[k].N = numInputDimensions;
369 models[k].w.
resize( numInputDimensions );
370 for(UINT n=0; n<numInputDimensions; n++){
371 file >> models[k].w[n];
380 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
382 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
397 if(word !=
"NumFeatures:"){
398 errorLog <<
"loadModelFromFile(string filename) - Could not find NumFeatures!" << std::endl;
401 file >> numInputDimensions;
404 if(word !=
"NumClasses:"){
405 errorLog <<
"loadModelFromFile(string filename) - Could not find NumClasses!" << std::endl;
411 if(word !=
"UseScaling:"){
412 errorLog <<
"loadModelFromFile(string filename) - Could not find UseScaling!" << std::endl;
418 if(word !=
"UseNullRejection:"){
419 errorLog <<
"loadModelFromFile(string filename) - Could not find UseNullRejection!" << std::endl;
422 file >> useNullRejection;
427 ranges.
resize(numInputDimensions);
430 if(word !=
"Ranges:"){
431 errorLog <<
"loadModelFromFile(string filename) - Could not find the Ranges!" << std::endl;
434 for(UINT n=0; n<ranges.size(); n++){
435 file >> ranges[n].minValue;
436 file >> ranges[n].maxValue;
441 models.
resize(numClasses);
442 classLabels.
resize(numClasses);
446 if(word !=
"Models:"){
447 errorLog <<
"loadModelFromFile(string filename) - Could not find the Models!" << std::endl;
451 for(UINT k=0; k<numClasses; k++){
453 if(word !=
"ClassLabel:"){
454 errorLog <<
"loadModelFromFile(string filename) - Could not find the ClassLabel for model: " << k <<
"!" << std::endl;
457 file >> models[k].classLabel;
458 classLabels[k] = models[k].classLabel;
461 if(word !=
"Weights:"){
462 errorLog <<
"loadModelFromFile(string filename) - Could not find the Weights for model: " << k <<
"!" << std::endl;
465 file >> models[k].w0;
467 models[k].N = numInputDimensions;
468 models[k].w.
resize( numInputDimensions );
469 for(UINT n=0; n<numInputDimensions; n++){
470 file >> models[k].w[n];
479 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
481 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
bool saveBaseSettingsToFile(std::fstream &file) const
virtual bool recomputeNullRejectionThresholds()
#define DEFAULT_NULL_LIKELIHOOD_VALUE
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
bool loadLegacyModelFromFile(std::fstream &file)
std::string getClassifierType() const
Vector< ClassTracker > getClassTracker() const
virtual bool resize(const unsigned int size)
Vector< SoftmaxModel > getModels() const
virtual bool predict_(VectorFloat &inputVector)
Softmax(const bool useScaling=false, const Float learningRate=0.1, const Float minChange=1.0e-10, const UINT maxNumEpochs=1000)
Softmax & operator=(const Softmax &rhs)
UINT getNumSamples() const
bool copyBaseVariables(const Classifier *classifier)
bool loadBaseSettingsFromFile(std::fstream &file)
UINT getNumDimensions() const
UINT getNumClasses() const
The Softmax Classifier is a simple but effective classifier (based on logisitc regression) that works...
Vector< MinMax > getRanges() const
virtual bool deepCopyFrom(const Classifier *classifier)
bool scale(const Float minTarget, const Float maxTarget)
virtual bool train_(ClassificationData &trainingData)
virtual bool loadModelFromFile(std::fstream &file)
virtual bool saveModelToFile(std::fstream &file) const