📄 svm_common.c
字号:
/************************************************************************/
/* */
/* svm_common.c */
/* */
/* Definitions and functions used in both svm_learn and svm_classify. */
/* */
/* Author: Thorsten Joachims */
/* Date: 02.07.04 */
/* */
/* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
/* */
/* This software is available for non-commercial use only. It must */
/* not be modified and distributed without prior permission of the */
/* author. The author is not responsible for implications from the */
/* use of this software. */
/* */
/************************************************************************/
# include "ctype.h"
# include "svm_common.h"
# include "kernel.h" /* this contains a user supplied kernel */
#define MAX(x,y) ((x) < (y) ? (y) : (x))
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#define SIGN(x) ((x) > (0) ? (1) : (((x) < (0) ? (-1) : (0))))
long verbosity; /* verbosity level (0-4) */
long kernel_cache_statistic;
double classify_example(MODEL *model, DOC *ex)
/* classifies one example */
{
register long i;
register double dist;
if((model->kernel_parm.kernel_type == LINEAR) && (model->lin_weights))
return(classify_example_linear(model,ex));
dist=0;
for(i=1;i<model->sv_num;i++) {
dist+=kernel(&model->kernel_parm,model->supvec[i],ex)*model->alpha[i];
}
return(dist-model->b);
}
double classify_example_linear(MODEL *model, DOC *ex)
/* classifies example for linear kernel */
/* important: the model must have the linear weight vector computed */
/* use: add_weight_vector_to_linear_model(&model); */
/* important: the feature numbers in the example to classify must */
/* not be larger than the weight vector! */
{
double sum=0;
SVECTOR *f;
for(f=ex->fvec;f;f=f->next)
sum+=f->factor*sprod_ns(model->lin_weights,f);
return(sum-model->b);
}
CFLOAT kernel(KERNEL_PARM *kernel_parm, DOC *a, DOC *b)
/* calculate the kernel function */
{
double sum=0;
SVECTOR *fa,*fb;
if(kernel_parm->kernel_type == GRAM) { /* use value from explicitly */
if((a->kernelid>=0) && (b->kernelid>=0)) /* stored gram matrix */
return(kernel_parm->gram_matrix->element[MAX(a->kernelid,b->kernelid)]
[MIN(a->kernelid,b->kernelid)]);
else
return(0); /* in case it is called for unknown vector */
}
/* in case the constraints are sums of feature vector as represented
as a list of SVECTOR's with their coefficient factor in the sum,
take the kernel between all pairs */
for(fa=a->fvec;fa;fa=fa->next) {
for(fb=b->fvec;fb;fb=fb->next) {
if(fa->kernel_id == fb->kernel_id)
sum+=fa->factor*fb->factor*single_kernel(kernel_parm,fa,fb);
}
}
return(sum);
}
CFLOAT single_kernel(KERNEL_PARM *kernel_parm, SVECTOR *a, SVECTOR *b)
/* calculate the kernel function between two vectors */
{
kernel_cache_statistic++;
switch(kernel_parm->kernel_type) {
case LINEAR: /* linear */
return((CFLOAT)sprod_ss(a,b));
case POLY: /* polynomial */
return((CFLOAT)pow(kernel_parm->coef_lin*sprod_ss(a,b)+kernel_parm->coef_const,(double)kernel_parm->poly_degree));
case RBF: /* radial basis function */
if(a->twonorm_sq<0) a->twonorm_sq=sprod_ss(a,a);
if(b->twonorm_sq<0) a->twonorm_sq=sprod_ss(b,b);
return((CFLOAT)exp(-kernel_parm->rbf_gamma*(a->twonorm_sq-2*sprod_ss(a,b)+b->twonorm_sq)));
case SIGMOID:/* sigmoid neural net */
return((CFLOAT)tanh(kernel_parm->coef_lin*sprod_ss(a,b)+kernel_parm->coef_const));
case CUSTOM: /* custom-kernel supplied in file kernel.h*/
return((CFLOAT)custom_kernel(kernel_parm,a,b));
default: printf("Error: Unknown kernel function\n"); exit(1);
}
}
SVECTOR *create_svector(WORD *words,char *userdefined,double factor)
{
SVECTOR *vec;
long fnum,i;
fnum=0;
while(words[fnum].wnum) {
fnum++;
}
fnum++;
vec = (SVECTOR *)my_malloc(sizeof(SVECTOR));
vec->words = (WORD *)my_malloc(sizeof(WORD)*(fnum));
for(i=0;i<fnum;i++) {
vec->words[i]=words[i];
}
vec->twonorm_sq=-1;
fnum=0;
while(userdefined[fnum]) {
fnum++;
}
fnum++;
vec->userdefined = (char *)my_malloc(sizeof(char)*(fnum));
for(i=0;i<fnum;i++) {
vec->userdefined[i]=userdefined[i];
}
vec->kernel_id=0;
vec->next=NULL;
vec->factor=factor;
return(vec);
}
SVECTOR *create_svector_shallow(WORD *words,char *userdefined,double factor)
/* unlike 'create_svector' this does not copy words and userdefined */
{
SVECTOR *vec;
vec = (SVECTOR *)my_malloc(sizeof(SVECTOR));
vec->words = words;
vec->twonorm_sq=-1;
vec->userdefined=userdefined;
vec->kernel_id=0;
vec->next=NULL;
vec->factor=factor;
return(vec);
}
SVECTOR *create_svector_n(double *nonsparsevec, long maxfeatnum, char *userdefined, double factor)
{
SVECTOR *vec;
long fnum,i;
fnum=0;
for(i=1;i<=maxfeatnum;i++)
if(nonsparsevec[i] != 0)
fnum++;
vec = (SVECTOR *)my_malloc(sizeof(SVECTOR));
vec->words = (WORD *)my_malloc(sizeof(WORD)*(fnum+1));
fnum=0;
for(i=1;i<=maxfeatnum;i++) {
if(nonsparsevec[i] != 0) {
vec->words[fnum].wnum=i;
vec->words[fnum].weight=nonsparsevec[i];
fnum++;
}
}
vec->words[fnum].wnum=0;
vec->twonorm_sq=-1;
fnum=0;
while(userdefined[fnum]) {
fnum++;
}
fnum++;
vec->userdefined = (char *)my_malloc(sizeof(char)*(fnum));
for(i=0;i<fnum;i++) {
vec->userdefined[i]=userdefined[i];
}
vec->kernel_id=0;
vec->next=NULL;
vec->factor=factor;
return(vec);
}
SVECTOR *copy_svector(SVECTOR *vec)
{
SVECTOR *newvec=NULL;
if(vec) {
newvec=create_svector(vec->words,vec->userdefined,vec->factor);
newvec->next=copy_svector(vec->next);
}
return(newvec);
}
SVECTOR *copy_svector_shallow(SVECTOR *vec)
/* unlike 'copy_svector' this does not copy words and userdefined */
{
SVECTOR *newvec=NULL;
if(vec) {
newvec=create_svector_shallow(vec->words,vec->userdefined,vec->factor);
newvec->next=copy_svector_shallow(vec->next);
}
return(newvec);
}
void free_svector(SVECTOR *vec)
{
SVECTOR *next;
while(vec) {
if(vec->words)
free(vec->words);
if(vec->userdefined)
free(vec->userdefined);
next=vec->next;
free(vec);
vec=next;
}
}
void free_svector_shallow(SVECTOR *vec)
/* unlike 'free_svector' this does not free words and userdefined */
{
SVECTOR *next;
while(vec) {
next=vec->next;
free(vec);
vec=next;
}
}
double sprod_ss(SVECTOR *a, SVECTOR *b)
/* compute the inner product of two sparse vectors */
{
register CFLOAT sum=0;
register WORD *ai,*bj;
ai=a->words;
bj=b->words;
while (ai->wnum && bj->wnum) {
if(ai->wnum > bj->wnum) {
bj++;
}
else if (ai->wnum < bj->wnum) {
ai++;
}
else {
sum+=(CFLOAT)(ai->weight) * (CFLOAT)(bj->weight);
ai++;
bj++;
}
}
return((double)sum);
}
SVECTOR* multadd_ss(SVECTOR *a, SVECTOR *b, double factor)
/* compute a+factor*b of two sparse vectors */
/* Note: SVECTOR lists are not followed, but only the first
SVECTOR is used */
{
SVECTOR *vec;
register WORD *sum,*sumi;
register WORD *ai,*bj;
long veclength;
ai=a->words;
bj=b->words;
veclength=0;
while (ai->wnum && bj->wnum) {
if(ai->wnum > bj->wnum) {
veclength++;
bj++;
}
else if (ai->wnum < bj->wnum) {
veclength++;
ai++;
}
else {
veclength++;
ai++;
bj++;
}
}
while (bj->wnum) {
veclength++;
bj++;
}
while (ai->wnum) {
veclength++;
ai++;
}
veclength++;
sum=(WORD *)my_malloc(sizeof(WORD)*veclength);
sumi=sum;
ai=a->words;
bj=b->words;
while (ai->wnum && bj->wnum) {
if(ai->wnum > bj->wnum) {
(*sumi)=(*bj);
sumi->weight*=factor;
sumi++;
bj++;
}
else if (ai->wnum < bj->wnum) {
(*sumi)=(*ai);
sumi++;
ai++;
}
else {
(*sumi)=(*ai);
sumi->weight+=factor*bj->weight;
if(sumi->weight != 0)
sumi++;
ai++;
bj++;
}
}
while (bj->wnum) {
(*sumi)=(*bj);
sumi->weight*=factor;
sumi++;
bj++;
}
while (ai->wnum) {
(*sumi)=(*ai);
sumi++;
ai++;
}
sumi->wnum=0;
vec=create_svector(sum,"",1.0);
free(sum);
return(vec);
}
SVECTOR* sub_ss(SVECTOR *a, SVECTOR *b)
/* compute the difference a-b of two sparse vectors */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -