依據機器學習算法如何學習數據可分為3類:
有監督學習:從有標簽的數據學習,得到模型參數,對測試數據正確分類;
無監督學習:沒有標簽,計算機自己尋找輸入數據可能的模型;
強化學習(reinforcement learning):計算機與動態環境交互,學習錯誤反饋達到更優的目的。
依據機器學習期望結果來分類:
分類:輸入被分為N個類別的一種;
回歸:輸出是連續值;如依據房子的大小,時間,位置來預測房子的價格;
聚類:使用無監督學習將輸入聚為N類;
密度估計(density estimation):找到輸入可能的分布;
以OpenCV的SVM為例:
支持向量機較其他傳統機器學習算法的優點:
1、小樣本,並不是說樣本的絕對數量少(實際上,對任何算法來說,更多的樣本幾乎總是能帶來更好的效果),而是說與問題的復雜度比起來,SVM算法要求的樣本數是相對比較少的。SVM解決問題的時候,和樣本的維數是無關的(甚至樣本是上萬維的都可以,這使得SVM很適合用來解決文本分類的問題,當然,有這樣的能力也因為引入了核函數)。
2、結構風險最小。(對問題真實模型的逼近與問題真實解之間的誤差,就叫做風險,更嚴格的說,誤差的累積叫做風險)。
3、非線性,是指SVM擅長應付樣本數據線性不可分的情況,主要通過松弛變量(也有人叫懲罰變量)和核函數技術來實現,這一部分是SVM的精髓。
SVM的精髓之一核函數:OpenCV提供了以下幾種
線性核函數:SVM::LINEAR,線性內核,沒有高維空間映射,速度快;
多項式核函數:SVM::POLY,gamma>0,coef(),degree;
徑向基核函數: SVM::RBF,比較好的選擇,gamma>0;
SIGMOD核函數:這個核讓人想起神經網絡和深度學習。。gamma,coef();
上面核中記錄了SVM使用的參數;見SVMParams();
C++: CvSVMParams::CvSVMParams(int svm_type, int kernel_type, double degree, double gamma, double coef0, double Cvalue, double nu, double p, CvMat* class_weights, CvTermCriteria term_crit)
svm_type:SVM類型:
1、CvSVM::C_SVC : C類支撐向量分類機。 n類分組 (n≥2),容許用異常值處罰因子C進行不完全分類。
2、CvSVM::NU_SVC : 類支撐向量分類機。n類似然不完全分類的分類器。參數為gamma代替C。
3、CvSVM::ONE_CLASS : 單分類器,所有的練習數據提取自同一個類里,然后SVM建樹了一個分界線以分別該類在特點空間中所占區域和其它類在特點空間中所占區域。
4、CvSVM::EPS_SVR : 用於回歸。練習集中的特征向量和擬合出來的超平面的間隔須要小於p。異常值處罰因子C被采取。
5、CvSVM::NU_SVR : 回歸機,gamma代替p
kernel_type:即上面所說的核函數類型;仔細看可以發現這兩個參數類型都是int,所以除了填這些宏一樣的名稱外也可以直接填1,2,3.。。。
degree,gamma,coef0,都是特定核函數使用的參數,上面有總結;
Cvalue:SVM類型(C_SVC/ EPS_SVR/ NU_SVR)的參數C。
nu:SVM類型(NU_SVC/ ONE_CLASS/ NU_SVR)的參數 gamma;
p:SVM類型(EPS_SVR)的參數
class_weights:C_SVC中的可選權重,賦給指定的類,乘以C后變成 class_weights*C;
term_crit:SVM的迭代終止條件,可以指定的公差和最大迭代次數。
不設置時使用默認初始值初始化各參數。
SVM的訓練函數有兩個,訓練的好壞直接影響學習結果,非常重要。
C++: bool CvSVM::train(const Mat& trainData, const Mat& responses, const Mat& varIdx=Mat(), const Mat& sampleIdx=Mat(), CvSVMParams params=CvSVMParams() )
C++: bool CvSVM::train_auto();
推薦第二個,因為能幫你優化參數啊!!!除非你自認調參能力出眾可選第一個!
訓練后就是預測了,SVM有以下三種形式:
C++: float CvSVM::predict(const Mat& sample, bool returnDFVal=false ) const
C++: float CvSVM::predict(const CvMat* sample, bool returnDFVal=false ) const
C++: float CvSVM::predict(const CvMat* samples, CvMat* results) const
sample: 須要預測的輸入樣本;samples: 須要預測的輸入樣本們,多個;
returnDFVal: 指定返回值類型。若值是true,則是一個2類分類問題;
results: 響應的樣本輸出猜測的響應;分類中返回的是標簽類別號;
來看一下OPENCV文檔的例子:
1 void TestSVM1() 2 { 3 4 int width = 512, height = 512; 5 Mat image = Mat::zeros(height, width, CV_8UC3); 6 7 // set up training data 8 float labels[4] = { 1.0, 1.0, -1.0, -1.0 }; 9 Mat labelsMat(4, 1, CV_32FC1, labels); 10 11 float trainingData[4][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 } }; 12 Mat trainingDataMat(4, 2, CV_32FC1, trainingData); 13 14 // set up SVM's parameters 15 CvSVMParams params; 16 params.svm_type = CvSVM::C_SVC; 17 params.kernel_type = CvSVM::LINEAR; 18 params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); 19 20 // train the svm 21 CvSVM SVM; 22 SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params); 23 24 Vec3b green(0, 255, 0), blue(255, 0, 0); 25 26 // show the decision region given by the SVM 27 for (int i = 0; i < image.rows; ++i) 28 { 29 for (int j = 0; j < image.cols; ++j) 30 { 31 Mat sampleMat = (Mat_<float>(1, 2) << i, j); 32 33 // predict 函數使用訓練好的SVM模型對一個輸入的樣本進行分類 34 float response = SVM.predict(sampleMat); 35 36 if (response == 1) 37 { 38 // 注意這里是(j,i),不是(i,j) 39 image.at<Vec3b>(j, i) = green; 40 } 41 else 42 { 43 // 同上 44 image.at<Vec3b>(j, i) = blue; 45 } 46 } 47 } 48 49 int thickness = -1; 50 int lineType = 8; 51 52 circle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType); 53 circle(image, Point(255, 10), 5, Scalar(0, 0, 0), thickness, lineType); 54 circle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType); 55 circle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType); 56 57 // show support vectors 58 thickness = 2; 59 lineType = 8; 60 61 // 獲得當前的支持向量的個數 62 int c = SVM.get_support_vector_count(); 63 64 for (int i = 0; i < c; ++i) 65 { 66 const float* v = SVM.get_support_vector(i); 67 circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType); 68 } 69 70 //imwrite("result.png", image); // save the image 71 72 imshow("SVM Simple Example", image); // show it to the user 73 waitKey(0); 74 return; 75 }
看代碼的label可以知道是一個二分類問題,輸入為四個點,核函數也是線性核。
結果:
四個點每個類才兩個點總覺得不夠看啊,筆者增加了點數還是二分類,分界面看上去好多了。
每個類6點,看上去分類更有規律了。
下次將介紹從文件訓練模型,使用更復雜的SVM模型~~