2015-10-17 47 views
2

我在Android應用程序(NDK)上運行LibSVM。我在Mac應用程序上實現了類似的代碼,該代碼適用於所有特徵向量大小。當我給出408個特徵向量時,我沒有問題做多類分類。任何409或更高,不過,(我最終會在16800被投入)似乎無法在這裏:Segfault with large feature vector LibSVM

0-16 23:28:41.084 30997-31028/? A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0xaf000000 in tid 31028 (GLThread 17147) 
10-16 23:28:41.190 27393-27393/? I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 
10-16 23:28:41.191 27393-27393/? I/DEBUG: Build fingerprint: 'google/hammerhead/hammerhead:5.1.1/LMY48M/2167285:user/release-keys' 
10-16 23:28:41.191 27393-27393/? I/DEBUG: Revision: '11' 
10-16 23:28:41.191 27393-27393/? I/DEBUG: ABI: 'arm' 
10-16 23:28:41.191 27393-27393/? I/DEBUG: pid: 30997, tid: 31028, name: GLThread 17147 >>> cc.openframeworks.androidEmptyExample <<< 
10-16 23:28:41.191 27393-27393/? I/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xaf000000 
10-16 23:28:41.202 27393-27393/? I/DEBUG:  r0 aef3e000 r1 aef5ed10 r2 00000001 r3 af000000 
10-16 23:28:41.202 27393-27393/? I/DEBUG:  r4 aec29eb8 r5 00000001 r6 b4b2c608 r7 12d090c0 
10-16 23:28:41.202 27393-27393/? I/DEBUG:  r8 12d15660 r9 b4a39400 sl 00000000 fp af37d824 
10-16 23:28:41.202 27393-27393/? I/DEBUG:  ip b6e417dc sp af37d810 lr a301ff78 pc a301ff04 cpsr 000f0010 
10-16 23:28:41.202 27393-27393/? I/DEBUG:  #00 pc 00167f04 /data/app/cc.openframeworks.androidEmptyExample-1/lib/arm/libOFAndroidApp.so (Kernel::dot(svm_node const*, svm_node const*)+192) 

下面是我與學習相關的代碼:

ofxSvm mSvm; 
void ofApp::update() 
{ //Runs in loop    
    for(int i =0; i<8400; ++i) 
    { 
     HandDataVector.push_back((double)tempValue[i]);//tempValue is incoming data from a serial port (8400 doubles per packet) 
    } 
    //If I exclude this I get segfaults: 
    HandDataVector.resize(150); 
    if(learningToggleBoxTicked) 
    { 
     mSvm.addData(HandDataVector,label) 
     mSvm.train(); 
    } else { 
     ofLogNotice("Classified As")<< mSvm.classify(); 
    } 
} 

int ofApp::classify() 
{ 
    return mSvm.predict(HandDataVector); 
} 

這裏的ofxSvm我使用

