/// <summary> /// /// </summary> /// <param name="dataFilename"></param> /// <param name="filenameToSave"></param> /// <param name="filenameToLoad"></param> private void BuildBoostClassifier(string dataFilename, string filenameToSave, string filenameToLoad) { const int ClassCount = 26; CvMat data = null; CvMat responses = null; CvMat varType = null; CvMat tempSample = null; CvMat weakResponses = null; int nsamplesAall = 0, ntrainSamples = 0; int varCount; double trainHr = 0, testHr = 0; CvBoost boost = new CvBoost(); try { ReadNumClassData(dataFilename, 16, out data, out responses); } catch { Console.WriteLine("Could not read the database {0}", dataFilename); return; } Console.WriteLine("The database {0} is loaded.", dataFilename); nsamplesAall = data.Rows; ntrainSamples = (int)(nsamplesAall * 0.5); varCount = data.Cols; // Create or load Boosted Tree classifier if (filenameToLoad != null) { // load classifier from the specified file boost.Load(filenameToLoad); ntrainSamples = 0; if (boost.GetWeakPredictors() == null) { Console.WriteLine("Could not read the classifier {0}", filenameToLoad); return; } Console.WriteLine("The classifier {0} is loaded.", filenameToLoad); } else { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // As currently boosted tree classifier in MLL can only be trained // for 2-class problems, we transform the training database by // "unrolling" each training sample as many times as the number of // classes (26) that we have. // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! using (CvMat newData = new CvMat(ntrainSamples * ClassCount, varCount + 1, MatrixType.F32C1)) using (CvMat newResponses = new CvMat(ntrainSamples * ClassCount, 1, MatrixType.S32C1)) { // 1. unroll the database type mask Console.WriteLine("Unrolling the database..."); for (int i = 0; i < ntrainSamples; i++) { unsafe { float *dataRow = (float *)(data.DataByte + data.Step * i); for (int j = 0; j < ClassCount; j++) { float *newDataRow = (float *)(newData.DataByte + newData.Step * (i * ClassCount + j)); for (int k = 0; k < varCount; k++) { newDataRow[k] = dataRow[k]; } newDataRow[varCount] = (float)j; newResponses.DataInt32[i * ClassCount + j] = (responses.DataSingle[i] == j + 'A') ? 1 : 0; } } } // 2. create type mask varType = new CvMat(varCount + 2, 1, MatrixType.U8C1); varType.Set(CvScalar.ScalarAll(CvStatModel.CV_VAR_ORDERED)); // the last indicator variable, as well // as the new (binary) response are categorical varType.SetReal1D(varCount, CvStatModel.CV_VAR_CATEGORICAL); varType.SetReal1D(varCount + 1, CvStatModel.CV_VAR_CATEGORICAL); // 3. train classifier Console.Write("Training the classifier (may take a few minutes)..."); boost.Train( newData, DTreeDataLayout.RowSample, newResponses, null, null, varType, null, new CvBoostParams(CvBoost.REAL, 100, 0.95, 5, false, null) ); } Console.WriteLine(); } tempSample = new CvMat(1, varCount + 1, MatrixType.F32C1); weakResponses = new CvMat(1, boost.GetWeakPredictors().Total, MatrixType.F32C1); // compute prediction error on train and test data for (int i = 0; i < nsamplesAall; i++) { int bestClass = 0; double maxSum = double.MinValue; double r; CvMat sample; Cv.GetRow(data, out sample, i); for (int k = 0; k < varCount; k++) { tempSample.DataArraySingle[k] = sample.DataArraySingle[k]; } for (int j = 0; j < ClassCount; j++) { tempSample.DataArraySingle[varCount] = (float)j; boost.Predict(tempSample, null, weakResponses); double sum = weakResponses.Sum().Val0; if (maxSum < sum) { maxSum = sum; bestClass = j + 'A'; } } r = (Math.Abs(bestClass - responses.DataArraySingle[i]) < float.Epsilon) ? 1 : 0; if (i < ntrainSamples) { trainHr += r; } else { testHr += r; } } testHr /= (double)(nsamplesAall - ntrainSamples); trainHr /= (double)ntrainSamples; Console.WriteLine("Recognition rate: train = {0:F1}%, test = {1:F1}%", trainHr * 100.0, testHr * 100.0); Console.WriteLine("Number of trees: {0}", boost.GetWeakPredictors().Total); // Save classifier to file if needed if (filenameToSave != null) { boost.Save(filenameToSave); } Console.Read(); tempSample.Dispose(); weakResponses.Dispose(); if (varType != null) { varType.Dispose(); } data.Dispose(); responses.Dispose(); boost.Dispose(); }
/// <summary> /// /// </summary> /// <param name="dataFilename"></param> /// <param name="filenameToSave"></param> /// <param name="filenameToLoad"></param> private void BuildBoostClassifier(string dataFilename, string filenameToSave, string filenameToLoad) { const int ClassCount = 26; CvMat data = null; CvMat responses = null; CvMat varType = null; CvMat tempSample = null; CvMat weakResponses = null; int nsamplesAall = 0, ntrainSamples = 0; int varCount; double trainHr = 0, testHr = 0; CvBoost boost = new CvBoost(); try { ReadNumClassData(dataFilename, 16, out data, out responses); } catch { Console.WriteLine("Could not read the database {0}", dataFilename); return; } Console.WriteLine("The database {0} is loaded.", dataFilename); nsamplesAall = data.Rows; ntrainSamples = (int)(nsamplesAall * 0.5); varCount = data.Cols; // Create or load Boosted Tree classifier if (filenameToLoad != null) { // load classifier from the specified file boost.Load(filenameToLoad); ntrainSamples = 0; if (boost.GetWeakPredictors() == null) { Console.WriteLine("Could not read the classifier {0}", filenameToLoad); return; } Console.WriteLine("The classifier {0} is loaded.", filenameToLoad); } else { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // As currently boosted tree classifier in MLL can only be trained // for 2-class problems, we transform the training database by // "unrolling" each training sample as many times as the number of // classes (26) that we have. // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! using (CvMat newData = new CvMat(ntrainSamples * ClassCount, varCount + 1, MatrixType.F32C1)) using (CvMat newResponses = new CvMat(ntrainSamples * ClassCount, 1, MatrixType.S32C1)) { // 1. unroll the database type mask Console.WriteLine("Unrolling the database..."); for (int i = 0; i < ntrainSamples; i++) { unsafe { float* dataRow = (float*)(data.DataByte + data.Step * i); for (int j = 0; j < ClassCount; j++) { float* newDataRow = (float*)(newData.DataByte + newData.Step * (i * ClassCount + j)); for (int k = 0; k < varCount; k++) { newDataRow[k] = dataRow[k]; } newDataRow[varCount] = (float)j; newResponses.DataInt32[i * ClassCount + j] = (responses.DataSingle[i] == j + 'A') ? 1 : 0; } } } // 2. create type mask varType = new CvMat(varCount + 2, 1, MatrixType.U8C1); varType.Set(CvScalar.ScalarAll(CvStatModel.CV_VAR_ORDERED)); // the last indicator variable, as well // as the new (binary) response are categorical varType.SetReal1D(varCount, CvStatModel.CV_VAR_CATEGORICAL); varType.SetReal1D(varCount + 1, CvStatModel.CV_VAR_CATEGORICAL); // 3. train classifier Console.Write("Training the classifier (may take a few minutes)..."); boost.Train( newData, DTreeDataLayout.RowSample, newResponses, null, null, varType, null, new CvBoostParams(CvBoost.REAL, 100, 0.95, 5, false, null) ); } Console.WriteLine(); } tempSample = new CvMat(1, varCount + 1, MatrixType.F32C1); weakResponses = new CvMat(1, boost.GetWeakPredictors().Total, MatrixType.F32C1); // compute prediction error on train and test data for (int i = 0; i < nsamplesAall; i++) { int bestClass = 0; double maxSum = double.MinValue; double r; CvMat sample; Cv.GetRow(data, out sample, i); for (int k = 0; k < varCount; k++) { tempSample.DataArraySingle[k] = sample.DataArraySingle[k]; } for (int j = 0; j < ClassCount; j++) { tempSample.DataArraySingle[varCount] = (float)j; boost.Predict(tempSample, null, weakResponses); double sum = weakResponses.Sum().Val0; if (maxSum < sum) { maxSum = sum; bestClass = j + 'A'; } } r = (Math.Abs(bestClass - responses.DataArraySingle[i]) < float.Epsilon) ? 1 : 0; if (i < ntrainSamples) trainHr += r; else testHr += r; } testHr /= (double)(nsamplesAall - ntrainSamples); trainHr /= (double)ntrainSamples; Console.WriteLine("Recognition rate: train = {0:F1}%, test = {1:F1}%", trainHr * 100.0, testHr * 100.0); Console.WriteLine("Number of trees: {0}", boost.GetWeakPredictors().Total); // Save classifier to file if needed if (filenameToSave != null) { boost.Save(filenameToSave); } Console.Read(); tempSample.Dispose(); weakResponses.Dispose(); if (varType != null) varType.Dispose(); data.Dispose(); responses.Dispose(); boost.Dispose(); }