Skip to content

Commit

Permalink
parallelize all libsvm learners
Browse files Browse the repository at this point in the history
however, speedup is really only marginal.
  • Loading branch information
Soeren Sonnenburg committed Sep 26, 2011
1 parent df28c58 commit 0c743b2
Showing 1 changed file with 111 additions and 104 deletions.
215 changes: 111 additions & 104 deletions src/shogun/classifier/svm/SVM_libsvm.cpp
Expand Up @@ -216,6 +216,21 @@ class QMatrix {
float64_t max_train_time;
};

class LibSVMKernel;

// helper struct for threaded processing
struct Q_THREAD_PARAM
{
int32_t i;
int32_t start;
int32_t end;
Qfloat* data;
float64_t* y;
const LibSVMKernel* q;
};

extern Parallel* sg_parallel;

class LibSVMKernel: public QMatrix {
public:
LibSVMKernel(int32_t l, svm_node * const * x, const svm_parameter& param);
Expand All @@ -229,6 +244,94 @@ class LibSVMKernel: public QMatrix {
if(x_square) CMath::swap(x_square[i],x_square[j]);
}

static void* compute_Q_parallel_helper(void* p)
{
Q_THREAD_PARAM* params= (Q_THREAD_PARAM*) p;
int32_t i=params->i;
int32_t start=params->start;
int32_t end=params->end;
float64_t* y=params->y;
Qfloat* data=params->data;
const LibSVMKernel* q=params->q;

if (y) // two class
{
for(int32_t j=start;j<end;j++)
data[j] = (Qfloat) y[i]*y[j]*q->kernel_function(i,j);
}
else // one class, eps svr
{
for(int32_t j=start;j<end;j++)
data[j] = (Qfloat) q->kernel_function(i,j);
}

return NULL;
}

void compute_Q_parallel(Qfloat* data, float64_t* lab, int32_t i, int32_t start, int32_t len) const
{
int32_t num_threads=sg_parallel->get_num_threads();
if (num_threads < 2)
{
Q_THREAD_PARAM params;
params.i=i;
params.start=start;
params.end=len;
params.y=lab;
params.data=data;
params.q=this;
compute_Q_parallel_helper((void*) &params);
}
else
{
int32_t total_num=(len-start);
pthread_t* threads = SG_MALLOC(pthread_t, num_threads-1);
Q_THREAD_PARAM* params = SG_MALLOC(Q_THREAD_PARAM, num_threads);
int32_t step= total_num/num_threads;

int32_t t;

num_threads--;
for (t=0; t<num_threads; t++)
{
params[t].i=i;
params[t].start=t*step;
params[t].end=(t+1)*step;
params[t].y=lab;
params[t].data=data;
params[t].q=this;

int code=pthread_create(&threads[t], NULL,
compute_Q_parallel_helper, (void*)&params[t]);

if (code != 0)
{
SG_SWARNING("Thread creation failed (thread %d of %d) "
"with error:'%s'\n",t, num_threads, strerror(code));
num_threads=t;
break;
}
}

params[t].i=i;
params[t].start=t*step;
params[t].end=len;
params[t].y=lab;
params[t].data=data;
params[t].q=this;
compute_Q_parallel_helper(&params[t]);

for (t=0; t<num_threads; t++)
{
if (pthread_join(threads[t], NULL) != 0)
SG_SWARNING("pthread_join of thread %d/%d failed\n", t, num_threads);
}

SG_FREE(params);
SG_FREE(threads);
}
}

inline float64_t kernel_function(int32_t i, int32_t j) const
{
return kernel->kernel(x[i]->index,x[j]->index);
Expand Down Expand Up @@ -1243,12 +1346,14 @@ class SVC_QMC: public LibSVMKernel
int32_t start;
if((start = cache->get_data(i,&data,len)) < len)
{
compute_Q_parallel(data, NULL, i, start, len);

for(int32_t j=start;j<len;j++)
{
if (y[i]==y[j])
data[j] = factor*(nr_class-1)*kernel_function(i,j);
data[j] *= (factor*(nr_class-1));
else
data[j] = -factor*kernel_function(i,j);
data[j] *= (-factor);
}
}
return data;
Expand Down Expand Up @@ -1597,19 +1702,6 @@ float64_t Solver_NUMC::calculate_rho()
}


extern Parallel* sg_parallel;

// helper struct for threaded processing
struct Q_THREAD_PARAM
{
int32_t i;
int32_t start;
int32_t end;
Qfloat* data;
float64_t* y;
const LibSVMKernel* q;
};

//
// Q matrices for various formulations
//
Expand All @@ -1626,92 +1718,12 @@ class SVC_Q: public LibSVMKernel
QD[i]= (Qfloat)kernel_function(i,i);
}

