日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

SVM开发详解

發(fā)布時間:2025/7/25 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SVM开发详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

EasyPR--開發(fā)詳解(6)SVM開發(fā)詳解

時間?2015-02-02 10:31:00 博客園精華區(qū) 原文? http://www.cnblogs.com/subconscious/p/4249581.html 主題 支持向量機

在前面的幾篇文章中,我們介紹了EasyPR中車牌定位模塊的相關內(nèi)容。本文開始分析車牌定位模塊后續(xù)步驟的車牌判斷模塊。車牌判斷模塊是EasyPR中的基于機器學習模型的一個模塊,這個模型就是作者前文中從機器學習談起中提到的SVM(支持向量機)。

我們已經(jīng)知道,車牌定位模塊的輸出是一些候選車牌的圖片。但如何從這些候選車牌圖片中甄選出真正的車牌,就是通過SVM模型判斷/預測得到的。

圖1 從候選車牌中選出真正的車牌

簡單來說,EasyPR的車牌判斷模塊就是將候選車牌的圖片一張張地輸入到SVM模型中,然后問它,這是車牌么?如果SVM模型回答不是,那么就繼續(xù)下一張,如果是,則把圖片放到一個輸出列表里。最后把列表輸入到下一步處理。由于EasyPR使用的是列表作為輸出,因此它可以輸出一副圖片中所有的車牌,不像一些車牌識別程序,只能輸出一個車牌結(jié)果。

圖2 EasyPR輸出多個車牌

