純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>


分享到:


相關文章: