26 RegisterClassifierModule< Softmax > Softmax::registerModule(
"Softmax");
28 Softmax::Softmax(
const bool useScaling,
const double learningRate,
const double 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!" << endl;
103 numInputDimensions = N;
106 classLabels.resize(K);
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] << endl;
136 errorLog <<
"predict_(VectorDouble &inputVector) - Model Not Trained!" << endl;
140 predictedClassLabel = 0;
141 maxLikelihood = -10000;
143 if( !trained )
return false;
145 if( inputVector.size() != numInputDimensions ){
146 errorLog <<
"predict_(VectorDouble &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << 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);
161 double bestEstimate = numeric_limits<double>::min();
163 for(UINT k=0; k<numClasses; k++){
164 double 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 double lastErrorSum = 0;
201 bool keepTraining =
true;
204 vector< UINT > randomTrainingOrder(M);
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 << endl;
277 errorLog <<
"loadModelFromFile(fstream &file) - The file is not open!" << endl;
282 file<<
"GRT_SOFTMAX_MODEL_FILE_V2.0\n";
286 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << endl;
292 for(UINT k=0; k<numClasses; k++){
293 file <<
"ClassLabel: " << models[k].classLabel << 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" << 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" << endl;
336 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << endl;
342 models.resize(numClasses);
343 classLabels.resize(numClasses);
347 if(word !=
"Models:"){
348 errorLog <<
"loadModelFromFile(string filename) - Could not find the Models!" << 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 <<
"!" << 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 <<
"!" << 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];
379 maxLikelihood = DEFAULT_NULL_LIKELIHOOD_VALUE;
380 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
381 classLikelihoods.resize(numClasses,DEFAULT_NULL_LIKELIHOOD_VALUE);
382 classDistances.resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
397 if(word !=
"NumFeatures:"){
398 errorLog <<
"loadModelFromFile(string filename) - Could not find NumFeatures!" << endl;
401 file >> numInputDimensions;
404 if(word !=
"NumClasses:"){
405 errorLog <<
"loadModelFromFile(string filename) - Could not find NumClasses!" << endl;
411 if(word !=
"UseScaling:"){
412 errorLog <<
"loadModelFromFile(string filename) - Could not find UseScaling!" << endl;
418 if(word !=
"UseNullRejection:"){
419 errorLog <<
"loadModelFromFile(string filename) - Could not find UseNullRejection!" << endl;
422 file >> useNullRejection;
427 ranges.resize(numInputDimensions);
430 if(word !=
"Ranges:"){
431 errorLog <<
"loadModelFromFile(string filename) - Could not find the Ranges!" << 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!" << 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 <<
"!" << 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 <<
"!" << 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];
478 maxLikelihood = DEFAULT_NULL_LIKELIHOOD_VALUE;
479 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
480 classLikelihoods.resize(numClasses,DEFAULT_NULL_LIKELIHOOD_VALUE);
481 classDistances.resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
Softmax(const bool useScaling=false, const double learningRate=0.1, const double minChange=1.0e-10, const UINT maxNumEpochs=1000)
virtual bool deepCopyFrom(const Classifier *classifier)
virtual bool recomputeNullRejectionThresholds()
virtual bool saveModelToFile(fstream &file) const
bool copyBaseVariables(const Classifier *classifier)
UINT getNumDimensions() const
bool loadBaseSettingsFromFile(fstream &file)
UINT getNumSamples() const
virtual bool train_(ClassificationData &trainingData)
vector< ClassTracker > getClassTracker() const
UINT getNumClasses() const
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 scale(const double minTarget, const double maxTarget)
Softmax & operator=(const Softmax &rhs)
The Softmax Classifier is a simple but effective classifier (based on logisitc regression) that works...
vector< MinMax > getRanges() const
virtual bool loadModelFromFile(fstream &file)
vector< SoftmaxModel > getModels() const
string getClassifierType() const
bool loadLegacyModelFromFile(fstream &file)
virtual bool predict_(VectorDouble &inputVector)