Algorithm-LibLinear
view release on metacpan or search on metacpan
src/liblinear/linear.cpp view on Meta::CPAN
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <locale.h>
#include "linear.h"
#include "newton.h"
int liblinear_version = LIBLINEAR_VERSION;
typedef signed char schar;
template <class T> static inline void swap(T& x, T& y) { T t=x; x=y; y=t; }
#ifndef min
template <class T> static inline T min(T x,T y) { return (x<y)?x:y; }
#endif
#ifndef max
template <class T> static inline T max(T x,T y) { return (x>y)?x:y; }
#endif
template <class S, class T> static inline void clone(T*& dst, S* src, int n)
{
dst = new T[n];
memcpy((void *)dst,(void *)src,sizeof(T)*n);
}
#define INF HUGE_VAL
#define Malloc(type,n) (type *)malloc((n)*sizeof(type))
static void print_string_stdout(const char *s)
{
fputs(s,stdout);
fflush(stdout);
}
static void print_null(const char *s) {}
static void (*liblinear_print_string) (const char *) = &print_string_stdout;
#if 1
static void info(const char *fmt,...)
{
char buf[BUFSIZ];
va_list ap;
va_start(ap,fmt);
vsprintf(buf,fmt,ap);
va_end(ap);
(*liblinear_print_string)(buf);
}
#else
static void info(const char *fmt,...) {}
#endif
class sparse_operator
{
public:
static double nrm2_sq(const feature_node *x)
{
double ret = 0;
while(x->index != -1)
{
ret += x->value*x->value;
x++;
}
return ret;
}
static double dot(const double *s, const feature_node *x)
{
double ret = 0;
while(x->index != -1)
{
ret += s[x->index-1]*x->value;
x++;
}
return ret;
}
static double sparse_dot(const feature_node *x1, const feature_node *x2)
{
double ret = 0;
while(x1->index != -1 && x2->index != -1)
{
if(x1->index == x2->index)
{
ret += x1->value * x2->value;
++x1;
++x2;
}
else
{
if(x1->index > x2->index)
++x2;
else
++x1;
}
}
return ret;
}
static void axpy(const double a, const feature_node *x, double *y)
{
while(x->index != -1)
{
y[x->index-1] += a*x->value;
x++;
}
}
};
// L2-regularized empirical risk minimization
// min_w w^Tw/2 + \sum C_i \xi(w^Tx_i), where \xi() is the loss
class l2r_erm_fun: public function
{
public:
l2r_erm_fun(const problem *prob, const parameter *param, double *C);
~l2r_erm_fun();
double fun(double *w);
double linesearch_and_update(double *w, double *d, double *f, double *g, double alpha);
int get_nr_variable(void);
protected:
virtual double C_times_loss(int i, double wx_i) = 0;
void Xv(double *v, double *Xv);
void XTv(double *v, double *XTv);
double *C;
const problem *prob;
double *wx;
double *tmp; // a working array
double wTw;
int regularize_bias;
};
l2r_erm_fun::l2r_erm_fun(const problem *prob, const parameter *param, double *C)
{
int l=prob->l;
this->prob = prob;
wx = new double[l];
tmp = new double[l];
this->C = C;
this->regularize_bias = param->regularize_bias;
}
l2r_erm_fun::~l2r_erm_fun()
{
delete[] wx;
delete[] tmp;
}
double l2r_erm_fun::fun(double *w)
{
int i;
double f=0;
int l=prob->l;
int w_size=get_nr_variable();
wTw = 0;
Xv(w, wx);
for(i=0;i<w_size;i++)
wTw += w[i]*w[i];
if(regularize_bias == 0)
wTw -= w[w_size-1]*w[w_size-1];
for(i=0;i<l;i++)
f += C_times_loss(i, wx[i]);
f = f + 0.5 * wTw;
return f;
}
int l2r_erm_fun::get_nr_variable(void)
src/liblinear/linear.cpp view on Meta::CPAN
sTs -= s[w_size-1] * s[w_size-1];
wTs -= s[w_size-1] * w[w_size-1];
}
int num_linesearch = 0;
for(num_linesearch=0; num_linesearch < max_num_linesearch; num_linesearch++)
{
double loss = 0;
for(i=0;i<l;i++)
{
double inner_product = tmp[i] * alpha + wx[i];
loss += C_times_loss(i, inner_product);
}
*f = loss + (alpha * alpha * sTs + wTw) / 2.0 + alpha * wTs;
if (*f - fold <= eta * alpha * gTs)
{
for (i=0;i<l;i++)
wx[i] += alpha * tmp[i];
break;
}
else
alpha *= 0.5;
}
if (num_linesearch >= max_num_linesearch)
{
*f = fold;
return 0;
}
else
for (i=0;i<w_size;i++)
w[i] += alpha * s[i];
wTw += alpha * alpha * sTs + 2* alpha * wTs;
return alpha;
}
void l2r_erm_fun::Xv(double *v, double *Xv)
{
int i;
int l=prob->l;
feature_node **x=prob->x;
for(i=0;i<l;i++)
Xv[i]=sparse_operator::dot(v, x[i]);
}
void l2r_erm_fun::XTv(double *v, double *XTv)
{
int i;
int l=prob->l;
int w_size=get_nr_variable();
feature_node **x=prob->x;
for(i=0;i<w_size;i++)
XTv[i]=0;
for(i=0;i<l;i++)
sparse_operator::axpy(v[i], x[i], XTv);
}
class l2r_lr_fun: public l2r_erm_fun
{
public:
l2r_lr_fun(const problem *prob, const parameter *param, double *C);
~l2r_lr_fun();
void grad(double *w, double *g);
void Hv(double *s, double *Hs);
void get_diag_preconditioner(double *M);
private:
double *D;
double C_times_loss(int i, double wx_i);
};
l2r_lr_fun::l2r_lr_fun(const problem *prob, const parameter *param, double *C):
l2r_erm_fun(prob, param, C)
{
int l=prob->l;
D = new double[l];
}
l2r_lr_fun::~l2r_lr_fun()
{
delete[] D;
}
double l2r_lr_fun::C_times_loss(int i, double wx_i)
{
double ywx_i = wx_i * prob->y[i];
if (ywx_i >= 0)
return C[i]*log(1 + exp(-ywx_i));
else
return C[i]*(-ywx_i + log(1 + exp(ywx_i)));
}
void l2r_lr_fun::grad(double *w, double *g)
{
int i;
double *y=prob->y;
int l=prob->l;
int w_size=get_nr_variable();
for(i=0;i<l;i++)
{
tmp[i] = 1/(1 + exp(-y[i]*wx[i]));
D[i] = tmp[i]*(1-tmp[i]);
tmp[i] = C[i]*(tmp[i]-1)*y[i];
}
XTv(tmp, g);
for(i=0;i<w_size;i++)
g[i] = w[i] + g[i];
if(regularize_bias == 0)
g[w_size-1] -= w[w_size-1];
}
void l2r_lr_fun::get_diag_preconditioner(double *M)
{
int i;
int l = prob->l;
int w_size=get_nr_variable();
feature_node **x = prob->x;
for (i=0; i<w_size; i++)
M[i] = 1;
if(regularize_bias == 0)
M[w_size-1] = 0;
for (i=0; i<l; i++)
{
feature_node *xi = x[i];
while (xi->index!=-1)
{
M[xi->index-1] += xi->value*xi->value*C[i]*D[i];
xi++;
}
}
}
void l2r_lr_fun::Hv(double *s, double *Hs)
{
int i;
int l=prob->l;
int w_size=get_nr_variable();
feature_node **x=prob->x;
for(i=0;i<w_size;i++)
Hs[i] = 0;
for(i=0;i<l;i++)
{
feature_node * const xi=x[i];
double xTs = sparse_operator::dot(s, xi);
xTs = C[i]*D[i]*xTs;
sparse_operator::axpy(xTs, xi, Hs);
}
for(i=0;i<w_size;i++)
Hs[i] = s[i] + Hs[i];
if(regularize_bias == 0)
Hs[w_size-1] -= s[w_size-1];
}
class l2r_l2_svc_fun: public l2r_erm_fun
{
public:
l2r_l2_svc_fun(const problem *prob, const parameter *param, double *C);
~l2r_l2_svc_fun();
void grad(double *w, double *g);
void Hv(double *s, double *Hs);
void get_diag_preconditioner(double *M);
protected:
void subXTv(double *v, double *XTv);
int *I;
int sizeI;
private:
double C_times_loss(int i, double wx_i);
};
l2r_l2_svc_fun::l2r_l2_svc_fun(const problem *prob, const parameter *param, double *C):
l2r_erm_fun(prob, param, C)
{
I = new int[prob->l];
}
l2r_l2_svc_fun::~l2r_l2_svc_fun()
{
delete[] I;
}
double l2r_l2_svc_fun::C_times_loss(int i, double wx_i)
{
double d = 1 - prob->y[i] * wx_i;
if (d > 0)
return C[i] * d * d;
else
return 0;
}
void l2r_l2_svc_fun::grad(double *w, double *g)
{
int i;
double *y=prob->y;
int l=prob->l;
int w_size=get_nr_variable();
sizeI = 0;
for (i=0;i<l;i++)
{
tmp[i] = wx[i] * y[i];
if (tmp[i] < 1)
{
tmp[sizeI] = C[i]*y[i]*(tmp[i]-1);
I[sizeI] = i;
sizeI++;
}
}
subXTv(tmp, g);
for(i=0;i<w_size;i++)
g[i] = w[i] + 2*g[i];
src/liblinear/linear.cpp view on Meta::CPAN
}
void l2r_l2_svc_fun::get_diag_preconditioner(double *M)
{
int i;
int w_size=get_nr_variable();
feature_node **x = prob->x;
for (i=0; i<w_size; i++)
M[i] = 1;
if(regularize_bias == 0)
M[w_size-1] = 0;
for (i=0; i<sizeI; i++)
{
int idx = I[i];
feature_node *xi = x[idx];
while (xi->index!=-1)
{
M[xi->index-1] += xi->value*xi->value*C[idx]*2;
xi++;
}
}
}
void l2r_l2_svc_fun::Hv(double *s, double *Hs)
{
int i;
int w_size=get_nr_variable();
feature_node **x=prob->x;
for(i=0;i<w_size;i++)
Hs[i]=0;
for(i=0;i<sizeI;i++)
{
feature_node * const xi=x[I[i]];
double xTs = sparse_operator::dot(s, xi);
xTs = C[I[i]]*xTs;
sparse_operator::axpy(xTs, xi, Hs);
}
for(i=0;i<w_size;i++)
Hs[i] = s[i] + 2*Hs[i];
if(regularize_bias == 0)
Hs[w_size-1] -= s[w_size-1];
}
void l2r_l2_svc_fun::subXTv(double *v, double *XTv)
{
int i;
int w_size=get_nr_variable();
feature_node **x=prob->x;
for(i=0;i<w_size;i++)
XTv[i]=0;
for(i=0;i<sizeI;i++)
sparse_operator::axpy(v[i], x[I[i]], XTv);
}
class l2r_l2_svr_fun: public l2r_l2_svc_fun
{
public:
l2r_l2_svr_fun(const problem *prob, const parameter *param, double *C);
void grad(double *w, double *g);
private:
double C_times_loss(int i, double wx_i);
double p;
};
l2r_l2_svr_fun::l2r_l2_svr_fun(const problem *prob, const parameter *param, double *C):
l2r_l2_svc_fun(prob, param, C)
{
this->p = param->p;
this->regularize_bias = param->regularize_bias;
}
double l2r_l2_svr_fun::C_times_loss(int i, double wx_i)
{
double d = wx_i - prob->y[i];
if(d < -p)
return C[i]*(d+p)*(d+p);
else if(d > p)
return C[i]*(d-p)*(d-p);
return 0;
}
void l2r_l2_svr_fun::grad(double *w, double *g)
{
int i;
double *y=prob->y;
int l=prob->l;
int w_size=get_nr_variable();
double d;
sizeI = 0;
for(i=0;i<l;i++)
{
d = wx[i] - y[i];
// generate index set I
if(d < -p)
{
tmp[sizeI] = C[i]*(d+p);
I[sizeI] = i;
sizeI++;
}
else if(d > p)
{
tmp[sizeI] = C[i]*(d-p);
I[sizeI] = i;
sizeI++;
}
}
subXTv(tmp, g);
for(i=0;i<w_size;i++)
g[i] = w[i] + 2*g[i];
if(regularize_bias == 0)
g[w_size-1] -= w[w_size-1];
}
// A coordinate descent algorithm for
// multi-class support vector machines by Crammer and Singer
//
// min_{\alpha} 0.5 \sum_m ||w_m(\alpha)||^2 + \sum_i \sum_m e^m_i alpha^m_i
// s.t. \alpha^m_i <= C^m_i \forall m,i , \sum_m \alpha^m_i=0 \forall i
//
// where e^m_i = 0 if y_i = m,
// e^m_i = 1 if y_i != m,
// C^m_i = C if m = y_i,
// C^m_i = 0 if m != y_i,
// and w_m(\alpha) = \sum_i \alpha^m_i x_i
//
// Given:
// x, y, C
// eps is the stopping tolerance
//
// solution will be put in w
//
// See Appendix of LIBLINEAR paper, Fan et al. (2008)
#define GETI(i) ((int) prob->y[i])
// To support weights for instances, use GETI(i) (i)
class Solver_MCSVM_CS
{
public:
Solver_MCSVM_CS(const problem *prob, int nr_class, double *C, double eps=0.1, int max_iter=100000);
~Solver_MCSVM_CS();
void Solve(double *w);
private:
void solve_sub_problem(double A_i, int yi, double C_yi, int active_i, double *alpha_new);
bool be_shrunk(int i, int m, int yi, double alpha_i, double minG);
double *B, *C, *G;
int w_size, l;
int nr_class;
int max_iter;
double eps;
const problem *prob;
};
Solver_MCSVM_CS::Solver_MCSVM_CS(const problem *prob, int nr_class, double *weighted_C, double eps, int max_iter)
{
this->w_size = prob->n;
this->l = prob->l;
this->nr_class = nr_class;
this->eps = eps;
this->max_iter = max_iter;
this->prob = prob;
this->B = new double[nr_class];
this->G = new double[nr_class];
this->C = weighted_C;
}
Solver_MCSVM_CS::~Solver_MCSVM_CS()
{
delete[] B;
delete[] G;
}
int compare_double(const void *a, const void *b)
{
if(*(double *)a > *(double *)b)
return -1;
if(*(double *)a < *(double *)b)
return 1;
return 0;
}
void Solver_MCSVM_CS::solve_sub_problem(double A_i, int yi, double C_yi, int active_i, double *alpha_new)
{
int r;
double *D;
clone(D, B, active_i);
if(yi < active_i)
D[yi] += A_i*C_yi;
qsort(D, active_i, sizeof(double), compare_double);
double beta = D[0] - A_i*C_yi;
for(r=1;r<active_i && beta<r*D[r];r++)
beta += D[r];
beta /= r;
for(r=0;r<active_i;r++)
{
if(r == yi)
( run in 1.502 second using v1.01-cache-2.11-cpan-13bb782fe5a )