int ofxSvm::addData(int label, vector<double>& vec) 
    { 
      checkDimension(vec.size()); 

      mData.insert(make_pair(label, vec)); 
      mDimension = vec.size(); 


      stringstream ss; 
      for (const auto v : vec) ss << v << " "; 
      ss << "EOS"; 
      ofLogNotice(LOG_MODULE, "add data, label: " + ofToString(label) + " size: "+ofToString(vec.size())+" vec: " + ss.str()); 


      return mData.size(); 
    } 
    void ofxSvm::train() 
    { 


      svm_problem prob; 

      prob.l = mData.size(); 

      prob.y = new double[prob.l]; 
      { 
       data_type::iterator it = mData.begin(); 
       int i = 0; 
       while (it != mData.end()) 
       { 
        prob.y[i] = it->first; 
        ++it; ++i; 
       } 
      } 


      if(mParam.gamma == 0) 
      { 
       mParam.gamma = 1.0/mDimension; 
      } 

      int nodeLength = mDimension + 1; 
      svm_node* node = new svm_node[prob.l * nodeLength]; 
      prob.x = new svm_node*[prob.l]; 
      { 
       data_type::iterator it = mData.begin(); 
       int i = 0; 
       while (it != mData.end()) 
       { 
        prob.x[i] = node + i * nodeLength; 
        for (int j = 0; j < mDimension; ++j) 
        { 
         prob.x[i][j].index = j + 1; 
         prob.x[i][j].value = it->second[j]; 
        } 
        prob.x[i][mDimension].index = -1; // delimiter 
        ++it; ++i; 
       } 
      } 

      ofLogNotice(LOG_MODULE, "Start train..."); 

      mModel = svm_train(&prob, &mParam); 



      ofLogNotice(LOG_MODULE, "Finished train!"); 

      int x = mModel->nr_class; 

      ofLogNotice("TRAINED MODEL LABELS: " + ofToString(x)); 

      delete[] node; 
      delete[] prob.x; 
      delete[] prob.y; 
     } 

     int ofxSvm::predict(vector<double>& testVec) 
     { 
      if (mModel == NULL) 
      { 
       ofLogNotice(LOG_MODULE, "null model, before do train or load model file"); 
       return -5; 
      } 
      if (testVec.size() != mDimension) 
      { 
       ofLogNotice(LOG_MODULE, "different dimension"); 
       return -6; 
      } 


      svm_node* node = new svm_node[mDimension + 1]; 
      for (int i = 0; i < mDimension; ++i) 
      { 
       node[i].index = i + 1; 
       node[i].value = testVec[i]; 
       ofLogNotice("node") << node[i].value <<"-" << i; 

      } 
      node[mDimension].index = -1; 

      int res = static_cast<int>(svm_predict(mModel, node)); 


      stringstream ss; 
      for (const auto v : testVec) ss << v << " "; 
      ss << "EOS"; 
      ofLogNotice(LOG_MODULE, "add data, label: size: "+ofToString(testVec.size())+" vec: " + ss.str()); 


      ofLogNotice("ANSWER")<< res; 


      delete[] node; 
      return res; 
    } 

這裏圖書館在LIBSVM庫中的故障發生中的作用:

double Kernel::dot(const svm_node *px, const svm_node *py) 
{ 
    double sum = 0; 
    while(px->index != -1 && py->index != -1) 
    { 
     if(px->index == py->index) 
     { 
      sum += px->value * py->value; 
      ++px; 
      ++py; 
     } 
     else 
     { 
      if(px->index > py->index) 
       ++py; 
      else 
       ++px; 
     } 
    } 
    return sum; 
} 

編輯:在這裏點函數被調用(在svm_predict_values k_function)

double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values) 
{ 
    int i; 
    if(model->param.svm_type == ONE_CLASS || 
     model->param.svm_type == EPSILON_SVR || 
     model->param.svm_type == NU_SVR) 
    { 
     double *sv_coef = model->sv_coef[0]; 
     double sum = 0; 
     for(i=0;i<model->l;i++) 
      sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param); 
     sum -= model->rho[0]; 
     *dec_values = sum; 

     if(model->param.svm_type == ONE_CLASS) 
      return (sum>0)?1:-1; 
     else 
      return sum; 
    } 
    else 
    { 
     int nr_class = model->nr_class; 
     int l = model->l; 

     double *kvalue = Malloc(double,l); 
     for(i=0;i<l;i++) 
      kvalue[i] = Kernel::k_function(x,model->SV[i],model->param); 

     int *start = Malloc(int,nr_class); 
     start[0] = 0; 
     for(i=1;i<nr_class;i++) 
      start[i] = start[i-1]+model->nSV[i-1]; 

     int *vote = Malloc(int,nr_class); 
     for(i=0;i<nr_class;i++) 
      vote[i] = 0; 

     int p=0; 
     for(i=0;i<nr_class;i++) 
      for(int j=i+1;j<nr_class;j++) 
      { 
       double sum = 0; 
       int si = start[i]; 
       int sj = start[j]; 
       int ci = model->nSV[i]; 
       int cj = model->nSV[j]; 

       int k; 
       double *coef1 = model->sv_coef[j-1]; 
       double *coef2 = model->sv_coef[i]; 
       for(k=0;k<ci;k++) 
        sum += coef1[si+k] * kvalue[si+k]; 
       for(k=0;k<cj;k++) 
        sum += coef2[sj+k] * kvalue[sj+k]; 
       sum -= model->rho[p]; 
       dec_values[p] = sum; 

       if(dec_values[p] > 0) 
        ++vote[i]; 
       else 
        ++vote[j]; 
       p++; 
      } 

     int vote_max_idx = 0; 
     for(i=1;i<nr_class;i++) 
      if(vote[i] > vote[vote_max_idx]) 
       vote_max_idx = i; 

     free(kvalue); 
     free(start); 
     free(vote); 
     return model->label[vote_max_idx]; 
    } 
} 

