纯C++实现支持向量机SVM

1.前言

部分人,比如Python程序员或许早已听说过SVM。支持向量机(SVM)是一种十分重要的机器学习分类算法,本身是一种线性分类算法,但是由于加入了核技巧,使得SVM也可以进行非线性数据的分类;SVM本来是一种二分类分类器,但是可以扩展到多分类。在深度学习出现之前,SVM已经是当时最顶尖牛逼的算法。

2.对SVM的一些理解

想搞机器学习,请先看看《统计学习方法》这个经典著作。书中对于SVM的讲解已经很好了,请务必跟着一步一步推导,这样你就会发现整个SVM的推导过程无非就是以下几步:

  1. 将分类器建模成n维空间中的超平面,但是这个超平面有个很重要的选取原则,那就是让所有样本点到超平面的距离都尽量大,也就是让距离超平面最近的点到超平面的距离达到最大,于是得出了约束最大化问题。
  2. 将问题简化到只和决定超平面的参数w有关,使用熟悉的拉格朗日数乘法将约束最优化问题变成一个式子,然后转化为对偶问题。
  3. 求解对偶问题的最优解a,然后根据原问题和对偶问题的关系由a求出w,此时就得到SVM的参数了。

1,2步都是需要推导的,唯独涉及实现的地方是第3步,我们实现的重点变成了如何快速的得到最优解a(a可是有N个分量的,N为训练样本数)。于是SMO算法就出现了。

3.C++实现SVM

<code>//--------------------------------------【程序说明】-------------------------------------------
//\t\t程序描述:支持向量机SVM引导
//\t\t测试所用操作系统: Windows 10 64bit
//\t\t测试所用IDE版本:Visual Studio 2017
//\t\t开发测试所用OpenCV版本:\t3.4
//\t\t2020年3月 Revised by @DL小宝
//------------------------------------------------------------------------------------------------

//---------------------------------【头文件、命名空间包含部分】----------------------------
//\t\t描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <opencv2>
#include <opencv2>
#include <opencv2>
using namespace cv;

//OpenCV3需额外加入:
#include <opencv2>
#include "opencv2/imgcodecs.hpp"
using namespace cv::ml;

//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
\t//输出欢迎信息和OpenCV版本
\tprintf("\\n\\n\\t\\t\\t 当前使用的OpenCV版本为:" CV_VERSION);
\tprintf("\\n\\n ----------------------------------------------------------------------------\\n");
}

//-----------------------------------【main( )函数】--------------------------------------------
//\t\t描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main()
{

\t// 视觉表达数据的设置(Data for visual representation)
\tint width = 512, height = 512;
\tMat image = Mat::zeros(height, width, CV_8UC3);

\t//建立训练数据( Set up training data)
\tint labels[4] = { 1, -1, -1, -1 };
\tMat labelsMat(4, 1, CV_32SC1, labels);

\tfloat trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
\tMat trainingDataMat(4, 2, CV_32FC1, trainingData);

\tShowHelpText();

\t//设置支持向量机的参数(Set up SVM's parameters)
\tSVM::Params params;
\tparams.svmType = SVM::C_SVC;
\tparams.kernelType = SVM::LINEAR;
\tparams.termCrit = TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6);


\t// 训练支持向量机(Train the SVM)
\tPtr svm = StatModel::train(trainingDataMat, ROW_SAMPLE, labelsMat, params);

\tVec3b green(0, 255, 0), blue(255, 0, 0);
\t//显示由SVM给出的决定区域 (Show the decision regions given by the SVM)
\tfor (int i = 0; i < image.rows; ++i)
\t\tfor (int j = 0; j < image.cols; ++j)
\t\t{
\t\t\tMat sampleMat = (Mat_<float>(1, 2) << j, i);
\t\t\tfloat response = svm->predict(sampleMat);

\t\t\tif (response == 1)
\t\t\t\timage.at<vec3b>(i, j) = green;
\t\t\telse if (response == -1)
\t\t\t\timage.at<vec3b>(i, j) = blue;
\t\t}

\t//显示训练数据 (Show the training data)
\tint thickness = -1;
\tint lineType = 8;
\tcircle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType);
\tcircle(image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType);

\tcircle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);
\tcircle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType);

\t//显示支持向量 (Show support vectors)
\tthickness = 2;
\tlineType = 8;
\tMat sv = svm->getSupportVectors();

\tfor (int i = 0; i < sv.rows; ++i)
\t{
\t\tconst float* v = sv.ptr<float>(i);
\t\tcircle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
\t}
\timwrite("SVM.png", image); // 保存图像
\timshow("SVM Simple Example", image); // 显示图像
\twaitKey(0);
}/<float>/<vec3b>/<vec3b>/<float>
/<opencv2>/<opencv2>/<opencv2>/<opencv2>/<code>


分享到:


相關文章: