目的 html
原理 ios
上一篇文章,咱們推導出對於線性可分數據,最佳劃分超平面應知足: 函數
如今咱們想引入一些東西,來表示那些被錯分的數據點(好比噪點),對劃分的影響。 優化
如何來表示這些影響呢? ui
被錯分的點,離本身應當存在的區域越遠,就表明了,這個點「錯」得越嚴重。 spa
因此咱們引入,爲對應樣本離同類區域的距離。 .net
接下來的問題是,如何將這種錯的程度,轉換爲和原模型相同的度量呢? code
咱們再引入一個常量C,表示和原模型度量的轉換關係,用C對
進行加權和,來表徵錯分點對原模型的影響,這樣咱們獲得新的最優化問題模型: htm
關於參數C的選擇, 明顯的取決於訓練樣本的分佈狀況。 儘管並不存在一個廣泛的答案,可是記住下面幾點規則仍是有用的: blog
說白了,C的大小表徵了,錯分數據對原模型的影響程度。因而C越大,優化時越關注錯分問題。反之越關注可否產生一個較大間隔的超平面。
開始使用
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp> #define NTRAINING_SAMPLES 100 // 每類訓練樣本的數量 #define FRAC_LINEAR_SEP 0.9f // 線性可分部分的樣本組成比例 using namespace cv; using namespace std; int main(){ // 用於顯示的數據 const int WIDTH = 512, HEIGHT = 512; Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); /* 1. 隨即產生訓練數據 */ Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1); Mat labels (2*NTRAINING_SAMPLES, 1, CV_32FC1); RNG rng(100); // 生成隨即數 // 設置線性可分的訓練數據 int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES); // 生成分類1的隨機點 Mat trainClass = trainData.rowRange(0, nLinearSamples); // 點的x座標在[0, 0.4)之間 Mat c = trainClass.colRange(0, 1); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH)); // 點的y座標在[0, 1)之間 c = trainClass.colRange(1,2); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); // 生成分類2的隨機點 trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES); // 點的x座標在[0.6, 1]之間 c = trainClass.colRange(0 , 1); rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH)); // 點的y座標在[0, 1)之間 c = trainClass.colRange(1,2); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); /* 設置非線性可分的訓練數據 */ // 生成分類1和分類2的隨機點 trainClass = trainData.rowRange( nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples); // 點的x座標在[0.4, 0.6)之間 c = trainClass.colRange(0,1); rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH)); // 點的y座標在[0, 1)之間 c = trainClass.colRange(1,2); rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); /* 設置分類標籤 */ labels.rowRange( 0, NTRAINING_SAMPLES).setTo(1); // Class 1 labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2); // Class 2 /* 設置支持向量機參數 */ CvSVMParams params; params.svm_type = SVM::C_SVC; params.C = 0.1; params.kernel_type = SVM::LINEAR; params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6); /* 3. 訓練支持向量機 */ cout << "Starting training process" << endl; CvSVM svm; svm.train(trainData, labels, Mat(), Mat(), params); cout << "Finished training process" << endl; /* 4. 顯示劃分區域 */ Vec3b green(0,100,0), blue (100,0,0); for (int i = 0; i < I.rows; ++i) for (int j = 0; j < I.cols; ++j){ Mat sampleMat = (Mat_<float>(1,2) << i, j); float response = svm.predict(sampleMat); if (response == 1) I.at<Vec3b>(j, i) = green; else if (response == 2) I.at<Vec3b>(j, i) = blue; } /* 5. 顯示訓練數據 */ int thick = -1; int lineType = 8; float px, py; // 分類1 for (int i = 0; i < NTRAINING_SAMPLES; ++i){ px = trainData.at<float>(i,0); py = trainData.at<float>(i,1); circle(I, Point( (int) px, (int) py ), 3, Scalar(0, 255, 0), thick, lineType); } // 分類2 for (int i = NTRAINING_SAMPLES; i <2*NTRAINING_SAMPLES; ++i){ px = trainData.at<float>(i,0); py = trainData.at<float>(i,1); circle(I, Point( (int) px, (int) py ), 3, Scalar(255, 0, 0), thick, lineType); } /* 6. 顯示支持向量 */ thick = 2; lineType = 8; int x = svm.get_support_vector_count(); for (int i = 0; i < x; ++i) { const float* v = svm.get_support_vector(i); circle( I, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick, lineType); } imwrite("result.png", I); // 保存圖片 imshow("SVM線性不可分數據劃分", I); // 顯示給用戶 waitKey(0); }
設置SVM參數
這裏的參數設置能夠參考一下上一篇文章的API。
CvSVMParams params; params.svm_type = SVM::C_SVC; params.C = 0.1; params.kernel_type = SVM::LINEAR; params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6);
能夠看到,此次使用的是C類支持向量分類機。其參數C的值爲0.1。
結果
被山寨的原文
Support Vector Machines for Non-Linearly Separable Data . OpenCV.org