現(xiàn)在,讓我們一步步地,進入這個SVM模型的核心看看,它是如何做到判斷一副圖片是車牌還是不是車牌的?本文主要分為三個大的部分:

  • SVM應用:描述如何利用SVM模型進行車牌圖片的判斷。
  • SVM訓練:說明如何通過一系列步驟得到SVM模型。
  • SVM調(diào)優(yōu):討論如何對SVM模型進行優(yōu)化,使其效果更加好。
  • 一.SVM應用

    人類是如何判斷一個張圖片所表達的信息呢?簡單來說,人類在成長過程中,大腦記憶了無數(shù)的圖像,并且依次給這些圖像打上了標簽,例如太陽,天空,房子,車子等等。你們還記得當年上幼兒園時的那些教科書么,上面一個太陽,下面是文字。圖像的組成事實上就是許多個像素,由像素組成的這些信息被輸入大腦中,然后得出這個是什么東西的回答。我們在SVM模型中一開始輸入的原始信息也是圖像的所有像素,然后SVM模型通過對這些像素進行分析,輸出這個圖片是否是車牌的結(jié)論。

    圖3 通過圖像來學習

    SVM模型處理的是最簡單的情況,它只要回答是或者不是這個“二值”問題,比從許多類中檢索要簡單很多。

    我們可以看一下SVM進行判斷的代碼:

    int CPlateJudge::plateJudge(const vector<Mat>& inVec, vector<Mat>& resultVec) { int num = inVec.size(); for (int j = 0; j < num; j++) { Mat inMat = inVec[j]; Mat p = histeq(inMat).reshape(1, 1); p.convertTo(p, CV_32FC1); int response = (int)svm.predict(p); if (response == 1) { resultVec.push_back(inMat); } } return 0; } View Code

    首先我們讀取這幅圖片,然后把這幅圖片轉(zhuǎn)為OPENCV需要的格式;

    Mat p = histeq(inMat).reshape(1, 1);p.convertTo(p, CV_32FC1);

    接著調(diào)用svm的方法predict;

    int response = (int)svm.predict(p);

    perdict方法返回的值是1的話,就代表是車牌,否則就不是;

    if (response == 1){resultVec.push_back(inMat);}

    svm是類CvSVM的一個對象。這個類是opencv里內(nèi)置的一個機器學習類。

    CvSVM svm;

    opencv的CvSVM的實現(xiàn)基于libsvm(具體信息可以看opencv的官方文檔的 介紹 )。

    libsvm是臺灣大學林智仁(Lin Chih-Jen)教授寫的一個世界知名的svm庫(可能算是目前業(yè)界使用率最高的一個庫)。官方主頁地址是 這里 。

    libsvm的實現(xiàn)基于SVM這個算法,90年代初由Vapnik等人提出。國內(nèi)幾篇較好的解釋svm原理的博文:cnblog的LeftNotEasy(解釋的易懂),pluskid的 博文 (專業(yè)有配圖)。

    作為支持向量機的發(fā)明者,Vapnik是一位機器學習界極為重要的大牛。 最近這位大牛也加入了Facebook 。

    圖4 SVM之父Vapnik

    svm的perdict方法的輸入是待預測數(shù)據(jù)的特征,也稱之為features。在這里,我們輸入的特征是圖像全部的像素。由于svm要求輸入的特征應該是一個向量,而Mat是與圖像寬高對應的矩陣,因此在輸入前我們需要使用reshape(1,1)方法把矩陣拉伸成向量。除了全部像素以外,也可以有其他的特征,具體看第三部分“SVM調(diào)優(yōu)”。

    predict方法的輸出是float型的值,我們需要把它轉(zhuǎn)變?yōu)閕nt型后再進行判斷。如果是1代表就是車牌,否則不是。這個"1"的取值是由你在訓練時輸入的標簽決定的。標簽,又稱之為label,代表某個數(shù)據(jù)的分類。如果你給SVM模型輸入一個車牌,并告訴它,這個圖片的標簽是5。那么你這邊判斷時所用的值就應該是5。

    以上就是svm模型判斷的全過程。事實上,在你使用EasyPR的過程中,這些全部都是透明的。你不需要轉(zhuǎn)變圖片格式,也不需要調(diào)用svm模型preditct方法,這些全部由EasyPR在內(nèi)部調(diào)用。

    那么,我們應該做什么?這里的關鍵在于CvSVM這個類。我在前面的機器學習論文中介紹過,機器學習過程的步驟就是首先你搜集大量的數(shù)據(jù),然后把這些數(shù)據(jù)輸入模型中訓練,最后再把生成的模型拿出來使用。

    訓練和預測兩個過程是分開的。也就是說你們在使用EasyPR時用到的CvSVM類是我在先前就訓練好的。我是如何把我訓練好的模型交給各位使用的呢?CvSVM類有個方法,把訓練好的結(jié)果以xml文件的形式存儲,我就是把這個xml文件隨EasyPR發(fā)布,并讓程序在執(zhí)行前先加載好這個xml。這個xml的位置就是在文件夾Model下面--svm.xml文件。

    圖5 model文件夾下的svm.xml

    如果看CPlateJudge的代碼,在構(gòu)造函數(shù)中調(diào)用了LoadModel()這個方法。

    CPlateJudge::CPlateJudge() {//cout << "CPlateJudge" << endl;m_path = "model/svm.xml";LoadModel(); }

    LoadModel()方法的主要任務就是裝載model文件夾下svm.xml這個模型。

    void CPlateJudge::LoadModel() {svm.clear();svm.load(m_path.c_str(), "svm"); }

    如果你把這個xml文件換成其他的,那么你就可以改變EasyPR車牌判斷的內(nèi)核,從而實現(xiàn)你自己的車牌判斷模塊。

    后面的部分全部是告訴你如何有效地實現(xiàn)一個自己的模型(也就是svm.xml文件)。如果你對EasyPR的需求僅僅在應用層面,那么到目前的了解就足夠了。如果你希望能夠改善EasyPR的效果,定制一個自己的車牌判斷模塊,那么請繼續(xù)往下看。

    二.SVM訓練

    恭喜你!從現(xiàn)在開始起,你將真正踏入機器學習這個神秘并且充滿未知的領域。至今為止,機器學習很多方法的背后原理都非常復雜,但眾多的實踐都證明了其有效性。與許多其他學科不同,機器學習界更為關注的是最終方法的效果,也就是偏重以實踐效果作為評判標準。因此非常適合從工程的角度入手,通過自己動手實踐一個項目里來學習,然后再轉(zhuǎn)入理論。這個過程已經(jīng)被證明是 有效 的,本文的作者在開發(fā)EasyPR的時候,還沒有任何機器學習的理論基礎。后來的知識是將通過學習相關課程后獲取的。

    簡而言之,SVM訓練部分的目標就是通過一批數(shù)據(jù),然后生成一個代表我們模型的xml文件。

    EasyPR中所有關于訓練的方法都可以在 svm_train.cpp 中找到(1.0版位于train/code文件夾下,1.1版位于src/train文件夾下)。

    一個訓練過程包含5個步驟,見下圖:

    圖6 一個完整的SVM訓練流程

    下面具體講解一下這5個步驟,步驟后面的括號里代表的是這個步驟主要的輸入與輸出。

    1. preprocss(原始數(shù)據(jù)->學習數(shù)據(jù)(未標簽))

    預處理步驟主要處理的是原始數(shù)據(jù)到學習數(shù)據(jù)的轉(zhuǎn)換過程。原始數(shù)據(jù)(raw data),表示你一開始拿到的數(shù)據(jù)。這些數(shù)據(jù)的情況是取決你具體的環(huán)境的,可能有各種問題。學習數(shù)據(jù)(learn data),是可以被輸入到模型的數(shù)據(jù)。

    為了能夠進入模型訓練,必須將原始數(shù)據(jù)處理為學習數(shù)據(jù),同時也可能進行了數(shù)據(jù)的篩選。比方說你有10000張原始圖片,出于性能考慮,你只想用1000張圖片訓練,那么你的預處理過程就是將這10000張?zhí)幚頌榉嫌柧氁蟮?000張。你生成的1000張圖片中應該包含兩類數(shù)據(jù):真正的車牌圖片和不是車牌的圖片。如果你想讓你的模型能夠區(qū)分這兩種類型。你就必須給它輸入這兩類的數(shù)據(jù)。

    通過EasyPR的車牌定位模塊PlateLocate可以生成大量的候選車牌圖片,里面包括模型需要的車牌和非車牌圖片。但這些候選車牌是沒有經(jīng)過分類的,也就是說沒有標簽。下步工作就是給這些數(shù)據(jù)貼上標簽。

    2. label(學習數(shù)據(jù)(未標簽)->學習數(shù)據(jù))

    訓練過程的第二步就是將未貼標簽的數(shù)據(jù)轉(zhuǎn)化為貼過標簽的學習數(shù)據(jù)。我們所要做的工作只是將車牌圖片放到一個文件夾里,非車牌圖片放到另一個文件夾里。在EasyPR里,這兩個文件夾分別叫做HasPlate和NoPlate。如果你打開train/data/plate_detect_svm后,你就會看到這兩個壓縮包,解壓后就是打好標簽的數(shù)據(jù)(1.1版本在同層learn data文件夾下面)。

    如果有人問我開發(fā)一個機器學習系統(tǒng)最耗時的步驟是哪個,我會毫不猶豫的回答:“貼標簽”。誠然,各位看到的壓縮包里已經(jīng)有打好標簽的數(shù)據(jù)了。但各位可能不知道作者花在貼這些標簽上的時間。粗略估計,整個EasyPR開發(fā)過程中有70%的時間都在貼標簽。SVM模型還好,只有兩個類,訓練數(shù)據(jù)僅有1000張。到了ANN模型那里,字符的類數(shù)有40多個,而且訓練數(shù)據(jù)有4000張左右。那時候的貼標簽過程,真是不堪回首的回憶,來回移動文件導致作者手經(jīng)常性的非常酸。后來我一度想找個實習生幫我做這些工作。但轉(zhuǎn)念一想,這些苦我都不愿承擔,何苦還要那些小伙子承擔呢。“己所不欲,勿施于人”。算了,既然這是機器學習者的命,那就欣然接受吧。幸好在這段磨礪的時光,我逐漸掌握了一個方法,大幅度減少了我貼標簽的時間與精力。不然,我可能還未開始寫這個系列的教程,就已經(jīng)累吐血了。開發(fā)EasyPR1.1版本時,新增了一大批數(shù)據(jù),因此又有了貼標簽的過程。幸好使用這個方法,使得相關時間大幅度減少。這個方法叫做 逐次迭代自動標簽法 。在后面會介紹這個方法。

    貼標簽后的車牌數(shù)據(jù)如下圖:

    圖7 在HasPlate文件夾下的圖片

    貼標簽后的非車牌數(shù)據(jù)下圖:

    圖8 在NoPlate文件夾下的圖片

    擁有了貼好標簽的數(shù)據(jù)以后,下面的步驟是分組,也稱之為divide過程。

    3. divide(學習數(shù)據(jù)->分組數(shù)據(jù))

    分組這個過程是EasyPR1.1版新引入的方法。

    在貼完標簽以后,我擁有了車牌圖片和非車牌圖片共幾千張。在我直接訓練前,不急。先拿出30%的數(shù)據(jù),只用剩下的70%數(shù)據(jù)進行SVM模型的訓練,訓練好的模型再用這30%數(shù)據(jù)進行一個效果測試。這30%數(shù)據(jù)充當?shù)淖饔镁褪且粋€評判數(shù)據(jù)測試集,稱之為test data,另70%數(shù)據(jù)稱之為train data。于是一個完整的learn data被分為了train data和test data。

    圖9 數(shù)據(jù)分組過程

    在EasyPR1.0版是沒有test data概念的,所有數(shù)據(jù)都輸入訓練,然后直接在原始的數(shù)據(jù)上進行測試。直接在原始的數(shù)據(jù)集上測試與單獨劃分出30%的數(shù)據(jù)測試效果究竟有多少不同?

    事實上,我們訓練出模型的根本目的是為了對未知的,新的數(shù)據(jù)進行預測與判斷。

    當使用訓練的數(shù)據(jù)進行測試時,由于模型已經(jīng)考慮到了訓練數(shù)據(jù)的特征,因此很難將這個測試效果推廣到其他未知數(shù)據(jù)上。如果使用單獨的測試集進行驗證,由于測試數(shù)據(jù)集跟模型的生成沒有關聯(lián),因此可以很好的反映出模型推廣到其他場景下的效果。 這個過程就可以簡單描述為你不可以拿你給學生的復習提綱卷去考學生,而是應該出一份考察知識點一樣,但題目不一樣的卷子。前者的方式無法區(qū)分出真正學會的人和死記硬背的人,而后者就能有效地反映出哪些人才是真正“學會”的。

    在divide的過程中,注意無論在train data和test data中都要保持數(shù)據(jù)的標簽,也就是說車牌數(shù)據(jù)仍然歸到HasPlate文件夾,非車牌數(shù)據(jù)歸到NoPlate文件夾。于是,車牌圖片30%歸到test data下面的hasplate文件夾,70%歸到train data下面的hasplate文件夾,非車牌圖片30%歸到test data下面的noplate文件夾,70%歸到train data下面的noplate文件夾。于是在文件夾train 和 test下面又有兩個子文件夾,他們的結(jié)構(gòu)樹就是下圖:

    圖10 分組后的文件樹

    divide數(shù)據(jù)結(jié)束以后,我們就可以進入真正的機器學習過程。也就是對數(shù)據(jù)的訓練過程。

    4. train(訓練數(shù)據(jù)->模型)

    模型在代碼里的代表就是CvSVM類。在這一步中所要做的就是加載train data,然后用CvSVM類的train方法進行訓練。這個步驟只針對的是上步中生成的總數(shù)據(jù)70%的訓練數(shù)據(jù)。

    具體來說,分為以下幾個子步驟:

    1) 加載待訓練的車牌數(shù)據(jù)。見下面這段代碼。

    void getPlate(Mat& trainingImages, vector<int>& trainingLabels) { char * filePath = "train/data/plate_detect_svm/HasPlate/HasPlate"; vector<string> files; getFiles(filePath, files ); int size = files.size(); if (0 == size) cout << "No File Found in train HasPlate!" << endl; for (int i = 0;i < size;i++) { cout << files[i].c_str() << endl; Mat img = imread(files[i].c_str()); img= img.reshape(1, 1); trainingImages.push_back(img); trainingLabels.push_back(1); } } View Code

    注意看,車牌圖像我存儲在的是一個vector<Mat>中,而標簽數(shù)據(jù)我存儲在的是一個vector<int>中。我將train/HasPlate中的圖像依次取出來,存入vector<Mat>。每存入一個圖像,同時也往vector<int>中存入一個int值1,也就是說圖像和標簽分別存在不同的vector對象里,但是保持一一對應的關系。

    2) 加載待訓練的非車牌數(shù)據(jù),見下面這段代碼中的函數(shù)。基本內(nèi)容與加載車牌數(shù)據(jù)類似,不同之處在于文件夾是train/NoPlate,并且我往vector<int>中存入的是int值0,代表無車牌。

    void getNoPlate(Mat& trainingImages, vector<int>& trainingLabels) { char * filePath = "train/data/plate_detect_svm/NoPlate/NoPlate"; vector<string> files; getFiles(filePath, files ); int size = files.size(); if (0 == size) cout << "No File Found in train NoPlate!" << endl; for (int i = 0;i < size;i++) { cout << files[i].c_str() << endl; Mat img = imread(files[i].c_str()); img= img.reshape(1, 1); trainingImages.push_back(img); trainingLabels.push_back(0); } } View Code

    3) 將兩者合并。目前擁有了兩個vector<Mat>和兩個vector<int>。將代表車牌圖片和非車牌圖片數(shù)據(jù)的兩個vector<Mat>組成一個新的Mat--trainingData,而代表車牌圖片與非車牌圖片標簽的兩個vector<int>組成另一個Mat--classes。接著做一些數(shù)據(jù)類型的調(diào)整,以讓其符合svm訓練函數(shù)train的要求。這些做完后,數(shù)據(jù)的準備工作基本結(jié)束,下面就是參數(shù)配置的工作。

    Mat classes;//(numPlates+numNoPlates, 1, CV_32FC1); Mat trainingData;//(numPlates+numNoPlates, imageWidth*imageHeight, CV_32FC1 ); Mat trainingImages; vector<int> trainingLabels; getPlate(trainingImages, trainingLabels); getNoPlate(trainingImages, trainingLabels); Mat(trainingImages).copyTo(trainingData); trainingData.convertTo(trainingData, CV_32FC1); Mat(trainingLabels).copyTo(classes); View Code

    4) 配置SVM模型的訓練參數(shù)。SVM模型的訓練需要一個CvSVMParams的對象,這個類是SVM模型中訓練對象的參數(shù)的組合,如何給這里的參數(shù)賦值,是很有講究的一個工作。注意,這里是SVM訓練的核心內(nèi)容,也是最能體現(xiàn)一個機器學習專家和新手區(qū)別的地方。機器學習最后模型的效果差異有很大因素取決與模型訓練時的參數(shù),尤其是SVM,有非常多的參數(shù)供你配置(見下面的代碼)。參數(shù)眾多是一個問題,更為顯著的是,機器學習模型中參數(shù)的一點微調(diào)都可能帶來最終結(jié)果的巨大差異。

    CvSVMParams SVM_params; SVM_params.svm_type = CvSVM::C_SVC; SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR; SVM_params.degree = 0; SVM_params.gamma = 1; SVM_params.coef0 = 0; SVM_params.C = 1; SVM_params.nu = 0; SVM_params.p = 0; SVM_params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, 0.01);

    opencv官網(wǎng)文檔對CvSVMParams類的各個參數(shù)有一個詳細的解釋。如果你上過SVM課程的理論部分,你可能對這些參數(shù)的意思能搞的明白。但在這里,我們可以不去管參數(shù)的含義,因為我們有更好的方法去解決這個問題。

    圖11 SVM各參數(shù)的作用

    這個原因在于:EasyPR1.0使用的是liner核,也稱之為線型核,因此degree和gamma還有coef0三個參數(shù)沒有作用。同時,在這里SVM模型用作的問題是分類問題,那么nu和p兩個參數(shù)也沒有影響。最后唯一能影響的參數(shù)只有Cvalue。到了EasyPR1.1版本以后,默認使用的是RBF核,因此需要調(diào)整的參數(shù)多了一個gamma。

    以上參數(shù)的選擇都可以用自動訓練(train_auto)的方法去解決,在下面的SVM調(diào)優(yōu)部分會具體介紹train_auto。

    5) 開始訓練。OK!數(shù)據(jù)載入完畢,參數(shù)配置結(jié)束,一切準備就緒,下面就是交給opencv的時間。我們只要將前面的 trainingData,classes,以及CvSVMParams的對象SVM_params交給CvSVM類的train函數(shù)就可以。另外,直接使用CvSVM的構(gòu)造函數(shù),也可以完成訓練過程。例如下面這行代碼:

    CvSVM svm(trainingData, classes, Mat(), Mat(), SVM_params);

    訓練開始后,慢慢等一會。機器學習中數(shù)據(jù)訓練的計算量往往是非常大的,即便現(xiàn)代計算機也要運行很長時間。具體的時間取決于你訓練的數(shù)據(jù)量的大小以及模型的復雜度。在我的2.0GHz的機器上,訓練1000條數(shù)據(jù)的SVM模型的時間大約在1分鐘左右。

    訓練完成以后,我們就可以用CvSVM類的對象

    s vm

    去進行預測了。如果我們僅僅需要這個模型,現(xiàn)在可以把它存到xml文件里,留待下次使用:

    FileStorage fsTo("train/svm.xml", cv::FileStorage::WRITE);svm.write(*fsTo, "svm");

    5. test(測試數(shù)據(jù)->評判指標)

    記得我們還有30%的測試數(shù)據(jù)了么?現(xiàn)在是使用它們的時候了。將這些數(shù)據(jù)以及它們的標簽加載如內(nèi)存,這個過程與加載訓練數(shù)據(jù)的過程是一樣的。接著使用我們訓練好的SVM模型去判斷這些圖片。

    下面的步驟是對我們的模型做指標評判的過程。首先,測試數(shù)據(jù)是有標簽的數(shù)據(jù),這意味著我們知道每張圖片是車牌還是不是車牌。另外,用新生成的svm模型對數(shù)據(jù)進行判斷,也會生成一個標簽,叫做“預測標簽”。“預測標簽”與“標簽”一般是存在誤差的,這也就是模型的誤差。這種誤差有兩種情況:1.這副圖片是真的車牌,但是svm模型判斷它是“非車牌”;2.這幅圖片不是車牌,但svm模型判斷它是“車牌”。無疑,這兩種情況都屬于svm模型判斷失誤的情況。我們需要設計出來兩個指標,來分別評測這兩種失誤情況發(fā)生的概率。這兩個指標就是下面要說的“準確率”(precision)和“查全率”(recall)。

    準確率是統(tǒng)計在我已經(jīng)預測為車牌的圖片中,真正車牌數(shù)據(jù)所占的比例。假設我們用ptrue_rtrue表示預測(p)為車牌并且實際(r)為車牌的數(shù)量,而用ptrue_rfalse表示實際不為車牌的數(shù)量。

    準確率的計算公式是:

    圖12 precise 準確率

    查全率是統(tǒng)計真正的車牌圖片中,我預測為車牌的圖片所占的比例。同上,我們用ptrue_rtrue表示預測與實際都為車牌的數(shù)量。用pfalse_rtrue表示實際為車牌,但我預測為非車牌的數(shù)量。

    查全率的計算公式是:

    圖13 recall 查全率

    recall的公式與precision公式唯一的區(qū)別在于右下角。precision是ptrue_rfalse,代表預測為車牌但實際不是的數(shù)量;而recall是pfalse_rtrue,代表預測是非車牌但其實是車牌的數(shù)量。

    簡單來說,precision指標的期望含義就是要“ 查的準 ”,recall的期望含義就是“ 不要漏 ”。查全率還有一個翻譯叫做“召回率”。但很明顯,召回這個詞沒有反映出查全率所體現(xiàn)出的不要漏的含義。

    值得說明的是,precise和recall這兩個值自然是越高越好。但是如果一個高,一個低的話效果會如何,如何跟兩個都中等的情況進行比較?為了能夠數(shù)字化這種比較。機器學習界又引入了FScore這個數(shù)值。當precise和recall兩者中任一者較高,而另一者較低是,FScore都會較低。兩者中等的情況下Fscore表現(xiàn)比一高一低要好。當兩者都很高時,FScore會很高。

    FScore的計算公式如下圖:

    圖14 Fscore計算公式

    模型測試以及評價指標是EasyPR1.1中新增的功能。在 svm_train.cpp 的最下面可以看到這三個指標的計算過程。

    訓練心得

    通過以上5個步驟,我們就完成了模型的準備,訓練,測試的全部過程。下面,說一說過程中的幾點心得。

    1. 完善EasyPR的plateLocate功能

    在1.1版本中的EasyPR的車牌定位模塊仍然不夠完善。如果你的所有的圖片符合某種通用的模式,參照前面的車牌定位的幾篇教程,以及使用EasyPR新增的Debug模式,你可以將EasyPR的plateLocate模塊改造為適合你的情況。于是,你就可以利用EasyPR為你制造大量的學習數(shù)據(jù)。通過原始數(shù)據(jù)的輸入,然后通過plateLocate進行定位,再使用EasyPR已有的車牌判斷模塊進行圖片的分類,于是你就可以得到一個基本分好類的學習數(shù)據(jù)。下面所需要做的就是人工核對,確認一下,保證每張圖片的標簽是正確的,然后再輸入模型進行訓練。

    2. 使用“逐次迭代自動標簽法”。

    上面討論的貼標簽方法是在EasyPR已經(jīng)提供了一個訓練好的模型的情況下。如果一開始手上任何模型都沒有,該怎么辦?假設目前手里有成千上萬個通過定位出來的各種候選車牌,手工一個個貼標簽的話,豈不會讓人累吐血?在前文中說過,我在一開始貼標簽過程中碰到了這個問題,在不斷被折磨與痛苦中,我發(fā)現(xiàn)了一個好方法,大幅度減輕了這整個工作的痛苦性。

    當然,這個方法很簡單。我如果說出來你一定也不覺得有什么奇妙的。但是如果在你準備對1000張圖片進行手工貼標簽時,相信我,使用這個方法會讓你最后的時間節(jié)省一半。如果你需要雇10個人來貼標簽的話,那么用了這個方法,可能你最后一個人都不用雇。

    這個方法被我稱為“逐次迭代自動標簽法”。

    方法核心很簡單。就是假設你有3000張未分類的圖片。你從中選出1%,也就是30張出來,手工給它們每個圖片進行分類工作。好的,如今你有了30張貼好標簽的數(shù)據(jù)了,下步你把它直接輸入到SVM模型中訓練,獲得了一個簡單粗曠的模型。之后,你從圖片集中再取出3%的圖片,也就是90張, 然后用剛訓練好的模型對這些圖片進行預測 ,根據(jù)預測結(jié)果將它們自動分到hasplate和noplate文件夾下面。分完以后,你到這兩個文件夾下面,看看哪些是預測錯的,把hasplate里預測錯的 移動 到noplate里,反之,把noplate里預測錯的移動到hasplate里。

    接著,你把一開始手工分類好的那30張圖片,結(jié)合調(diào)整分類的90張圖片,總共120張圖片再輸入svm模型中進行訓練。于是你獲得一個比最開始粗曠模型更精準點的模型。然后,你從3000張圖片中再取出6%的圖片來,用這個模型再對它們進行預測,分類....

    以上反復。你每訓練出一個新模型,用它來預測后面更多的數(shù)據(jù),然后自動分類。這樣做最大的好處就是你只需要移動那些被分類錯誤的圖片。其他的圖片已經(jīng)被正 確的歸類了。注意,在整個過程中,你每次只需要對新拿出的數(shù)據(jù)進行人工確認,因為前面的數(shù)據(jù)已經(jīng)分好類了。因此,你最好使用兩個文件夾,一個是已經(jīng)分好類 的數(shù)據(jù),另一個是自動分類數(shù)據(jù),需要手工確認的。這樣兩者不容易亂。

    每次從未標簽的原始數(shù)據(jù)庫中取出的數(shù)據(jù)不要多,最好不要超過上次數(shù)據(jù)的兩倍。這樣可以保證你的模型的準確率穩(wěn)步上升。如果想一口吃個大胖子,例如用30張圖片訓練出的模型,去預測1000張數(shù)據(jù),那最后結(jié)果跟你手工分類沒有任何區(qū)別了。

    整個方法的原理很簡單,就是 不斷迭代循環(huán)細化 的思想。跟軟件工程中迭代開發(fā)過程有異曲同工之妙。你只要理解了其原理,很容易就可以復用在任何其他機器學習模型的訓練中,從而大幅度(或者部分)減輕機器學習過程中貼標簽的巨大負擔。

    回到一個核心問題,對于開發(fā)者而言,什么樣的方法才是自己實現(xiàn)一個svm.xml的最好方法。有以下幾種選擇。

    1.你使用EasyPR提供的svm.xml,這個方式等同于你沒有訓練,那么EasyPR識別的效率取決于你的環(huán)境與EasyPR的匹配度。運氣好的話,這個效果也會不錯。但如果你的環(huán)境下車牌跟EasyPR默認的不一樣。那么可能就會有點問題。

    2.使用EasyPR提供的訓練數(shù)據(jù),例如train/data文件下的數(shù)據(jù),這樣生成的效果等同于第一步的,不過你可以調(diào)整參數(shù),試試看模型的表現(xiàn)會不會更好一點。

    3.使用自己的數(shù)據(jù)進行訓練。這個方法的適應性最好。首先你得準備你原始的數(shù)據(jù),并且寫一個處理方法,能夠?qū)⒃紨?shù)據(jù)轉(zhuǎn)化為學習數(shù)據(jù)。下面你調(diào)用EasyPR的PlateLocate方法進行處理,將候選車牌圖片從原圖片截取出來。你可以使用逐次迭代自動標簽思想,使用EasyPR已有的svm模型對這些候選圖片進行預標簽。然后再進行肉眼確認和手工調(diào)整,以生成標準的貼好標簽的數(shù)據(jù)。后面的步驟就可以按照分組,訓練,測試等過程順次走下去。如果你使用了EasyPR1.1版本,后面的這幾個過程已經(jīng)幫你實現(xiàn)好代碼了,你甚至可以直接在命令行選擇操作。

    以上就是SVM模型訓練的部分,通過這個步驟的學習,你知道如何通過已有的數(shù)據(jù)去訓練出一個自己的模型。下面的部分,是對這個訓練過程的一個思考,討論通過何種方法可以改善我最后模型的效果。

    三.SVM調(diào)優(yōu)

    SVM調(diào)優(yōu)部分,是通過對SVM的原理進行了解,并運用機器學習的一些調(diào)優(yōu)策略進行優(yōu)化的步驟。

    在這個部分里,最好要懂一點機器學習的知識。同時,本部分也會講的盡量通俗易懂,讓人不會有理解上的負擔。在EasyPR1.0版本中,SVM模型的代碼完全參考了mastering opencv書里的實現(xiàn)思路。從1.1版本開始,EasyPR對車牌判斷模塊進行了優(yōu)化,使得模型最后的效果有了較大的改善。

    具體說來,本部分主要包括如下幾個子部分:1.RBF核;2.參數(shù)調(diào)優(yōu);3.特征提取;4.接口函數(shù);5.自動化。

    下面分別對這幾個子部分展開介紹。

    1.RBF核

    SVM中最關鍵的技巧是核技巧。“核”其實是一個函數(shù),通過一些轉(zhuǎn)換規(guī)則把低維的數(shù)據(jù)映射為高維的數(shù)據(jù)。在機器學習里,數(shù)據(jù)跟向量是等同的意思。例如,一個 [174, 72]表示人的身高與體重的數(shù)據(jù)就是一個兩維的向量。在這里,維度代表的是向量的長度。(務必要區(qū)分“維度”這個詞在不同語境下的含義,有的時候我們會說向量是一維的,矩陣是二維的,這種說法針對的是數(shù)據(jù)展開的層次。機器學習里講的維度代表的是向量的長度,與前者不同)

    簡單來說,低維空間到高維空間映射帶來的好處就是可以利用高維空間的線型切割模擬低維空間的非線性分類效果。也就是說,SVM模型其實只能做線型分類,但是在線型分類前,它可以通過核技巧把數(shù)據(jù)映射到高維,然后在高維空間進行線型切割。高維空間的線型切割完后在低維空間中最后看到的效果就是劃出了一條復雜的分線型分類界限。 從這點來看,SVM并沒有完成真正的非線性分類,而是通過其它方式達到了類似目的,可謂“曲徑通幽”。

    SVM模型總共可以支持多少種核呢。根據(jù)官方文檔,支持的核類型有以下幾種:

  • liner核,也就是無核。
  • rbf核,使用的是高斯函數(shù)作為核函數(shù)。
  • poly核,使用多項式函數(shù)作為核函數(shù)。
  • sigmoid 核,使用sigmoid函數(shù)作為核函數(shù)。
  • liner核和rbf核是所有核中應用最廣泛的。

    liner核,雖然名稱帶核,但它其實是無核模型,也就是沒有使用核函數(shù)對數(shù)據(jù)進行轉(zhuǎn)換。因此,它的分類效果僅僅比邏輯回歸好一點。在EasyPR1.0版中,我們的SVM模型應用的是liner核。我們用的是圖像的全部像素作為特征。

    rbf核,會將輸入數(shù)據(jù)的特征維數(shù)進行一個維度轉(zhuǎn)換,具體會轉(zhuǎn)換為多少維?這個等于你輸入的訓練量。假設你有500張圖片,rbf核會把每張圖片的數(shù)據(jù)轉(zhuǎn) 換為500維的。如果你有1000張圖片,rbf核會把每幅圖片的特征轉(zhuǎn)到1000維。這么說來,隨著你輸入訓練數(shù)據(jù)量的增長,數(shù)據(jù)的維數(shù)越多。更方便在高維空間下的分類效果,因此最后模型效果表現(xiàn)較好。

    既然選擇SVM作為模型,而且SVM中核心的關鍵技巧是核函數(shù),那么理應使用帶核的函數(shù)模型,充分利用數(shù)據(jù)高維化的好處,利用高維的線型分類帶來低維空間下的非線性分類效果。但是,rbf核的使用是需要條件的。

    當你的數(shù)據(jù)量很大,但是每個數(shù)據(jù)量的維度一般時,才適合用rbf核。相反,當你的數(shù)據(jù)量不多,但是每個數(shù)據(jù)量的維數(shù)都很大時,適合用線型核。

    在EasyPR1.0版中,我們用的是圖像的全部像素作為特征,那么根據(jù)車牌圖像的136×36的大小來看的話,就是4896維的數(shù)據(jù),再加上我們輸入的 是彩色圖像,也就是說有R,G,B三個通道,那么數(shù)量還要乘以3,也就是14688個維度。這是一個非常龐大的數(shù)據(jù)量,你可以把每幅圖片的數(shù)據(jù)理解為長度 為14688的向量。這個時候,每個數(shù)據(jù)的維度很大,而數(shù)據(jù)的總數(shù)很少,如果用rbf核的話,相反效果反而不如無核。

    在EasyPR1.1版本時,輸入訓練的數(shù)據(jù)有3000張圖片,每個數(shù)據(jù)的特征改用直方統(tǒng)計,共有172個維度。這個場景下,如果用rbf核的話,就會將每個數(shù)據(jù)的維度轉(zhuǎn)化為與數(shù)據(jù)總數(shù)一樣的數(shù)量,也就是3000的維度,可以充分利用數(shù)據(jù)高維化后的好處。

    因此可以看出,為了讓EasyPR新版使用rbf核技巧,我們給訓練數(shù)據(jù)做了增加,擴充了兩倍的數(shù)據(jù),同時,減小了每個數(shù)據(jù)的維度。以此滿足了rbf核的使用條件。通過使用rbf核來訓練,充分發(fā)揮了非線性模型分類的優(yōu)勢,因此帶來了較好的分類效果。

    但是,使用rbf核也有一個問題,那就是參數(shù)設置的問題。在rbf訓練的過程中,參數(shù)的選擇會顯著的影響最后rbf核訓練出模型的效果。因此必須對參數(shù)進行最優(yōu)選擇。

    2.參數(shù)調(diào)優(yōu)

    傳統(tǒng)的參數(shù)調(diào)優(yōu)方法是人手完成的。機器學習工程師觀察訓練出的模型與參數(shù)的對應關系,不斷調(diào)整,尋找最優(yōu)的參數(shù)。由于機器學習工程師大部分時間在調(diào)整模型的參數(shù),也有了“ 機器學習就是調(diào)參 ”這個說法。

    幸好,opencv的svm方法中提供了一個自動訓練的方法。也就是由opencv幫你,不斷改變參數(shù),訓練模型,測試模型,最后選擇模型效果最好的那些參數(shù)。整個過程是全自動的,完全不需要你參與,你只需要輸入你需要調(diào)整參數(shù)的參數(shù)類型,以及每次參數(shù)調(diào)整的步長即可。

    現(xiàn)在有個問題,如何驗證svm參數(shù)的效果?你可能會說,使用訓練集以外的那30%測試集啊。但事實上,機器學習模型中專門有一個數(shù)據(jù)集,是用來驗證參數(shù)效果的。也就是 交叉驗證集(cross validation set,簡稱validate data) ? 這個概念。

    validate data 就是專門從train data中取出一部分數(shù)據(jù),用這部分數(shù)據(jù)來驗證參數(shù)調(diào)整的效果。比方說現(xiàn)在有70%的訓練數(shù)據(jù),從中取出20%的數(shù)據(jù),剩下50%數(shù)據(jù)用來訓練,再用訓練出來的模型在20%數(shù)據(jù)上進行測試。這20%的數(shù)據(jù)就叫做 validate data 。真正拿來訓練的數(shù)據(jù)僅僅只是50%的數(shù)據(jù)。

    正如上面把數(shù)據(jù)劃分為test data和train data的理由一樣。為了驗證參數(shù)在新數(shù)據(jù)上的推廣性,我們不能用一個訓練數(shù)據(jù)集,所以我們要把訓練數(shù)據(jù)集再細分為train data和 validate data 。在train data上訓練,然后在 validate data 上測試參數(shù)的效果。所以說,在一個更一般的機器學習場景中,機器學習工程師會把數(shù)據(jù)分為train data, validate data ,以及test data。在train data上訓練模型,用 validate data 測試參數(shù),最后用test data測試模型和參數(shù)的整體表現(xiàn)。

    說了這么多,那么,大家可能要問,是不是還缺少一個數(shù)據(jù)集,需要再劃分出來一個 validate data吧。但是答案是No。opencv的train_auto函數(shù)幫你完成了所有工作,你只需要告訴它,你需要劃分多少個子分組,以及 validate data

    所占的比例。然后train_auto函數(shù)會自動幫你從你輸入的train data中劃分出一部分的

    validate data

    ,然后自動測試,選擇表現(xiàn)效果最好的參數(shù)。

    感謝train_auto函數(shù)!既幫我們劃分了參數(shù)驗證的數(shù)據(jù)集,還幫我們一步步調(diào)整參數(shù),最后選擇效果最好的那個參數(shù),可謂是節(jié)省了調(diào)優(yōu)過程中80%的工作。

    train_auto函數(shù)的調(diào)用代碼如下:

    svm.train_auto(trainingData, classes, Mat(), Mat(), SVM_params, 10, CvSVM::get_default_grid(CvSVM::C), CvSVM::get_default_grid(CvSVM::GAMMA), CvSVM::get_default_grid(CvSVM::P), CvSVM::get_default_grid(CvSVM::NU), CvSVM::get_default_grid(CvSVM::COEF), CvSVM::get_default_grid(CvSVM::DEGREE), true);

    你唯一需要做的就是泡杯茶,翻翻書,然后慢慢等待這計算機幫你處理好所有事情(時間較長,因為每次調(diào)整參數(shù)又得重新訓練一次)。作者最近的一次訓練的耗時為1個半小時)。

    訓練完畢后,看看模型和參數(shù)在test data上的表現(xiàn)把。99%的precise和98%的recall。非常棒,比任何一次手工配的效果都好。

    3.特征提取

    在rbf核介紹時提到過,輸入數(shù)據(jù)的特征的維度現(xiàn)在是172,那么這個數(shù)字是如何計算出來的?現(xiàn)在的特征用的是直方統(tǒng)計函數(shù),也就是先把圖像二值化,然后統(tǒng)計圖像中一行元素中1的數(shù)目,由于輸入圖像有36行,因此有36個值,再統(tǒng)計圖像中每一列中1的數(shù)目,圖像有136列,因此有136個值,兩者相加正好等于172。新的輸入數(shù)據(jù)的特征提取函數(shù)就是下面的代碼:

    // ! EasyPR的getFeatures回調(diào)函數(shù) // !本函數(shù)是獲取垂直和水平的直方圖圖值 void getHistogramFeatures(const Mat& image, Mat& features) { Mat grayImage; cvtColor(image, grayImage, CV_RGB2GRAY); Mat img_threshold; threshold(grayImage, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY); features = getTheFeatures(img_threshold); }

    我們輸入數(shù)據(jù)的特征不再是全部的三原色的像素值了,而是抽取過的一些特征。從原始的圖像到抽取后的特征的過程就被稱為特征提取的過程。在1.0版中沒有特征提取的概念,是直接把圖像中全部像素作為特征的。這要感謝群里的“如果有一天”同學,他堅持認為全部像素的輸入是最低級的做法,認為用特征提取后的效果會好多。我問大概能到多少準確率,當時的準確率有92%,我以為已經(jīng)很高了,結(jié)果他說能到99%。在半信半疑中我嘗試了,果真如他所說,結(jié)合了rbf核與新特征訓練的模型達到的precise在99%左右,而且recall也有98%,這真是個令人咋舌并且非常驚喜的成績。

    “如果有一天”建議用的是SFIT特征提取或者HOG特征提取,由于時間原因,這兩者我沒有實現(xiàn),但是把函數(shù)留在了那里。留待以后有時間完成。在這個過程中,我充分體會到了開源的力量,如果不是把軟件開源,如果不是有這么多優(yōu)秀的大家一起討論,這樣的思路與改善是不可能出現(xiàn)的。

    4.接口函數(shù)

    由于有SIFT以及HOG等特征沒有實現(xiàn),而且未來有可能會有更多有效的特征函數(shù)出現(xiàn)。因此我把特征函數(shù)抽象為借口。使用回調(diào)函數(shù)的思路實現(xiàn)。所有回調(diào)函數(shù)的代碼都在feature.cpp中,開發(fā)者可以實現(xiàn)自己的回調(diào)函數(shù),并把它賦值給EasyPR中的某個函數(shù)指針,從而實現(xiàn)自定義的特征提取。也許你們會有更多更好的特征的想法與創(chuàng)意。

    關于特征其實有更多的思考,原始的SVM模型的輸入是圖像的全部像素,正如人類在小時候通過圖像識別各種事物的過程。后來SVM模型的輸入是經(jīng)過抽取的特 征。正如隨著人類接觸的事物越來越多,會發(fā)現(xiàn)單憑圖像越來越難區(qū)分一些非常相似的東西,于是學會了總結(jié)特征。例如太陽就是圓的,黃色,在天空等,可以憑借 這些特征就進行區(qū)分和判斷。

    從本質(zhì)上說,特征是區(qū)分事物的關鍵特性。這些特性,一定是從某些維度去看待的。例如,蘋果和梨子,一個是綠色,一個是黃色,這就是顏色的維度;魚和鳥,一個在水里,一個在空中,這是位置的區(qū)分,也就是空間的維度。 特征,是許多維度中最有區(qū)分意義的維度。 傳統(tǒng)數(shù)據(jù)倉庫中的OLAP,也稱為多維分析,提供了人類從多個維度觀察,比較的能力。通過人類的觀察比較,從多個維度中挑選出來的維度,就是要分析目標的特征。從這點來看,機器學習與多維分析有了關聯(lián)。多維分析提供了選擇特征的能力。而機器學習可以根據(jù)這些特征進行建模。

    機器學習界也有很多算法,專門是用來從數(shù)據(jù)中抽取特征信息的。例如傳統(tǒng)的PCA(主成分分析)算法以及最近流行的深度學習中的 AutoEncoder(自動編碼機)技術。這些算法的主要功能就是在數(shù)據(jù)中學習出最能夠明顯區(qū)分數(shù)據(jù)的特征,從而提升后續(xù)的機器學習分類算法的效果。

    說一個特征學習的案例。作者買車時,經(jīng)常會把大眾的兩款車--邁騰與帕薩特給弄混,因為兩者實在太像了。大家可以到網(wǎng)上去搜一下這兩車的圖片。如果不依賴后排的文字,光靠外形實在難以將兩車區(qū)分開來(雖然從生產(chǎn)商來說,前者是一汽大眾生產(chǎn)的,產(chǎn)地在長春,后者是上海大眾生產(chǎn)的,產(chǎn)地在上海。兩個不同的公司,南北兩個地方,相差了十萬八千里)。后來我通過仔細觀察,終于發(fā)現(xiàn)了一個明顯區(qū)分兩輛車的特征,后來我再也沒有認錯過。這個特征就是:邁騰的前臉有四條銀杠,而帕薩特只有三條,邁騰比帕薩特多一條銀杠。可以這么說,就是這么一條銀杠,分割了北和南兩個地方生產(chǎn)的汽車。

    圖15 一條銀杠,分割了“北”和“南”

    在這里區(qū)分的過程,我是通過不斷學習與研究才發(fā)現(xiàn)了這些區(qū)分的特征,這充分說明了事物的特征也是可以被學習的。如果讓機器學習中的特征選擇方法PCA和AutoEncoder來分析的話,按理來說它們也應該找出這條銀杠,否則它們就無法做到對這兩類最有效的分類與判斷。如果沒有找到的話,證明我們目前的特征選擇算法還有很多的改進空間(與這個案例類似的還有大眾的另兩款車,高爾夫和Polo。它們兩的區(qū)分也是用同樣的道理。相比邁騰和帕薩特,高爾夫和Polo價格差別的更大,所以區(qū)分的特征也更有價值)。

    5.自動化

    最后我想簡單談一下EasyPR1.1新增的自動化訓練功能與命令行。大家可能看到第二部分介紹SVM訓練時我將過程分成了5個步驟。事實上,這些步驟中的很多過程是可以模塊化的。一開始的時候我寫一些不相關的代碼函數(shù),幫我處理各種需要解決的問題,例如數(shù)據(jù)的分組,打標簽等等。但后來,我把思路理清后,我覺得這幾個步驟中很多的代碼都可以通用。于是我把一些步驟模塊化出來,形成通用的函數(shù),并寫了一個命令行界面去調(diào)用它們。在你運行EasyPR1.1版后,在你看到的第一個命令行界面選擇“3.SVM訓練過程”,你就可以看到這些全部的命令。

    圖16 svm訓練命令行

    這里的命令主要有6個部分。第一個部分是最可能需要修改代碼的地方,因為每個人的原始數(shù)據(jù)(raw data)都是不一樣的,因此你需要在data_prepare.cpp中找到這個函數(shù),改寫成適應你格式的代碼。接下來的第二個部分以后的功能基本都可以復用。例如自動貼標簽(注意貼完以后要人工核對一下)。

    第三個到第六部分功能類似。如果你的數(shù)據(jù)還沒分組,那么你執(zhí)行3以后,系統(tǒng)自動幫你分組,然后訓練,再測試驗證。第四個命令行省略了分組過程。第五個命令行部分省略訓練過程。第六個命令行省略了前面所有過程,只做最后模型的測試部分。

    讓我們回顧一下SVM調(diào)優(yōu)的五個思路。第一部分是rbf核,也就是模型選擇層次,根據(jù)你的實際環(huán)境選擇最合適的模型。第二部分是參數(shù)調(diào)優(yōu),也就是參數(shù)優(yōu)化層次,這部分的參數(shù)最好通過一個驗證集來確認,也可以使用opencv自帶的train_auto函數(shù)。第三部分是特征抽取部分,也就是特征甄選們,要能選擇出最能反映數(shù)據(jù)本質(zhì)區(qū)別的特征來。在這方面,pca以及深度學習技術中的autoencoder可能都會有所幫助。第四部分是通用接口部分,為了給優(yōu)化留下空間,需要抽象出接口,方便后續(xù)的改進與對比。第五部分是自動化部分,為了節(jié)省時間,將大量可以自動化處理的功能模塊化出來,然后提供一些方便的操作界面。前三部分是從機器學習的效果來提高,后兩部分是從軟件工程的層面去優(yōu)化。

    總結(jié)起來,就是 模型,參數(shù),特征,接口,模塊 五個層面。通過這五個層面,可以有效的提高機器學習模型訓練的效果與速度,從而降低機器學習工程實施的難度與提升相關的效率。當需要對機器學習模型進行調(diào)優(yōu)的時候,我們可以從這五個層面去考慮。

    后記

    講到這里,本次的SVM開發(fā)詳解也算是結(jié)束了。相信通過這篇文檔,以及作者的一些心得,會對你在SVM模型的開發(fā)上面帶來一些幫助。下面的工作可以考慮把這些相關的方法與思路運用到其他領域,或著改善EasyPR目前已有的模型與算法。如果你找出了比目前更好實現(xiàn)的思路,并且你愿意跟我們分享,那我們是非常歡迎的。

    EasyPR1.1的版本發(fā)生了較大的變化。我為了讓它擁有多人協(xié)作,眾包開發(fā)的能力,想過很多辦法。最后決定引入了GDTS(General Data Test Set,通用測試數(shù)據(jù)集,也就是新的image/general_test下的眾多車牌圖片)以及GDSL(General Data Share License,通用數(shù)據(jù)分享協(xié)議,image/GDSL.txt)。這些概念與協(xié)議的引入非常重要,可能會改變目前車牌識別與機器學習在國內(nèi)學習研究的格局。在下期的EasyPR開發(fā)詳解中我會重點介紹1.1版的新加入功能以及這兩個概念和背后的思想,歡迎繼續(xù)閱讀。

    上一篇還是第四篇,為什么本期SVM開發(fā)詳解屬于EasyPR開發(fā)的第六篇?事實上,對于目前的車牌定位模塊我們團隊覺得還有改進空間,所以第五篇的詳解內(nèi)容是留給改進后的車牌定位模塊的。如果有車牌定位模塊方面好的建議或者希望加入開源團隊,歡迎跟我們團隊聯(lián)系(easypr_dev@163.com )。您也可以為中國的開源事業(yè)做出一份貢獻。

    版權說明:

    本文中的所有文字,圖片,代碼的版權都是屬于作者和博客園共同所有。歡迎轉(zhuǎn)載,但是務必注明作者與出處。任何未經(jīng)允許的剽竊以及爬蟲抓取都屬于侵權,作者和博客園保留所有權利。

    總結(jié)

    以上是生活随笔為你收集整理的SVM开发详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。