成人av在线资源一区,亚洲av日韩av一区,欧美丰满熟妇乱XXXXX图片,狠狠做五月深爱婷婷伊人,桔子av一区二区三区,四虎国产精品永久在线网址,国产尤物精品人妻在线,中文字幕av一区二区三区欲色
    您正在使用IE低版瀏覽器,為了您的雷峰網賬號安全和更好的產品體驗,強烈建議使用更快更安全的瀏覽器
    此為臨時鏈接,僅用于文章預覽,將在時失效
    人工智能開發者 正文
    發私信給AI研習社
    發送

    0

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    本文作者: AI研習社 2017-05-14 14:34
    導語:SVM 算法實現指南。

    雷鋒網按:本文作者謝輝,原文載于作者個人博客,雷鋒網已獲授權。

    支持向量機SVM(Support Vector Machine)是一種有監督的學習模型,它的核心有兩個:一、核函數(kernel trick);二、序列最小優化算法SMO(Sequential minimal optimization)是John Platt在1996年發布的用于訓練SVM的有效算法。本文不打算細化SVM支持向量機的詳細推倒算法,只涉及以上兩點的內容做一個說明,最后給出算法實現和一個實驗對比圖。

      核函數

    核函數在處理復雜數據時效果顯著,它的做法是將某一個維度的線性不可分數據采取核函數進行特征空間的隱式映射到高維空間,從而在高維空間將數據轉化為線性可分,最后回歸到原始維度空間實施分類的過程,常見的幾個核函數如下:

    多項式核:

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    高斯核(徑向基函數):

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    線性核:

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    即是兩個矩陣空間的內積。

      SMO算法流程

    SMO的主要兩個步驟就是:

    1、選擇需要更新的一對α,采取啟發式的方式進行選擇,以使目標函數最大程度的接近其全局最優值;

    2、將目標函數對α進行優化,以保持其它所有α不變。

    以上是兩個基本步驟,實現具體推到公式如下:

    所需要收到的約束條件為:

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    同時更新α,要求滿足如下條件,就可以保證為0的約束

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    消去α可得

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    其中

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    u 的表達式為:

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    y為第i個特征因素的真實標簽值

    之后考慮約束條件 0<α<c 則

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    約束條件的線性表示

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    依據 y 同號或是異號,可得出上下兩個邊界為

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    對于α有

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    對于α首先可以通過E求得j,之后計算方式可為:

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    而b的更新為

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    其中

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    每次更新完和都需要重新計算b以及對應的和

    有了以上的公式,代碼實現就比較簡單了。

      算法實現

    完整的Platt-smo算法實現入口:

    public SvmResult plattSmo(final SvmResult svmResult) {

    double b = svmResult.getB();

    double[] alphas = svmResult.getAlphas();


    for(int i=0;i<featuresArray.length;i++){

    double ei = this.calcEk(i, alphas, b);

    if (((lablesArray[i] * ei < -tolerFactor)

    && (alphas[i] < penaltyFactor))

    || ((lablesArray[i] * ei > tolerFactor) && (alphas[i] > 0))) {

    double[] jSelected = this.selectJ(i, ei, alphas, b); //啟發式實現j的選擇

    int j = (int) jSelected[0]; 

    double ej = jSelected[1];

    double alphaIold = alphas[i];

    double alphaJold = alphas[j];

    double L = 0;

    double H = 0;

    //邊界計算

    if (lablesArray[i] != lablesArray[j]) {

    L = Math.max(0, alphas[j] - alphas[i]);

    H = Math.min(penaltyFactor, penaltyFactor + alphas[j]

    - alphas[i]);

    } else {

    L = Math.max(0, alphas[j] + alphas[i] - penaltyFactor);

    H = Math.min(penaltyFactor, alphas[j] + alphas[i]);

    }

    if (L == H) {

    logger.info("L==H");

    } else {

    double eta = (2.0 * this.kernelArray[i][j] - this.kernelArray[i][i] - this.kernelArray[j][j]);

    if (eta >= 0) {

    logger.info("eta>=0");

    } else {

    //雙向調整alphas[j]遞減

    alphas[j] -= lablesArray[j] * (ei - ej) / eta;

    if (alphas[j] > H) {

    alphas[j] = H;

    }

    if (L > alphas[j]) {

    alphas[j] = L;

    }

    //更新ej

    this.updateEk(j, alphas, b);

    if (Math.abs(alphas[j] - alphaJold) < 0.00001) {

    logger.info("j not moving enough");

    } else {

    //雙向調整alphas[i]遞減

    alphas[i] += lablesArray[j] * lablesArray[i]

    * (alphaJold - alphas[j]);

    //更新ei

    this.updateEk(i, alphas, b);

    //計算b

    double b1 = b - ei- lablesArray[i]*(alphas[i]-alphaIold)*this.kernelArray[i][i] - lablesArray[j]*(alphas[j]-alphaJold)*this.kernelArray[i][j];

    double b2 = b - ej- lablesArray[i]*(alphas[i]-alphaIold)*this.kernelArray[i][j] - lablesArray[j]*(alphas[j]-alphaJold)*this.kernelArray[j][j];

    if ((0 < alphas[i]) && (penaltyFactor > alphas[i])){

    b = b1;

    }else if ((0 < alphas[j]) && (penaltyFactor > alphas[j])){

    b = b2;

    }else{

    b = (b1 + b2)/2.0;

    }


    }

    }

    }

    }

    }

    return new SvmResult(b, alphas);

    }

    在以上算法里面重點關注是j的選擇,

    J的選擇:

    private double[] selectJ(int i,double ei,double[] alphas,double b){

    int maxK = -1; 

    double maxDeltaE = 0; 

    double ej = 0;

    int j = -1;

    double[] eiArray= new double[2];

    eiArray[0] = 1d;

    eiArray[1] = ei;

    this.eCache[i] = eiArray;

    boolean hasValidEcacheList = false;

    for(int k=0;k<this.eCache.length;k++){

    if(this.eCache[k][0] > 0){

    if(k == i){

    continue;

    }

    hasValidEcacheList = true;

    if(k == this.m){

    k = m-1;

    }

    double ek = this.calcEk(k, alphas, b);

    double deltaE = Math.abs(ei - ek);

    if (deltaE > maxDeltaE){

                   maxK = k; 

                   maxDeltaE = deltaE; 

                   ej = ek;

    }

    }

    }

    j = maxK;

    if(!hasValidEcacheList || j == -1){

    j = this.selectJRandom(i);

    ej = this.calcEk(j, alphas, b); 

    }

    if(j == this.m){

    j = m-1;

    }

    return new double[]{j,ej};

    }

    首選采取啟發式選擇j,通過計算deltaE的最大值來逼近j的選擇,如果選擇不到就隨機選擇一個j值,在j選擇里面有一個Ek的計算方式

    private double calcEk(int k,double[] alphas,double b){

    Matrix alphasMatrix = new Matrix(alphas);

    Matrix lablesMatrix = new Matrix(lablesArray);

    Matrix kMatrix = new Matrix(this.kernelArray[k]);

    double fXk = alphasMatrix.multiply(lablesMatrix).dotMultiply(kMatrix.transpose()).dotValue() + b;

    double ek = fXk - (float)this.lablesArray[k];

    return ek;

    }

    下面再介紹一下核函數計算方式,本文主要采取徑向基函數(RBF)實現,如下:

    public double[] kernelTrans(double[][] featuresArray,double[] featuresIArray){

    int mCount = featuresArray.length;

    double[] kernelTransI = new double[mCount];

    Matrix featuresMatrix = new Matrix(featuresArray);

    Matrix featuresIMatrix = new Matrix(featuresIArray);

    if(trainFactorMap.get("KT").equals("lin")){

    Matrix result = featuresMatrix.dotMultiply(featuresIMatrix.transpose());

    kernelTransI = result.transpose().values()[0];

    }else if(trainFactorMap.get("KT").equals("rbf")){

    double rbfDelta = (double)trainFactorMap.get("rbfDelta");

    for(int j=0;j<mCount;j++){

    Matrix xj = new Matrix(featuresArray[j]);

    Matrix delta = xj.reduce(featuresIMatrix);

    double deltaValue = delta.dotMultiply(delta.transpose()).dotValue();

    kernelTransI[j] = Math.exp((-1.0*deltaValue)/(2*Math.pow(rbfDelta, 2)));

    }

    }

    return kernelTransI;

    }

    最后看下測試代碼實現:

    double[][] datasvs = new double[m][d[0].length];

    double[] labelsvs = new double[m];

    double[] alphassvs = new double[m];

    int n = 0;

    for(int i=0;i<alphas.length;i++){

    if(alphas[i] != 0){

    datasvs[n] = d[i];

    labelsvs[n] = l[i];

    alphassvs[n] = alphas[i];

    n++;

    }

    }


    //model test

    int errorCount = 0;

    for(int i=0;i<d.length;i++){

    double[] kernelTransI = learner.kernelTrans(datasvs, d[i]);

    Matrix kernelTransIM = new Matrix(kernelTransI);

    Matrix labelsvsM = new Matrix(labelsvs);

    Matrix alphassvsM = new Matrix(alphassvs);

    double predict = kernelTransIM.dotMultiply(labelsvsM.multiply(alphassvsM).transpose()).dotValue() + b;

    System.out.println(i+"\t"+predict+"\t"+l[i]);

    if(AdaBoost.sigmoid(predict) != l[i]){

    errorCount++;

    }

    }

    測試代碼是首先找出所有的支持向量,并提取支持向量下的特征向量和標簽向量,采取核函數進行隱式映射,最后計算預測值。

      訓練結果


    本文采取100個二維平面無法線性可分的數據集合,如下:

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    通過徑向基函數映射后采取支持向量預測計算得到的可分平面如下

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    本算法100個數據訓練準確率可達98%。

    注:本文算法均來自Peter Harrington的《Machine Learning in action》

    ———————————————————————————————————————

    人工智能之神經網絡特訓班

    20年清華大學神經網絡授課導師,帶你系統學習人工智能之神經網絡!

    一站式深入了解深度學習的發展現狀、基本原理和主要方法。

    課程鏈接:http://www.mooc.ai/course/65 

    雷鋒網(公眾號:雷鋒網)相關閱讀:

    從理論到實踐,一文詳解 AI 推薦系統的三大算法

    監督學習最常見的五種算法,你知道幾個?

    雷峰網版權文章,未經授權禁止轉載。詳情見轉載須知

    基于Spark如何實現SVM算法?這里有一份詳盡的開發教程(含代碼)

    分享:
    相關文章

    編輯

    聚焦數據科學,連接 AI 開發者。更多精彩內容,請訪問:yanxishe.com
    當月熱門文章
    最新文章
    請填寫申請人資料
    姓名
    電話
    郵箱
    微信號
    作品鏈接
    個人簡介
    為了您的賬戶安全,請驗證郵箱
    您的郵箱還未驗證,完成可獲20積分喲!
    請驗證您的郵箱
    立即驗證
    完善賬號信息
    您的賬號已經綁定,現在您可以設置密碼以方便用郵箱登錄
    立即設置 以后再說