WDSVMOcas.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of the GNU General Public License as published by
00004  * the Free Software Foundation; either version 3 of the License, or
00005  * (at your option) any later version.
00006  *
00007  * Written (W) 2007-2008 Vojtech Franc
00008  * Written (W) 2007-2009 Soeren Sonnenburg
00009  * Copyright (C) 2007-2009 Fraunhofer Institute FIRST and Max-Planck-Society
00010  */
00011 
00012 #include "features/Labels.h"
00013 #include "lib/Mathematics.h"
00014 #include "lib/DynamicArray.h"
00015 #include "lib/Time.h"
00016 #include "base/Parallel.h"
00017 #include "classifier/Classifier.h"
00018 #include "classifier/svm/libocas.h"
00019 #include "classifier/svm/WDSVMOcas.h"
00020 #include "features/StringFeatures.h"
00021 #include "features/Alphabet.h"
00022 #include "features/Labels.h"
00023 
00024 using namespace shogun;
00025 
00026 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00027 struct wdocas_thread_params_output
00028 {
00029     float32_t* out;
00030     int32_t* val;
00031     float64_t* output;
00032     CWDSVMOcas* wdocas;
00033     int32_t start;
00034     int32_t end;
00035 };
00036 
00037 struct wdocas_thread_params_add
00038 {
00039     CWDSVMOcas* wdocas;
00040     float32_t* new_a;
00041     uint32_t* new_cut;
00042     int32_t start;
00043     int32_t end;
00044     uint32_t cut_length;
00045 };
00046 #endif // DOXYGEN_SHOULD_SKIP_THIS
00047 
00048 CWDSVMOcas::CWDSVMOcas(E_SVM_TYPE type)
00049 : CClassifier(), use_bias(false), bufsize(3000), C1(1), C2(1),
00050     epsilon(1e-3), method(type)
00051 {
00052     w=NULL;
00053     old_w=NULL;
00054     features=NULL;
00055     degree=6;
00056     from_degree=40;
00057     wd_weights=NULL;
00058     w_offsets=NULL;
00059     normalization_const=1.0;
00060 }
00061 
00062 CWDSVMOcas::CWDSVMOcas(
00063     float64_t C, int32_t d, int32_t from_d, CStringFeatures<uint8_t>* traindat,
00064     CLabels* trainlab)
00065 : CClassifier(), use_bias(false), bufsize(3000), C1(C), C2(C), epsilon(1e-3),
00066     degree(d), from_degree(from_d)
00067 {
00068     w=NULL;
00069     old_w=NULL;
00070     method=SVM_OCAS;
00071     features=traindat;
00072     set_labels(trainlab);
00073     wd_weights=NULL;
00074     w_offsets=NULL;
00075     normalization_const=1.0;
00076 }
00077 
00078 
00079 CWDSVMOcas::~CWDSVMOcas()
00080 {
00081 }
00082 
00083 CLabels* CWDSVMOcas::classify()
00084 {
00085     set_wd_weights();
00086     set_normalization_const();
00087 
00088     if (features)
00089     {
00090         int32_t num=features->get_num_vectors();
00091         ASSERT(num>0);
00092 
00093         CLabels* output=new CLabels(num);
00094         SG_REF(output);
00095 
00096         for (int32_t i=0; i<num; i++)
00097             output->set_label(i, classify_example(i));
00098 
00099         return output;
00100     }
00101 
00102     return NULL;
00103 }
00104 
00105 CLabels* CWDSVMOcas::classify(CFeatures* data)
00106 {
00107     if (!data)
00108         SG_ERROR("No features specified\n");
00109 
00110     if (data->get_feature_class() != C_STRING ||
00111             data->get_feature_type() != F_BYTE)
00112     {
00113         SG_ERROR("Features not of class string type byte\n");
00114     }
00115 
00116     set_features((CStringFeatures<uint8_t>*) data);
00117     return classify();
00118 }
00119 
00120 int32_t CWDSVMOcas::set_wd_weights()
00121 {
00122     ASSERT(degree>0 && degree<=8);
00123     delete[] wd_weights;
00124     wd_weights=new float32_t[degree];
00125     delete[] w_offsets;
00126     w_offsets=new int32_t[degree];
00127     int32_t w_dim_single_c=0;
00128 
00129     for (int32_t i=0; i<degree; i++)
00130     {
00131         w_offsets[i]=CMath::pow(alphabet_size, i+1);
00132         wd_weights[i]=sqrt(2.0*(from_degree-i)/(from_degree*(from_degree+1)));
00133         w_dim_single_c+=w_offsets[i];
00134     }
00135     return w_dim_single_c;
00136 }
00137 
00138 bool CWDSVMOcas::train(CFeatures* data)
00139 {
00140     SG_INFO("C=%f, epsilon=%f, bufsize=%d\n", get_C1(), get_epsilon(), bufsize);
00141 
00142     ASSERT(labels);
00143     if (data)
00144     {
00145         if (data->get_feature_class() != C_STRING ||
00146                 data->get_feature_type() != F_BYTE)
00147         {
00148             SG_ERROR("Features not of class string type byte\n");
00149         }
00150         set_features((CStringFeatures<uint8_t>*) data);
00151     }
00152 
00153     ASSERT(get_features());
00154     ASSERT(labels->is_two_class_labeling());
00155     CAlphabet* alphabet=get_features()->get_alphabet();
00156     ASSERT(alphabet && alphabet->get_alphabet()==RAWDNA);
00157 
00158     alphabet_size=alphabet->get_num_symbols();
00159     string_length=features->get_num_vectors();
00160     int32_t num_train_labels=0;
00161     lab=labels->get_labels(num_train_labels);
00162 
00163     w_dim_single_char=set_wd_weights();
00164     //CMath::display_vector(wd_weights, degree, "wd_weights");
00165     SG_DEBUG("w_dim_single_char=%d\n", w_dim_single_char);
00166     w_dim=string_length*w_dim_single_char;
00167     SG_DEBUG("cutting plane has %d dims\n", w_dim);
00168     num_vec=get_features()->get_max_vector_length();
00169 
00170     set_normalization_const();
00171     SG_INFO("num_vec: %d num_lab: %d\n", num_vec, num_train_labels);
00172     ASSERT(num_vec==num_train_labels);
00173     ASSERT(num_vec>0);
00174 
00175     delete[] w;
00176     w=new float32_t[w_dim];
00177     memset(w, 0, w_dim*sizeof(float32_t));
00178 
00179     delete[] old_w;
00180     old_w=new float32_t[w_dim];
00181     memset(old_w, 0, w_dim*sizeof(float32_t));
00182     bias=0;
00183     old_bias=0;
00184 
00185     cuts=new float32_t*[bufsize];
00186     memset(cuts, 0, sizeof(*cuts)*bufsize);
00187     cp_bias=new float64_t[bufsize];
00188     memset(cp_bias, 0, sizeof(float64_t)*bufsize);
00189 
00191     /*float64_t* tmp = new float64_t[num_vec];
00192     float64_t start=CTime::get_curtime();
00193     CMath::random_vector(w, w_dim, (float32_t) 0, (float32_t) 1000);
00194     compute_output(tmp, this);
00195     start=CTime::get_curtime()-start;
00196     SG_PRINT("timing:%f\n", start);
00197     delete[] tmp;
00198     exit(1);*/
00200     float64_t TolAbs=0;
00201     float64_t QPBound=0;
00202     uint8_t Method=0;
00203     if (method == SVM_OCAS)
00204         Method = 1;
00205     ocas_return_value_T result = svm_ocas_solver( get_C1(), num_vec, get_epsilon(),
00206             TolAbs, QPBound, bufsize, Method,
00207             &CWDSVMOcas::compute_W,
00208             &CWDSVMOcas::update_W,
00209             &CWDSVMOcas::add_new_cut,
00210             &CWDSVMOcas::compute_output,
00211             &CWDSVMOcas::sort,
00212             this);
00213 
00214     SG_INFO("Ocas Converged after %d iterations\n"
00215             "==================================\n"
00216             "timing statistics:\n"
00217             "output_time: %f s\n"
00218             "sort_time: %f s\n"
00219             "add_time: %f s\n"
00220             "w_time: %f s\n"
00221             "solver_time %f s\n"
00222             "ocas_time %f s\n\n", result.nIter, result.output_time, result.sort_time,
00223             result.add_time, result.w_time, result.solver_time, result.ocas_time);
00224 
00225     for (int32_t i=bufsize-1; i>=0; i--)
00226         delete[] cuts[i];
00227     delete[] cuts;
00228 
00229     delete[] lab;
00230     lab=NULL;
00231 
00232     SG_UNREF(alphabet);
00233 
00234     return true;
00235 }
00236 
00237 /*----------------------------------------------------------------------------------
00238   sq_norm_W = sparse_update_W( t ) does the following:
00239 
00240   W = oldW*(1-t) + t*W;
00241   sq_norm_W = W'*W;
00242 
00243   ---------------------------------------------------------------------------------*/
00244 float64_t CWDSVMOcas::update_W( float64_t t, void* ptr )
00245 {
00246   float64_t sq_norm_W = 0;         
00247   CWDSVMOcas* o = (CWDSVMOcas*) ptr;
00248   uint32_t nDim = (uint32_t) o->w_dim;
00249   float32_t* W=o->w;
00250   float32_t* oldW=o->old_w;
00251   float64_t bias=o->bias;
00252   float64_t old_bias=bias;
00253 
00254   for(uint32_t j=0; j <nDim; j++)
00255   {
00256       W[j] = oldW[j]*(1-t) + t*W[j];
00257       sq_norm_W += W[j]*W[j];
00258   }          
00259 
00260   bias=old_bias*(1-t) + t*bias;
00261   sq_norm_W += CMath::sq(bias);
00262 
00263   o->bias=bias;
00264   o->old_bias=old_bias;
00265 
00266   return( sq_norm_W );
00267 }
00268 
00269 /*----------------------------------------------------------------------------------
00270   sparse_add_new_cut( new_col_H, new_cut, cut_length, nSel ) does the following:
00271 
00272     new_a = sum(data_X(:,find(new_cut ~=0 )),2);
00273     new_col_H = [sparse_A(:,1:nSel)'*new_a ; new_a'*new_a];
00274     sparse_A(:,nSel+1) = new_a;
00275 
00276   ---------------------------------------------------------------------------------*/
00277 void* CWDSVMOcas::add_new_cut_helper( void* ptr)
00278 {
00279     wdocas_thread_params_add* p = (wdocas_thread_params_add*) ptr;
00280     CWDSVMOcas* o = p->wdocas;
00281     int32_t start = p->start;
00282     int32_t end = p->end;
00283     int32_t string_length = o->string_length;
00284     //uint32_t nDim=(uint32_t) o->w_dim;
00285     uint32_t cut_length=p->cut_length;
00286     uint32_t* new_cut=p->new_cut;
00287     int32_t* w_offsets = o->w_offsets;
00288     float64_t* y = o->lab;
00289     int32_t alphabet_size = o->alphabet_size;
00290     float32_t* wd_weights = o->wd_weights;
00291     int32_t degree = o->degree;
00292     CStringFeatures<uint8_t>* f = o->features;
00293     float64_t normalization_const = o->normalization_const;
00294 
00295     // temporary vector
00296     float32_t* new_a = p->new_a;
00297     //float32_t* new_a = new float32_t[nDim];
00298     //memset(new_a, 0, sizeof(float32_t)*nDim);
00299 
00300     int32_t* val=new int32_t[cut_length];
00301     for (int32_t j=start; j<end; j++)
00302     {
00303         int32_t offs=o->w_dim_single_char*j;
00304         memset(val,0,sizeof(int32_t)*cut_length);
00305         int32_t lim=CMath::min(degree, string_length-j);
00306         int32_t len;
00307 
00308         for (int32_t k=0; k<lim; k++)
00309         {
00310             bool free_vec;
00311             uint8_t* vec = f->get_feature_vector(j+k, len, free_vec);
00312             float32_t wd = wd_weights[k]/normalization_const;
00313 
00314             for(uint32_t i=0; i < cut_length; i++) 
00315             {
00316                 val[i]=val[i]*alphabet_size + vec[new_cut[i]];
00317                 new_a[offs+val[i]]+=wd * y[new_cut[i]];
00318             }
00319             offs+=w_offsets[k];
00320             f->free_feature_vector(vec, j+k, free_vec);
00321         }
00322     }
00323 
00324     //p->new_a=new_a;
00325     delete[] val;
00326     return NULL;
00327 }
00328 
00329 void CWDSVMOcas::add_new_cut(
00330     float64_t *new_col_H, uint32_t *new_cut, uint32_t cut_length,
00331     uint32_t nSel, void* ptr)
00332 {
00333     CWDSVMOcas* o = (CWDSVMOcas*) ptr;
00334     int32_t string_length = o->string_length;
00335     uint32_t nDim=(uint32_t) o->w_dim;
00336     float32_t** cuts=o->cuts;
00337     float64_t* c_bias = o->cp_bias;
00338 
00339     uint32_t i;
00340     wdocas_thread_params_add* params_add=new wdocas_thread_params_add[o->parallel->get_num_threads()];
00341     pthread_t* threads=new pthread_t[o->parallel->get_num_threads()];
00342     float32_t* new_a=new float32_t[nDim];
00343     memset(new_a, 0, sizeof(float32_t)*nDim);
00344 
00345     int32_t t;
00346     int32_t nthreads=o->parallel->get_num_threads()-1;
00347     int32_t end=0;
00348     int32_t step= string_length/o->parallel->get_num_threads();
00349 
00350     if (step<1)
00351     {
00352         nthreads=string_length-1;
00353         step=1;
00354     }
00355 
00356     for (t=0; t<nthreads; t++)
00357     {
00358         params_add[t].wdocas=o;
00359         //params_add[t].new_a=NULL;
00360         params_add[t].new_a=new_a;
00361         params_add[t].new_cut=new_cut;
00362         params_add[t].start = step*t;
00363         params_add[t].end = step*(t+1);
00364         params_add[t].cut_length = cut_length;
00365 
00366         if (pthread_create(&threads[t], NULL, &CWDSVMOcas::add_new_cut_helper, (void*)&params_add[t]) != 0)
00367         {
00368             nthreads=t;
00369             SG_SWARNING("thread creation failed\n");
00370             break;
00371         }
00372         end=params_add[t].end;
00373     }
00374 
00375     params_add[t].wdocas=o;
00376     //params_add[t].new_a=NULL;
00377     params_add[t].new_a=new_a;
00378     params_add[t].new_cut=new_cut;
00379     params_add[t].start = step*t;
00380     params_add[t].end = string_length;
00381     params_add[t].cut_length = cut_length;
00382     add_new_cut_helper(&params_add[t]);
00383     //float32_t* new_a=params_add[t].new_a;
00384 
00385     for (t=0; t<nthreads; t++)
00386     {
00387         if (pthread_join(threads[t], NULL) != 0)
00388             SG_SWARNING( "pthread_join failed\n");
00389 
00390         //float32_t* a=params_add[t].new_a;
00391         //for (i=0; i<nDim; i++)
00392         //  new_a[i]+=a[i];
00393         //delete[] a;
00394     }
00395 
00396     for(i=0; i < cut_length; i++) 
00397     {
00398         if (o->use_bias)
00399             c_bias[nSel]+=o->lab[new_cut[i]];
00400     }
00401 
00402     // insert new_a into the last column of sparse_A
00403     for(i=0; i < nSel; i++)
00404         new_col_H[i] = CMath::dot(new_a, cuts[i], nDim) + c_bias[nSel]*c_bias[i];
00405     new_col_H[nSel] = CMath::dot(new_a, new_a, nDim) + CMath::sq(c_bias[nSel]);
00406 
00407     cuts[nSel]=new_a;
00408     //CMath::display_vector(new_col_H, nSel+1, "new_col_H");
00409     //CMath::display_vector(cuts[nSel], nDim, "cut[nSel]");
00410     //
00411     delete[] threads;
00412     delete[] params_add;
00413 }
00414 
00415 void CWDSVMOcas::sort( float64_t* vals, uint32_t* idx, uint32_t size)
00416 {
00417     CMath::qsort_index(vals, idx, size);
00418 }
00419 
00420 /*----------------------------------------------------------------------
00421   sparse_compute_output( output ) does the follwing:
00422 
00423   output = data_X'*W;
00424   ----------------------------------------------------------------------*/
00425 void* CWDSVMOcas::compute_output_helper(void* ptr)
00426 {
00427     wdocas_thread_params_output* p = (wdocas_thread_params_output*) ptr;
00428     CWDSVMOcas* o = p->wdocas;
00429     int32_t start = p->start;
00430     int32_t end = p->end;
00431     float32_t* out = p->out;
00432     float64_t* output = p->output;
00433     int32_t* val = p->val;
00434 
00435     CStringFeatures<uint8_t>* f=o->get_features();
00436 
00437     int32_t degree = o->degree;
00438     int32_t string_length = o->string_length;
00439     int32_t alphabet_size = o->alphabet_size;
00440     int32_t* w_offsets = o->w_offsets;
00441     float32_t* wd_weights = o->wd_weights;
00442     float32_t* w= o->w;
00443 
00444     float64_t* y = o->lab;
00445     float64_t normalization_const = o->normalization_const;
00446 
00447 
00448     for (int32_t j=0; j<string_length; j++)
00449     {
00450         int32_t offs=o->w_dim_single_char*j;
00451         for (int32_t i=start ; i<end; i++)
00452             val[i]=0;
00453 
00454         int32_t lim=CMath::min(degree, string_length-j);
00455         int32_t len;
00456 
00457         for (int32_t k=0; k<lim; k++)
00458         {
00459             bool free_vec;
00460             uint8_t* vec=f->get_feature_vector(j+k, len, free_vec);
00461             float32_t wd = wd_weights[k];
00462 
00463             for (int32_t i=start; i<end; i++) // quite fast 1.9s
00464             {
00465                 val[i]=val[i]*alphabet_size + vec[i];
00466                 out[i]+=wd*w[offs+val[i]];
00467             }
00468 
00469             /*for (int32_t i=0; i<nData/4; i++) // slowest 2s
00470             {
00471                 uint32_t x=((uint32_t*) vec)[i];
00472                 int32_t ii=4*i;
00473                 val[ii]=val[ii]*alphabet_size + (x&255);
00474                 val[ii+1]=val[ii+1]*alphabet_size + ((x>>8)&255);
00475                 val[ii+2]=val[ii+2]*alphabet_size + ((x>>16)&255);
00476                 val[ii+3]=val[ii+3]*alphabet_size + (x>>24);
00477                 out[ii]+=wd*w[offs+val[ii]];
00478                 out[ii+1]+=wd*w[offs+val[ii+1]];
00479                 out[ii+2]+=wd*w[offs+val[ii+2]];
00480                 out[ii+3]+=wd*w[offs+val[ii+3]];
00481             }*/
00482 
00483             /*for (int32_t i=0; i<nData>>3; i++) // fastest on 64bit: 1.5s
00484             {
00485                 uint64_t x=((uint64_t*) vec)[i];
00486                 int32_t ii=i<<3;
00487                 val[ii]=val[ii]*alphabet_size + (x&255);
00488                 val[ii+1]=val[ii+1]*alphabet_size + ((x>>8)&255);
00489                 val[ii+2]=val[ii+2]*alphabet_size + ((x>>16)&255);
00490                 val[ii+3]=val[ii+3]*alphabet_size + ((x>>24)&255);
00491                 val[ii+4]=val[ii+4]*alphabet_size + ((x>>32)&255);
00492                 val[ii+5]=val[ii+5]*alphabet_size + ((x>>40)&255);
00493                 val[ii+6]=val[ii+6]*alphabet_size + ((x>>48)&255);
00494                 val[ii+7]=val[ii+7]*alphabet_size + (x>>56);
00495                 out[ii]+=wd*w[offs+val[ii]];
00496                 out[ii+1]+=wd*w[offs+val[ii+1]];
00497                 out[ii+2]+=wd*w[offs+val[ii+2]];
00498                 out[ii+3]+=wd*w[offs+val[ii+3]];
00499                 out[ii+4]+=wd*w[offs+val[ii+4]];
00500                 out[ii+5]+=wd*w[offs+val[ii+5]];
00501                 out[ii+6]+=wd*w[offs+val[ii+6]];
00502                 out[ii+7]+=wd*w[offs+val[ii+7]];
00503             }*/
00504             offs+=w_offsets[k];
00505             f->free_feature_vector(vec, j+k, free_vec);
00506         }
00507     }
00508 
00509     for (int32_t i=start; i<end; i++)
00510         output[i]=y[i]*o->bias + out[i]*y[i]/normalization_const;
00511 
00512     //CMath::display_vector(o->w, o->w_dim, "w");
00513     //CMath::display_vector(output, nData, "out");
00514     return NULL;
00515 }
00516 
00517 void CWDSVMOcas::compute_output( float64_t *output, void* ptr )
00518 {
00519     CWDSVMOcas* o = (CWDSVMOcas*) ptr;
00520     int32_t nData=o->num_vec;
00521     wdocas_thread_params_output* params_output=new wdocas_thread_params_output[o->parallel->get_num_threads()];
00522     pthread_t* threads = new pthread_t[o->parallel->get_num_threads()];
00523 
00524     float32_t* out=new float32_t[nData];
00525     int32_t* val=new int32_t[nData];
00526     memset(out, 0, sizeof(float32_t)*nData);
00527 
00528     int32_t t;
00529     int32_t nthreads=o->parallel->get_num_threads()-1;
00530     int32_t end=0;
00531     int32_t step= nData/o->parallel->get_num_threads();
00532 
00533     if (step<1)
00534     {
00535         nthreads=nData-1;
00536         step=1;
00537     }
00538 
00539     for (t=0; t<nthreads; t++)
00540     {
00541         params_output[t].wdocas=o;
00542         params_output[t].output=output;
00543         params_output[t].out=out;
00544         params_output[t].val=val;
00545         params_output[t].start = step*t;
00546         params_output[t].end = step*(t+1);
00547 
00548         //SG_SPRINT("t=%d start=%d end=%d output=%p\n", t, params_output[t].start, params_output[t].end, params_output[t].output);
00549         if (pthread_create(&threads[t], NULL, &CWDSVMOcas::compute_output_helper, (void*)&params_output[t]) != 0)
00550         {
00551             nthreads=t;
00552             SG_SWARNING("thread creation failed\n");
00553             break;
00554         }
00555         end=params_output[t].end;
00556     }
00557 
00558     params_output[t].wdocas=o;
00559     params_output[t].output=output;
00560     params_output[t].out=out;
00561     params_output[t].val=val;
00562     params_output[t].start = step*t;
00563     params_output[t].end = nData;
00564     compute_output_helper(&params_output[t]);
00565     //SG_SPRINT("t=%d start=%d end=%d output=%p\n", t, params_output[t].start, params_output[t].end, params_output[t].output);
00566 
00567     for (t=0; t<nthreads; t++)
00568     {
00569         if (pthread_join(threads[t], NULL) != 0)
00570             SG_SWARNING( "pthread_join failed\n");
00571     }
00572     delete[] threads;
00573     delete[] params_output;
00574     delete[] val;
00575     delete[] out;
00576 }
00577 /*----------------------------------------------------------------------
00578   sq_norm_W = compute_W( alpha, nSel ) does the following:
00579 
00580   oldW = W;
00581   W = sparse_A(:,1:nSel)'*alpha;
00582   sq_norm_W = W'*W;
00583   dp_WoldW = W'*oldW';
00584 
00585   ----------------------------------------------------------------------*/
00586 void CWDSVMOcas::compute_W(
00587     float64_t *sq_norm_W, float64_t *dp_WoldW, float64_t *alpha, uint32_t nSel,
00588     void* ptr)
00589 {
00590     CWDSVMOcas* o = (CWDSVMOcas*) ptr;
00591     uint32_t nDim= (uint32_t) o->w_dim;
00592     CMath::swap(o->w, o->old_w);
00593     float32_t* W=o->w;
00594     float32_t* oldW=o->old_w;
00595     float32_t** cuts=o->cuts;
00596     memset(W, 0, sizeof(float32_t)*nDim);
00597     float64_t* c_bias = o->cp_bias;
00598     float64_t old_bias=o->bias;
00599     float64_t bias=0;
00600 
00601     for (uint32_t i=0; i<nSel; i++)
00602     {
00603         if (alpha[i] > 0)
00604             CMath::vec1_plus_scalar_times_vec2(W, (float32_t) alpha[i], cuts[i], nDim);
00605 
00606         bias += c_bias[i]*alpha[i];
00607     }
00608 
00609     *sq_norm_W = CMath::dot(W,W, nDim) +CMath::sq(bias);
00610     *dp_WoldW = CMath::dot(W,oldW, nDim) + bias*old_bias;;
00611     //SG_PRINT("nSel=%d sq_norm_W=%f dp_WoldW=%f\n", nSel, *sq_norm_W, *dp_WoldW);
00612 
00613     o->bias = bias;
00614     o->old_bias = old_bias;
00615 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

SHOGUN Machine Learning Toolbox - Documentation