21 #define GRT_DLL_EXPORTS
29 Softmax::Softmax(
const bool useScaling,
const Float learningRate,
const Float minChange,
const UINT maxNumEpochs)
31 this->useScaling = useScaling;
32 this->learningRate = learningRate;
33 this->minChange = minChange;
34 this->maxNumEpochs = maxNumEpochs;
35 classType =
"Softmax";
36 classifierType = classType;
37 classifierMode = STANDARD_CLASSIFIER_MODE;
38 debugLog.setProceedingText(
"[DEBUG Softmax]");
39 errorLog.setProceedingText(
"[ERROR Softmax]");
40 trainingLog.setProceedingText(
"[TRAINING Softmax]");
41 warningLog.setProceedingText(
"[WARNING Softmax]");
45 classType =
"Softmax";
46 classifierType = classType;
47 classifierMode = STANDARD_CLASSIFIER_MODE;
48 debugLog.setProceedingText(
"[DEBUG Softmax]");
49 errorLog.setProceedingText(
"[ERROR Softmax]");
50 trainingLog.setProceedingText(
"[TRAINING Softmax]");
51 warningLog.setProceedingText(
"[WARNING Softmax]");
61 this->learningRate = rhs.learningRate;
62 this->minChange = rhs.minChange;
63 this->maxNumEpochs = rhs.maxNumEpochs;
64 this->models = rhs.models;
74 if( classifier == NULL )
return false;
79 this->learningRate = ptr->learningRate;
80 this->minChange = ptr->minChange;
81 this->maxNumEpochs = ptr->maxNumEpochs;
82 this->models = ptr->models;
100 errorLog <<
"train_(ClassificationData &labelledTrainingData) - Training data has zero samples!" << std::endl;
104 numInputDimensions = N;
113 trainingData.
scale(0, 1);
117 for(UINT k=0; k<numClasses; k++){
123 if( !trainSoftmaxModel(classLabels[k],models[k],trainingData) ){
124 errorLog <<
"train(ClassificationData labelledTrainingData) - Failed to train model for class: " << classLabels[k] << std::endl;
137 errorLog <<
"predict_(VectorFloat &inputVector) - Model Not Trained!" << std::endl;
141 predictedClassLabel = 0;
142 maxLikelihood = -10000;
144 if( !trained )
return false;
146 if( inputVector.size() != numInputDimensions ){
147 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
152 for(UINT n=0; n<numInputDimensions; n++){
153 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
157 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
158 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
164 for(UINT k=0; k<numClasses; k++){
165 Float estimate = models[k].compute( inputVector );
167 if( estimate > bestEstimate ){
168 bestEstimate = estimate;
172 classDistances[k] = estimate;
173 classLikelihoods[k] = estimate;
178 for(UINT k=0; k<numClasses; k++){
179 classLikelihoods[k] /= sum;
183 maxLikelihood = bestEstimate;
184 predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
187 maxLikelihood = classLikelihoods[bestIndex];
188 predictedClassLabel = classLabels[bestIndex];
197 Float lastErrorSum = 0;
202 bool keepTraining =
true;
208 model.init( classLabel, N );
211 for(UINT i=0; i<M; i++){
212 y[i] = data[i].getClassLabel()==classLabel ? 1.0 : 0;
218 for(UINT i=0; i<M; i++){
219 randomTrainingOrder[i] = i;
221 std::random_shuffle(randomTrainingOrder.begin(), randomTrainingOrder.end());
224 while( keepTraining ){
228 for(UINT m=0; m<M; m++){
231 UINT i = randomTrainingOrder[m];
234 error = y[i] - model.compute( data[i].getSample() );
238 for(UINT j=0; j<N; j++){
239 model.w[j] += learningRate * error * data[i][j];
241 model.w0 += learningRate * error;
245 delta = fabs( errorSum-lastErrorSum );
246 lastErrorSum = errorSum;
249 if( delta <= minChange ){
250 keepTraining =
false;
253 if( ++iter >= maxNumEpochs ){
254 keepTraining =
false;
257 trainingLog <<
"Epoch: " << iter <<
" TotalError: " << errorSum <<
" Delta: " << delta << std::endl;
278 errorLog <<
"load(fstream &file) - The file is not open!" << std::endl;
283 file<<
"GRT_SOFTMAX_MODEL_FILE_V2.0\n";
287 errorLog <<
"save(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
293 for(UINT k=0; k<numClasses; k++){
294 file <<
"ClassLabel: " << models[k].classLabel << std::endl;
295 file <<
"Weights: " << models[k].w0;
296 for(UINT n=0; n<numInputDimensions; n++){
297 file <<
" " << models[k].w[n];
309 numInputDimensions = 0;
316 errorLog <<
"load(string filename) - Could not open file to load model" << std::endl;
325 if( word ==
"GRT_SOFTMAX_MODEL_FILE_V1.0" ){
330 if(word !=
"GRT_SOFTMAX_MODEL_FILE_V2.0"){
331 errorLog <<
"load(string filename) - Could not find Model File Header" << std::endl;
337 errorLog <<
"load(string filename) - Failed to load base settings from file!" << std::endl;
343 models.
resize(numClasses);
344 classLabels.
resize(numClasses);
348 if(word !=
"Models:"){
349 errorLog <<
"load(string filename) - Could not find the Models!" << std::endl;
353 for(UINT k=0; k<numClasses; k++){
355 if(word !=
"ClassLabel:"){
356 errorLog <<
"load(string filename) - Could not find the ClassLabel for model: " << k <<
"!" << std::endl;
359 file >> models[k].classLabel;
360 classLabels[k] = models[k].classLabel;
363 if(word !=
"Weights:"){
364 errorLog <<
"load(string filename) - Could not find the Weights for model: " << k <<
"!" << std::endl;
367 file >> models[k].w0;
369 models[k].N = numInputDimensions;
370 models[k].w.
resize( numInputDimensions );
371 for(UINT n=0; n<numInputDimensions; n++){
372 file >> models[k].w[n];
381 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
383 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
398 if(word !=
"NumFeatures:"){
399 errorLog <<
"load(string filename) - Could not find NumFeatures!" << std::endl;
402 file >> numInputDimensions;
405 if(word !=
"NumClasses:"){
406 errorLog <<
"load(string filename) - Could not find NumClasses!" << std::endl;
412 if(word !=
"UseScaling:"){
413 errorLog <<
"load(string filename) - Could not find UseScaling!" << std::endl;
419 if(word !=
"UseNullRejection:"){
420 errorLog <<
"load(string filename) - Could not find UseNullRejection!" << std::endl;
423 file >> useNullRejection;
428 ranges.
resize(numInputDimensions);
431 if(word !=
"Ranges:"){
432 errorLog <<
"load(string filename) - Could not find the Ranges!" << std::endl;
435 for(UINT n=0; n<ranges.size(); n++){
436 file >> ranges[n].minValue;
437 file >> ranges[n].maxValue;
442 models.
resize(numClasses);
443 classLabels.
resize(numClasses);
447 if(word !=
"Models:"){
448 errorLog <<
"load(string filename) - Could not find the Models!" << std::endl;
452 for(UINT k=0; k<numClasses; k++){
454 if(word !=
"ClassLabel:"){
455 errorLog <<
"load(string filename) - Could not find the ClassLabel for model: " << k <<
"!" << std::endl;
458 file >> models[k].classLabel;
459 classLabels[k] = models[k].classLabel;
462 if(word !=
"Weights:"){
463 errorLog <<
"load(string filename) - Could not find the Weights for model: " << k <<
"!" << std::endl;
466 file >> models[k].w0;
468 models[k].N = numInputDimensions;
469 models[k].w.
resize( numInputDimensions );
470 for(UINT n=0; n<numInputDimensions; n++){
471 file >> models[k].w[n];
480 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
482 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...
virtual bool load(std::fstream &file)
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 save(std::fstream &file) const