static void* compute_Q_parallel_helper(void* p)
{
Q_THREAD_PARAM* params= (Q_THREAD_PARAM*) p;
int32_t i=params->i;
int32_t start=params->start;
int32_t end=params->end;
float64_t* y=params->y;
Qfloat* data=params->data;
const LibSVMKernel* q=params->q;

for(int32_t j=start;j<end;j++)
data[j] = (Qfloat) y[i]*y[j]*q->kernel_function(i,j);

return NULL;
}

void compute_Q_parallel(Qfloat* data, int32_t i, int32_t start, int32_t len) const
{
int32_t num_threads=sg_parallel->get_num_threads();
if (num_threads < 2)
{
Q_THREAD_PARAM params;
params.i=i;
params.start=start;
params.end=len;
params.y=y;
params.data=data;
params.q=this;
compute_Q_parallel_helper((void*) &params);
}
else
{
int32_t total_num=(len-start);
pthread_t* threads = SG_MALLOC(pthread_t, num_threads-1);
Q_THREAD_PARAM* params = SG_MALLOC(Q_THREAD_PARAM, num_threads);
int32_t step= total_num/num_threads;

int32_t t;

num_threads--;
for (t=0; t<num_threads; t++)
{
params[t].i=i;
params[t].start=t*step;
params[t].end=(t+1)*step;
params[t].y=y;
params[t].data=data;
params[t].q=this;

int code=pthread_create(&threads[t], NULL,
compute_Q_parallel_helper, (void*)&params[t]);

if (code != 0)
{
SG_SWARNING("Thread creation failed (thread %d of %d) "
"with error:'%s'\n",t, num_threads, strerror(code));
num_threads=t;
break;
}
}

params[t].i=i;
params[t].start=t*step;
params[t].end=len;
params[t].y=y;
params[t].data=data;
params[t].q=this;
compute_Q_parallel_helper(&params[t]);

for (t=0; t<num_threads; t++)
{
if (pthread_join(threads[t], NULL) != 0)
SG_SWARNING("pthread_join of thread %d/%d failed\n", t, num_threads);
}

SG_FREE(params);
SG_FREE(threads);
}
}

Qfloat *get_Q(int32_t i, int32_t len) const
{
Qfloat *data;
int32_t start;
if((start = cache->get_data(i,&data,len)) < len)
compute_Q_parallel(data, i, start, len);
compute_Q_parallel(data, y, i, start, len);

return data;
}
Expand Down Expand Up @@ -1759,10 +1771,8 @@ class ONE_CLASS_Q: public LibSVMKernel
Qfloat *data;
int32_t start;
if((start = cache->get_data(i,&data,len)) < len)
{
for(int32_t j=start;j<len;j++)
data[j] = (Qfloat) kernel_function(i,j);
}
compute_Q_parallel(data, NULL, i, start, len);

return data;
}

Expand Down Expand Up @@ -1825,10 +1835,7 @@ class SVR_Q: public LibSVMKernel
Qfloat *data;
int32_t real_i = index[i];
if(cache->get_data(real_i,&data,l) < l)
{
for(int32_t j=0;j<l;j++)
data[j] = (Qfloat)kernel_function(real_i,j);
}
compute_Q_parallel(data, NULL, real_i, 0, l);

// reorder and copy
Qfloat *buf = buffer[next_buffer];
Expand Down

0 comments on commit 0c743b2

Please sign in to comment.