diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 75fb6d134..7710abdae 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1511,9 +1511,9 @@ The gradient descent show amazing performance for large-scale problems, reducing The classifier has 5 parameters. These are - model type, - margin type, -- \f$\lambda\f$ (strength of restrictions on outliers), -- \f$\gamma_0\f$ (initial step size), -- \f$c\f$ (power coefficient for decreasing of step size), +- marginRegularization (\f$\lambda\f$), +- initialStepSize (\f$\gamma_0\f$), +- stepDecreasingPower (\f$c\f$), - and termination criteria. The model type may have one of the following values: \ref SGD and \ref ASGD. @@ -1538,27 +1538,27 @@ The margin type may have one of the following values: \ref SOFT_MARGIN or \ref H - In the general case (if you know nothing about linear separability of your sets), use SOFT_MARGIN. The other parameters may be described as follows: -- \f$\lambda\f$ parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers +- marginRegularization parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers (the less the parameter, the less probability that an outlier will be ignored). Recommended value for SGD model is 0.0001, for ASGD model is 0.00001. -- \f$\gamma_0\f$ parameter is the initial value for the step size \f$\gamma(t)\f$. +- initialStepSize parameter is the initial value for the step size \f$\gamma(t)\f$. You will have to find the best \f$\gamma_0\f$ for your problem. -- \f$c\f$ is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. +- stepDecreasingPower is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. Recommended value for SGD model is 1, for ASGD model is 0.75. - Termination criteria can be TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT + TermCriteria::EPS. You will have to find the best termination criteria for your problem. -Note that the parameters \f$\lambda\f$, \f$\gamma_0\f$, and \f$c\f$ should be positive. +Note that the parameters marginRegularization, initialStepSize, and stepDecreasingPower should be positive. To use SVMSGD algorithm do as follows: - first, create the SVMSGD object. -- then set parameters (model type, margin type, \f$\lambda\f$, \f$\gamma_0\f$, \f$c\f$) using the functions - setSvmsgdType(), setMarginType(), setLambda(), setGamma0(), and setC(), or the function setOptimalParameters(). +- then set parameters (model type, margin type, marginRegularization, initialStepSize, stepDecreasingPower) using the functions + setSvmsgdType(), setMarginType(), setMarginRegularization(), setInitialStepSize(), and setStepDecreasingPower(), or the function setOptimalParameters(). - then the SVM model can be trained using the train features and the correspondent labels by the method train(). @@ -1618,16 +1618,16 @@ public: /** @brief Function sets optimal parameters values for chosen SVM SGD model. * If chosen type is ASGD, function sets the following values for parameters of model: - * \f$\lambda = 0.00001\f$; - * \f$\gamma_0 = 0.05\f$; - * \f$c = 0.75\f$; + * marginRegularization = 0.00001; + * initialStepSize = 0.05; + * stepDecreasingPower = 0.75; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; * * If SGD: - * \f$\lambda = 0.0001\f$; - * \f$\gamma_0 = 0.05\f$; - * \f$c = 1\f$; + * marginRegularization = 0.0001; + * initialStepSize = 0.05; + * stepDecreasingPower = 1; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; * @param svmsgdType is the type of SVMSGD classifier. Legal values are SvmsgdType::SGD and SvmsgdType::ASGD. @@ -1650,23 +1650,23 @@ public: CV_WRAP virtual void setMarginType(int marginType) = 0; - /** @brief Parameter \f$\lambda\f$ of a %SVMSGD optimization problem. Default value is 0. */ - /** @see setLambda */ - CV_WRAP virtual float getLambda() const = 0; - /** @copybrief getLambda @see getLambda */ - CV_WRAP virtual void setLambda(float lambda) = 0; + /** @brief Parameter marginRegularization of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setMarginRegularization */ + CV_WRAP virtual float getMarginRegularization() const = 0; + /** @copybrief getMarginRegularization @see getMarginRegularization */ + CV_WRAP virtual void setMarginRegularization(float marginRegularization) = 0; /** @brief Parameter \f$\gamma_0\f$ of a %SVMSGD optimization problem. Default value is 0. */ - /** @see setGamma0 */ - CV_WRAP virtual float getGamma0() const = 0; - /** @copybrief getGamma0 @see getGamma0 */ - CV_WRAP virtual void setGamma0(float gamma0) = 0; + /** @see setInitialStepSize */ + CV_WRAP virtual float getInitialStepSize() const = 0; + /** @copybrief getInitialStepSize @see getInitialStepSize */ + CV_WRAP virtual void setInitialStepSize(float InitialStepSize) = 0; - /** @brief Parameter \f$c\f$ of a %SVMSGD optimization problem. Default value is 0. */ - /** @see setC */ - CV_WRAP virtual float getC() const = 0; - /** @copybrief getC @see getC */ - CV_WRAP virtual void setC(float c) = 0; + /** @brief Parameter stepDecreasingPower of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setStepDecreasingPower */ + CV_WRAP virtual float getStepDecreasingPower() const = 0; + /** @copybrief getStepDecreasingPower @see getStepDecreasingPower */ + CV_WRAP virtual void setStepDecreasingPower(float stepDecreasingPower) = 0; /** @brief Termination criteria of the training algorithm. You can specify the maximum number of iterations (maxCount) and/or how much the error could diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 0f1efcfea..17feeff17 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -91,13 +91,13 @@ public: CV_IMPL_PROPERTY(int, SvmsgdType, params.svmsgdType) CV_IMPL_PROPERTY(int, MarginType, params.marginType) - CV_IMPL_PROPERTY(float, Lambda, params.lambda) - CV_IMPL_PROPERTY(float, Gamma0, params.gamma0) - CV_IMPL_PROPERTY(float, C, params.c) + CV_IMPL_PROPERTY(float, MarginRegularization, params.marginRegularization) + CV_IMPL_PROPERTY(float, InitialStepSize, params.initialStepSize) + CV_IMPL_PROPERTY(float, StepDecreasingPower, params.stepDecreasingPower) CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) private: - void updateWeights(InputArray sample, bool isPositive, float gamma, Mat &weights); + void updateWeights(InputArray sample, bool isPositive, float stepSize, Mat &weights); std::pair areClassesEmpty(Mat responses); @@ -122,9 +122,9 @@ private: // Parameters for learning struct SVMSGDParams { - float lambda; //regularization - float gamma0; //learning rate - float c; + float marginRegularization; + float initialStepSize; + float stepDecreasingPower; TermCriteria termCrit; int svmsgdType; int marginType; @@ -166,8 +166,7 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) average = Mat(1, featuresCount, samples.type()); for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) { - Scalar scalAverage = mean(samples.col(featureIndex)); - average.at(featureIndex) = static_cast(scalAverage[0]); + average.at(featureIndex) = static_cast(mean(samples.col(featureIndex))[0]); } for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) @@ -193,7 +192,7 @@ void SVMSGDImpl::makeExtendedTrainSamples(const Mat &trainSamples, Mat &extended cv::hconcat(normalizedTrainSamples, onesCol, extendedTrainSamples); } -void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, Mat& weights) +void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float stepSize, Mat& weights) { Mat sample = _sample.getMat(); @@ -202,18 +201,18 @@ void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, if ( sample.dot(weights) * response > 1) { // Not a support vector, only apply weight decay - weights *= (1.f - gamma * params.lambda); + weights *= (1.f - stepSize * params.marginRegularization); } else { // It's a support vector, add it to the weights - weights -= (gamma * params.lambda) * weights - (gamma * response) * sample; + weights -= (stepSize * params.marginRegularization) * weights - (stepSize * response) * sample; } } float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const { - float distanceToClasses[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; + float margin[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; Mat trainSamples = _samples.getMat(); int trainSamplesCount = trainSamples.rows; @@ -225,18 +224,18 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const Mat currentSample = trainSamples.row(samplesIndex); float dotProduct = static_cast(currentSample.dot(weights_)); - bool firstClass = isPositive(trainResponses.at(samplesIndex)); - int index = firstClass ? 0 : 1; - float signToMul = firstClass ? 1.f : -1.f; - float curDistance = dotProduct * signToMul; + bool positive = isPositive(trainResponses.at(samplesIndex)); + int index = positive ? 0 : 1; + float signToMul = positive ? 1.f : -1.f; + float curMargin = dotProduct * signToMul; - if (curDistance < distanceToClasses[index]) + if (curMargin < margin[index]) { - distanceToClasses[index] = curDistance; + margin[index] = curMargin; } } - return -(distanceToClasses[0] - distanceToClasses[1]) / 2.f; + return -(margin[0] - margin[1]) / 2.f; } bool SVMSGDImpl::train(const Ptr& data, int) @@ -292,9 +291,9 @@ bool SVMSGDImpl::train(const Ptr& data, int) Mat currentSample = extendedTrainSamples.row(randomNumber); - float gamma = params.gamma0 * std::pow((1 + params.lambda * params.gamma0 * (float)iter), (-params.c)); //update gamma + float stepSize = params.initialStepSize * std::pow((1 + params.marginRegularization * params.initialStepSize * (float)iter), (-params.stepDecreasingPower)); //update stepSize - updateWeights( currentSample, isPositive(trainResponses.at(randomNumber)), gamma, extendedWeights ); + updateWeights( currentSample, isPositive(trainResponses.at(randomNumber)), stepSize, extendedWeights ); //average weights (only for ASGD model) if (params.svmsgdType == ASGD) @@ -370,7 +369,7 @@ bool SVMSGDImpl::isClassifier() const && (params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN) && - (params.lambda > 0) && (params.gamma0 > 0) && (params.c >= 0); + (params.marginRegularization > 0) && (params.initialStepSize > 0) && (params.stepDecreasingPower >= 0); } bool SVMSGDImpl::isTrained() const @@ -423,9 +422,9 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const fs << "marginType" << marginTypeStr; - fs << "lambda" << params.lambda; - fs << "gamma0" << params.gamma0; - fs << "c" << params.c; + fs << "marginRegularization" << params.marginRegularization; + fs << "initialStepSize" << params.initialStepSize; + fs << "stepDecreasingPower" << params.stepDecreasingPower; fs << "term_criteria" << "{:"; if( params.termCrit.type & TermCriteria::EPS ) @@ -467,14 +466,14 @@ void SVMSGDImpl::readParams( const FileNode& fn ) params.marginType = marginType; - CV_Assert ( fn["lambda"].isReal() ); - params.lambda = (float)fn["lambda"]; + CV_Assert ( fn["marginRegularization"].isReal() ); + params.marginRegularization = (float)fn["marginRegularization"]; - CV_Assert ( fn["gamma0"].isReal() ); - params.gamma0 = (float)fn["gamma0"]; + CV_Assert ( fn["initialStepSize"].isReal() ); + params.initialStepSize = (float)fn["initialStepSize"]; - CV_Assert ( fn["c"].isReal() ); - params.c = (float)fn["c"]; + CV_Assert ( fn["stepDecreasingPower"].isReal() ); + params.stepDecreasingPower = (float)fn["stepDecreasingPower"]; FileNode tcnode = fn["term_criteria"]; if( !tcnode.empty() ) @@ -504,9 +503,9 @@ SVMSGDImpl::SVMSGDImpl() params.marginType = -1; // Parameters for learning - params.lambda = 0; // regularization - params.gamma0 = 0; // learning rate (ideally should be large at beginning and decay each iteration) - params.c = 0; + params.marginRegularization = 0; // regularization + params.initialStepSize = 0; // learning rate (ideally should be large at beginning and decay each iteration) + params.stepDecreasingPower = 0; TermCriteria _termCrit(TermCriteria::COUNT + TermCriteria::EPS, 0, 0); params.termCrit = _termCrit; @@ -520,9 +519,9 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) params.svmsgdType = SGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; - params.lambda = 0.0001f; - params.gamma0 = 0.05f; - params.c = 1.f; + params.marginRegularization = 0.0001f; + params.initialStepSize = 0.05f; + params.stepDecreasingPower = 1.f; params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; @@ -530,9 +529,9 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) params.svmsgdType = ASGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; - params.lambda = 0.00001f; - params.gamma0 = 0.05f; - params.c = 0.75f; + params.marginRegularization = 0.00001f; + params.initialStepSize = 0.05f; + params.stepDecreasingPower = 0.75f; params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp index 01f5568da..15ae20096 100644 --- a/modules/ml/test/test_mltests2.cpp +++ b/modules/ml/test/test_mltests2.cpp @@ -469,9 +469,9 @@ int CV_MLBaseTest::train( int testCaseIdx ) int marginType = str_to_margin_type( marginTypeStr ); m->setMarginType(marginType); - m->setLambda(modelParamsNode["lambda"]); - m->setGamma0(modelParamsNode["gamma0"]); - m->setC(modelParamsNode["c"]); + m->setMarginRegularization(modelParamsNode["marginRegularization"]); + m->setInitialStepSize(modelParamsNode["initialStepSize"]); + m->setStepDecreasingPower(modelParamsNode["stepDecreasingPower"]); m->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10000, 0.00001)); model = m; } diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 00ebbf334..31fd71729 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -200,7 +200,6 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) } float err = (float)errCount / testSamplesCount; - std::cout << "err " << err << std::endl; if ( err > precision ) { diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index a68f613b2..efcff01cb 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -28,7 +28,7 @@ struct Data bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift); //function finds two points for drawing line (wx = 0) -bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2], int width, int height); +bool findPointsForLine(const Mat &weights, float shift, Point points[], int width, int height); // function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) ) bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint); @@ -119,7 +119,7 @@ bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair< return false; } -bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2], int width, int height) +bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height) { if (weights.empty()) {