double Kernel::k_function(const svm_node *x, const svm_node *y, 
          const svm_parameter& param) 
{ 
    switch(param.kernel_type) 
    { 
     case LINEAR: 
      return dot(x,y); 
     case POLY: 
      return powi(param.gamma*dot(x,y)+param.coef0,param.degree); 
     case RBF: 
     { 
      double sum = 0; 
      while(x->index != -1 && y->index !=-1) 
      { 
       if(x->index == y->index) 
       { 
        double d = x->value - y->value; 
        sum += d*d; 
        ++x; 
        ++y; 
       } 
       else 
       { 
        if(x->index > y->index) 
        { 
         sum += y->value * y->value; 
         ++y; 
        } 
        else 
        { 
         sum += x->value * x->value; 
         ++x; 
        } 
       } 
      } 

      while(x->index != -1) 
      { 
       sum += x->value * x->value; 
       ++x; 
      } 

      while(y->index != -1) 
      { 
       sum += y->value * y->value; 
       ++y; 
      } 

      return exp(-param.gamma*sum); 
     } 
     case SIGMOID: 
      return tanh(param.gamma*dot(x,y)+param.coef0); 
     case PRECOMPUTED: //x: test (validation), y: SV 
      return x[(int)(y->value)].value; 
     default: 
      return 0; // Unreachable 
    } 
} 

    double kernel_linear(int i, int j) const 
    { 
     return dot(x[i],x[j]); 
    } 
+0

「點」從哪裏調用?你正在走一個或兩個指針,超過分配內存的末尾。 – 1201ProgramAlarm

+0

@ 1201ProgramAlarm在調用svm_predict之後,它從LibSVM庫調用。這是算法的藝術。剛剛添加到編輯。你認爲哪一個是通過分配的內存? – Rohan

+0

你沒有檢查從malloc返回?如果malloc不能分配請求的內存,這將返回nullptr,並且當你嘗試訪問內存時你將得到一個SEGV。 – Ben

回答

1

介紹

我有一個非常很難找到關於LIBSVM任何文件在C++中。所以我的回答主要是基於您向我們展示的代碼,而沒有真實的參考文檔。

如果你可以發佈鏈接到您的文檔,這將是非常有益的:)

潛在問題

你顯示,你在你的訓練代碼初始化svm_node*代碼:

prob.x[i][mDimension].index = -1; 

您正在初始化一個svm_problem實例。顯然,在您的dot()函數中,您希望看到這樣的節點具有負指數以標記svm_node列表的末尾。

但是當你像這樣調用代碼失敗:

Kernel::k_function(x,model->SV[i],model->param); 

這裏,modelsvm_model,不是svm_problem,所以我想這是由LIBSVM 返回後,你訓練的模型。您確定svm_model遵循使用node->index = -1來標記節點列表的結尾的約定嗎?

所以,也許標記節點不存在,你用盡了界限。

爲什麼會突然打破409項

你得到的信號是一個SIGSEGV表明您是否嘗試過在你的過程沒有映射頁面訪問一個字節。

訪問項目出界時,通常不會獲得SIGSEGV,因爲之前分配的項目位於內存頁面的中間,並且頁面中有足夠的字節。可能發生的是,第409項僅在當前分配的頁面之後觸發信號。