libsvm源码解析

LibSvm使用说明 综述SVM支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别、分类、以及回归分析。总得来说,SVM就是通过训练得到一个超平面 ,将样本分类,保证被分类的样本中离超平面近的一些点距离超平面距离(几何间隔)最大,这些离超平面近的点叫作支持向量(之所以叫支持向量而不叫支持样本是因为每个样本均认为是一个向量,每个特征是向量的一个元素)。LibSvm 阅读详情


1. 引言

libsvm函数包的组织结构图如下图所示。主文件路径中包含了核心的C/C++程序和例子数据,以及java、python版本的实现。tool子文件路径中包含了一些检验数据格式以及选择svm参数的tool,其为辅助作用。
这里写图片描述

在此,本文先以svm.h及svm.cpp做简单结构分析。

  • svm.h中主要是定义了4个结构体,分别是svm_node、svm_problem、svm_parameter、svm_model,然后就是19个函数的声明。如svm_node结构体:
struct svm_node
{
    int index;
    double value;
};

这个结构体用于存储单一向量中的单个特征。例如:向量x1={0.002,0.345,4.000,5.677},则用svm_node来存储就是使用一个包含5个svm_node的数组来存储这个4维向量,内存中的表示如下:

12345
0.0020.3454.0005.677空
  • svm.cpp是核心文件,实现了svm算法的核心功能,里面总共有Cache、Kernel、ONE_CLASS_Q、QMatrix、Solver、Solver_NU、SVC_Q、SVR_Q 8个类,如下图所示:
    这里写图片描述

上述文件暂不做详细分析,列出c/c++语言版本的意图旨在对比其他语言,如java版本,用以表明不同语言的实现基本一致。后续内容将围绕java版本来原理分析。这样写的目的在于告诉读者,如果你熟悉的语言不是java,大可不必担心语言问题。如上述svm_node结构及几个核心类,在java中同样实现,如下图所示。
1


2 代码分析

2.1 svm_node代码分析

svm_node.java
整个文件源码非常少:

package libsvm;
public class svm_node implements java.io.Serializable
{
    public int index; //存储单一向量的索引
    public double value; //存储对应索引位置的值
}

2.2 svm_problem代码分析

svm_problem.java如下

package libsvm;
public class svm_problem implements java.io.Serializable
{
    public int l; //记录样本总数
    public double[] y; //样本所属类别(标签,如+1,-1)的数组
    public svm_node[][] x; //存储样本内容出标签外的信息
}

这个class结构存储本次参加运算的所有样本及其所属类别,一个示意图如下:
这里写图片描述

2.3 svm_parameter代码分析

svm_parameter.java

package libsvm;
public class svm_parameter implements Cloneable,java.io.Serializable
{
    /* svm_type */
    public static final int C_SVC = 0;
    public static final int NU_SVC = 1;
    public static final int ONE_CLASS = 2;
    public static final int EPSILON_SVR = 3;
    public static final int NU_SVR = 4;

    /* kernel_type */
    public static final int LINEAR = 0;
    public static final int POLY = 1;
    public static final int RBF = 2;
    public static final int SIGMOID = 3;
    public static final int PRECOMPUTED = 4;

    public int svm_type;
    public int kernel_type;
    public int degree;  // for poly 即,多项式核
    public double gamma;    // for poly/rbf/sigmoid  (rbf为高斯核径向基)
    public double coef0;    // for poly/sigmoid

    // these are for training only
    public double cache_size; // in MB
    public double eps;  // stopping criteria
    public double C;    // for C_SVC, EPSILON_SVR and NU_SVR
    public int nr_weight;       // for C_SVC
    public int[] weight_label;  // for C_SVC
    public double[] weight;     // for C_SVC
    public double nu;   // for NU_SVC, ONE_CLASS, and NU_SVR
    public double p;    // for EPSILON_SVR
    public int shrinking;   // use the shrinking heuristics
    public int probability; // do probability estimates
}

该class是对svm类型及参数的设置,在svm.java中会用到。

2.3 svm_model代码分析

svm_model.java

package libsvm;
public class svm_model implements java.io.Serializable
{
    public svm_parameter param; // parameter
    public int nr_class;        // number of classes, = 2 in regression/one class svm
    public int l;           // total #SV
    public svm_node[][] SV; // SVs (SV[l])
    public double[][] sv_coef;  // coefficients for SVs in decision functions (sv_coef[k-1][l])
    public double[] rho;        // constants in decision functions (rho[k*(k-1)/2])
    public double[] probA;         // pariwise probability information
    public double[] probB;
    public int[] sv_indices;       // sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set

    // for classification only

    public int[] label;     // label of each class (label[k])
    public int[] nSV;       // number of SVs for each class (nSV[k])
                // nSV[0] + nSV[1] + ... + nSV[k-1] = l
};

用于保存训练后的训练模型model,在predict中要用到。


3 核心代码分析

svm.java总共有2000多行代码,实现了svm算法的核心功能,里面总共有Cache、Kernel、ONE_CLASS_Q、QMatrix、Solver、Solver_NU、SVC_Q、SVR_Q 8个内部类。

1 Cache

class Cache {
    private final int l;  //数据总条目
    private long size;    //缓存大小
    private final class head_t
    {
        head_t prev, next;  // a cicular list 定义了链表节点
        float[] data;
        int len;        // data[0,len) is cached in this entry
    }
    private final head_t[] head; //链表的一个数组
    /*
     * head[0] -------------- head[1] ------------- haad[2]
     *   |                     |                     |
     * prev,next,len,data[0]  ...                  ...
     *               data[1]  ...                  ...
     */
    private head_t lru_head;

    Cache(int l_, long size_)  //Cache的构造函数,带数据个数和缓存大小
    {...}
    private void lru_delete(head_t h) //删除当前节点
    {
        // delete from current location
        h.prev.next = h.next;
        h.next.prev = h.prev;
    }
    ...
}

这个类的主要功能是:负责运算所涉及的内存管理,包括申请、释放等。上述class head_t,它是一个双向链表方便前后内存的访问。
参考:https://blog.youkuaiyun.com/linj_m/article/details/19571663

2 Kernel

Kernel类主要是为SVM的核函数服务的,里面实现了SVM常用的核函数。
其中几个常用核函数如下所示:(一般情况下,使用RBF核函数能取得很好的效果)

这里写图片描述
参考:https://blog.youkuaiyun.com/linj_m/article/details/19574623
上述涉及矩阵运算
即:

  1. 线性核(linear):主要用于线性可分的情况,我们可以看到特征空间到输入空间的维度是一样的,其参数少速度快,对于线性可分数据,其分类效果很理想,因此我们通常首先尝试用线性核函数来做分类,看看效果如何,如果不行再换别的

    K(x,z)=<x,z>

    行向量x与z向量积。如x=[1 2 3],z=[11 22 33],则<x,z>=1*11+2822+3*33。

  2. 多项式核(poly):多项式核函数可以实现将低维的输入空间映射到高纬的特征空间,但是多项式核函数的参数多,当多项式的阶数比较高的时候,核矩阵的元素值将趋于无穷大或者无穷小,计算复杂度会大到无法计算

    K(x,z)=(<x,z>+c)^d

    其中x,z是向量。d=1,c=0时退化为线性核。

  3. 高斯径向基核(RBF):高斯径向基函数是一种局部性强的核函数,其可以将一个样本映射到一个更高维的空间内,该核函数是应用最广的一个,无论大样本还是小样本都有比较好的性能,而且其相对于多项式核函数参数要少,因此大多数情况下在不知道用什么核函数的时候,优先使用高斯核函数

  4. 多层感知器核(sigmoid):采用sigmoid核函数,支持向量机实现的就是一种多层神经网络

Kernel继承于QMatrix,Kernel主要实现了以下方法:
powi

/*
 * 乘方函数重写,效率相比自带函数较高
 */
private static double powi(double base, int times)

kernel_function

/*
 * 根据不同的kernel_type分类。返回第i,j两行向量的核运算结果
 * i,j表示前向量第i行,后向量j列的输入数据,此函数仅得到运算矩阵中的一个点
 */
double kernel_function(int i, int j)

Kernel

/*
 * Kernel带参构造器,将样本总数l、除分类标签数据外的数据svm_node[][]、参数传入
 */
Kernel(int l, svm_node[][] x_, svm_parameter param)

dot

static double dot(svm_node[] x, svm_node[] y) //参数为两行向量(单行单列向量)

k_function

/*
 * 根据不同的kernel_type分类,及参数。返回向量x、向量j的核运算结果。
 * (和kernel_function类似)
 */
static double k_function(svm_node[] x, svm_node[] y,
                svm_parameter param)

完整代码及注释如下:

//
// Kernel evaluation
//
// the static method k_function is for doing single kernel evaluation
// the constructor of Kernel prepares to calculate the l*l kernel matrix
// the member function get_Q is for getting one column from the Q Matrix
//
abstract class QMatrix {
    abstract float[] get_Q(int column, int len);
    abstract double[] get_QD();
    abstract void swap_index(int i, int j);
};

abstract class Kernel extends QMatrix {
    private svm_node[][] x;
    private final double[] x_square;

    // svm_parameter
    private final int kernel_type;
    private final int degree;
    private final double gamma;
    private final double coef0;

    abstract float[] get_Q(int column, int len);
    abstract double[] get_QD();

    void swap_index(int i, int j)
    {
        do {svm_node[] tmp=x[i]; x[i]=x[j]; x[j]=tmp;} while(false);
        if(x_square != null) do {double tmp=x_square[i]; x_square[i]=x_square[j]; x_square[j]=tmp;} while(false);
    }

    /*
     * 乘方函数重写,效率相比自带函数较高
     */
    private static double powi(double base, int times)
    {
        double tmp = base, ret = 1.0;

        for(int t=times; t>0; t/=2)
        {
            if(t%2==1) ret*=tmp;
            tmp = tmp * tmp;
        }
        return ret;
    }

    /*
     * 根据不同的kernel_type分类。返回第i,j两行向量的核运算结果
     */
    double kernel_function(int i, int j) //i,j表示前向量第i行,后向量j列的输入数据,此函数仅得到运算矩阵中的一个点
    {
        switch(kernel_type)   //kernel_type是int型的参数
        {
            case svm_parameter.LINEAR: //0 线性核
                // K(x,z)=<x,z>
                return dot(x[i],x[j]); //对应索引相乘再相加
            case svm_parameter.POLY:   //1 多项式核
                return powi(gamma*dot(x[i],x[j])+coef0,degree);
            case svm_parameter.RBF:    //2
                return Math.exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j])));
            case svm_parameter.SIGMOID:
                return Math.tanh(gamma*dot(x[i],x[j])+coef0);
            case svm_parameter.PRECOMPUTED:
                return x[i][(int)(x[j][0].value)].value;
            default:
                return 0;   // java
        }
    }

    /*
     * Kernel带参构造器,将样本总数l、除分类标签数据外的数据svm_node[][]、参数传入
     */
    Kernel(int l, svm_node[][] x_, svm_parameter param)
    {
        this.kernel_type = param.kernel_type;
        this.degree = param.degree;
        this.gamma = param.gamma;
        this.coef0 = param.coef0;

        x = (svm_node[][])x_.clone();//将数据备份一次

        if(kernel_type == svm_parameter.RBF) //当高斯径向基核时
        {
            x_square = new double[l];
            for(int i=0;i<l;i++)
                x_square[i] = dot(x[i],x[i]);
        }
        else x_square = null;
    }

    /*
     * 将x,y对应索引相乘相加。判断索引相等,是因为允许值为0是index省略。
     *  11 22 33
     *  1  3  5  
     *  则结果11*1+22*3+33*5
     */
    static double dot(svm_node[] x, svm_node[] y) //参数为两行向量(单行单列向量)
    {
        double sum = 0;
        int xlen = x.length;
        int ylen = y.length;
        int i = 0;
        int j = 0;
        while(i < xlen && j < ylen)
        {
            if(x[i].index == y[j].index) //如果是对应的位置
                sum += x[i++].value * y[j++].value;
            else
            {
                if(x[i].index > y[j].index)
                    ++j;
                else
                    ++i;
            }
        }
        return sum;
    }

    /*
     * 根据不同的kernel_type分类,及参数。返回向量x、向量j的核运算结果。(和kernel_function类似)
     */
    static double k_function(svm_node[] x, svm_node[] y,
                    svm_parameter param)
    {
        switch(param.kernel_type)
        {
            case svm_parameter.LINEAR:
                return dot(x,y);
            case svm_parameter.POLY:
                return powi(param.gamma*dot(x,y)+param.coef0,param.degree);
            case svm_parameter.RBF:
            {
                double sum = 0;
                int xlen = x.length;
                int ylen = y.length;
                int i = 0;
                int j = 0;
                while(i < xlen && j < ylen)
                {
                    if(x[i].index == y[j].index)
                    {
                        double d = x[i++].value - y[j++].value;
                        sum += d*d;
                    }
                    else if(x[i].index > y[j].index)
                    {
                        sum += y[j].value * y[j].value;
                        ++j;
                    }
                    else
                    {
                        sum += x[i].value * x[i].value;
                        ++i;
                    }
                }

                while(i < xlen)
                {
                    sum += x[i].value * x[i].value;
                    ++i;
                }

                while(j < ylen)
                {
                    sum += y[j].value * y[j].value;
                    ++j;
                }

                return Math.exp(-param.gamma*sum);
            }
            case svm_parameter.SIGMOID:
                return Math.tanh(param.gamma*dot(x,y)+param.coef0);
            case svm_parameter.PRECOMPUTED:
                return  x[(int)(y[0].value)].value;
            default:
                return 0;   // java
        }
    }
}

3 Solver

现在我们涉及到的Solver类是一个SVM优化求解的实现技术:SMO(Sequential Minimal Optimization)即序列最小优化算法。libsvm中最原始的Solver的代码有六百多行,再加上各种变形就上千行了,为了好理解,我们先来看看理论问题。
代码的开头如下:

// An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918
// Solves:
//
//  min 0.5(\alpha^T Q \alpha) + p^T \alpha
//
//      y^T \alpha = \delta
//      y_i = +1 or -1
//      0 <= alpha_i <= Cp for y_i = 1
//      0 <= alpha_i <= Cn for y_i = -1
//
// Given:
//
//  Q, p, y, Cp, Cn, and an initial feasible point \alpha
//  l is the size of vectors and matrices
//  eps is the stopping tolerance
//
// solution will be put in \alpha, objective value will be put in obj
//

SMO(Sequential Minimal Optimization)是针对求解SVM问题的Lagrange对偶问题,一个二次规划式,开发的高效算法。传统的二次规划算法的计算开销正比于训练集的规模,而SMO基于问题本身的特性(KKT条件约束)对这个特殊的二次规划问题的求解过程进行优化。对偶问题中我们最后求解的变量只有Lagrange乘子向量,这个算法的基本思想就是每次都只选取一对,固定向量其他维度的元素的值,然后进行优化,直至收敛。
链接:https://www.zhihu.com/question/40546280/answer/88539689

SMO干了什么?

SMO算法是将分解算法思想推向极致得出的,即每次迭代仅优化两个点的最小子集
这里写图片描述
这里写图片描述
其中,yi=1或-1

为什么SMO跑的那么快
这里写图片描述
参考:https://www.zhihu.com/question/40546280?sort=created

SMO代码:

void Solve(int l, QMatrix Q, double[] p_, byte[] y_,
       double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, int shrinking)
{
    this.l = l;
    this.Q = Q;
    QD = Q.get_QD();
    p = (double[])p_.clone();
    y = (byte[])y_.clone();
    alpha = (double[])alpha_.clone();
    this.Cp = Cp;
    this.Cn = Cn;
    this.eps = eps;
    this.unshrink = false;

    // initialize alpha_status 初始化alpha
    {
        alpha_status = new byte[l];
        for(int i=0;i<l;i++)
            update_alpha_status(i);
    }

    // initialize active set (for shrinking)
    {
        active_set = new int[l];
        for(int i=0;i<l;i++)
            active_set[i] = i;
        active_size = l;
    }

    // initialize gradient
    {
        G = new double[l];
        G_bar = new double[l];
        int i;
        for(i=0;i<l;i++)
        {
            G[i] = p[i];
            G_bar[i] = 0;
        }
        for(i=0;i<l;i++)
            if(!is_lower_bound(i))
            {
                float[] Q_i = Q.get_Q(i,l);
                double alpha_i = alpha[i];
                int j;
                for(j=0;j<l;j++)
                    G[j] += alpha_i*Q_i[j];
                if(is_upper_bound(i))
                    for(j=0;j<l;j++)
                        G_bar[j] += get_C(i) * Q_i[j];
            }
    }

    // optimization step 优化步骤

    int iter = 0;
    int max_iter = Math.max(10000000, l>Integer.MAX_VALUE/100 ? Integer.MAX_VALUE : 100*l);
    int counter = Math.min(l,1000)+1;
    int[] working_set = new int[2];

    while(iter < max_iter) //迭代次数小于最大迭代次数时
    {
        // show progress and do shrinking

        if(--counter == 0)
        {
            counter = Math.min(l,1000);
            if(shrinking!=0) do_shrinking();
            svm.info(".");
        }

        if(select_working_set(working_set)!=0)
        {
            // reconstruct the whole gradient
            reconstruct_gradient();
            // reset active set size and check
            active_size = l;
            svm.info("*");
            if(select_working_set(working_set)!=0)
                break;
            else
                counter = 1;    // do shrinking next iteration
        }

        int i = working_set[0];
        int j = working_set[1];

        ++iter;

        // 更新两个alpha
        // update alpha[i] and alpha[j], handle bounds carefully

        float[] Q_i = Q.get_Q(i,active_size);
        float[] Q_j = Q.get_Q(j,active_size);

        double C_i = get_C(i);
        double C_j = get_C(j);

        double old_alpha_i = alpha[i];
        double old_alpha_j = alpha[j];

        if(y[i]!=y[j])
        {
            double quad_coef = QD[i]+QD[j]+2*Q_i[j];
            if (quad_coef <= 0)
                quad_coef = 1e-12;
            double delta = (-G[i]-G[j])/quad_coef;
            double diff = alpha[i] - alpha[j];
            alpha[i] += delta;
            alpha[j] += delta;

            if(diff > 0)
            {
                if(alpha[j] < 0)
                {
                    alpha[j] = 0;
                    alpha[i] = diff;
                }
            }
            else
            {
                if(alpha[i] < 0)
                {
                    alpha[i] = 0;
                    alpha[j] = -diff;
                }
            }
            if(diff > C_i - C_j)
            {
                if(alpha[i] > C_i)
                {
                    alpha[i] = C_i;
                    alpha[j] = C_i - diff;
                }
            }
            else
            {
                if(alpha[j] > C_j)
                {
                    alpha[j] = C_j;
                    alpha[i] = C_j + diff;
                }
            }
        }
        else
        {
            double quad_coef = QD[i]+QD[j]-2*Q_i[j];
            if (quad_coef <= 0)
                quad_coef = 1e-12;
            double delta = (G[i]-G[j])/quad_coef;
            double sum = alpha[i] + alpha[j];
            alpha[i] -= delta;
            alpha[j] += delta;

            if(sum > C_i)
            {
                if(alpha[i] > C_i)
                {
                    alpha[i] = C_i;
                    alpha[j] = sum - C_i;
                }
            }
            else
            {
                if(alpha[j] < 0)
                {
                    alpha[j] = 0;
                    alpha[i] = sum;
                }
            }
            if(sum > C_j)
            {
                if(alpha[j] > C_j)
                {
                    alpha[j] = C_j;
                    alpha[i] = sum - C_j;
                }
            }
            else
            {
                if(alpha[i] < 0)
                {
                    alpha[i] = 0;
                    alpha[j] = sum;
                }
            }
        }

        // update G

        double delta_alpha_i = alpha[i] - old_alpha_i;
        double delta_alpha_j = alpha[j] - old_alpha_j;

        for(int k=0;k<active_size;k++)
        {
            G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
        }

        // update alpha_status and G_bar

        {
            boolean ui = is_upper_bound(i);
            boolean uj = is_upper_bound(j);
            update_alpha_status(i);
            update_alpha_status(j);
            int k;
            if(ui != is_upper_bound(i))
            {
                Q_i = Q.get_Q(i,l);
                if(ui)
                    for(k=0;k<l;k++)
                        G_bar[k] -= C_i * Q_i[k];
                else
                    for(k=0;k<l;k++)
                        G_bar[k] += C_i * Q_i[k];
            }

            if(uj != is_upper_bound(j))
            {
                Q_j = Q.get_Q(j,l);
                if(uj)
                    for(k=0;k<l;k++)
                        G_bar[k] -= C_j * Q_j[k];
                else
                    for(k=0;k<l;k++)
                        G_bar[k] += C_j * Q_j[k];
            }
        }

    }

    if(iter >= max_iter)
    {
        if(active_size < l)
        {
            // reconstruct the whole gradient to calculate objective value
            reconstruct_gradient();
            active_size = l;
            svm.info("*");
        }
        System.err.print("\nWARNING: reaching max number of iterations\n");
    }

    // calculate rho

    si.rho = calculate_rho();

    // calculate objective value
    {
        double v = 0;
        int i;
        for(i=0;i<l;i++)
            v += alpha[i] * (G[i] + p[i]);

        si.obj = v/2;
    }

    // put back the solution
    {
        for(int i=0;i<l;i++)
            alpha_[active_set[i]] = alpha[i];
    }

    si.upper_bound_p = Cp;
    si.upper_bound_n = Cn;

    //打印迭代次数
    svm.info("\noptimization finished, #iter = "+iter+"\n");
}
关于libSVM的一些总结 libsvm相关参数 阅读详情

相关推荐

MATLAB支持向量机实战:LIBSVM源码解析与调参避坑指南

支持向量机(SVM)是一种基于最大间隔的经典分类算法,通过核函数将低维数据映射到高维空间实现线性可分。其核心在于寻找最优超平面,仅依赖支持向量决定决策边界,因此对小样本场景尤为友好。在工程实践中,LIBSVM 作为跨语言的开源工具箱,提供了统一的参数体系(如 -c、-g、-t),便于模型迁移与复现。典型应用包括课程设计、二分类实验及快速验证。本文结合 MATLAB 源码包与 heart_scale 数据集,详解从训练、预测到网格搜索调参的完整链路,并梳理常见报错与避坑方法。

weixin_28700411的博客 234

libsvm库简介及使用

libsvm库简介及使用

网络资源是无限的 2万+

支持向量机回归预测实战:libsvm MATLAB源码解析与调参指南

支持向量机(SVM)是一种强大的机器学习算法,通过核函数将数据映射到高维空间,解决非线性回归问题。其核心原理是寻找一个间隔带,允许epsilon宽度的误差容忍,从而提升模型泛化能力。在工程实践中,SVM回归常用于金融预测、信号处理等场景。本文基于libsvm工具包,提供一份完整的MATLAB回归预测源码,涵盖数据归一化、参数调优、核函数选择及常见避坑指南,帮助快速实现SVR模型并优化预测性能。

weixin_29031161的博客 301

Libsvm使用笔记【matlab】

​ 代码流程 I. 清空环境变量 II. 导入数据 III. 数据归一化 IV. SVM创建/训练(RBF核函数) V. SVM仿真测试 VI. 绘图 ​

arispy的博客 8587

SVM源码:libsvm

官方网站 http://www.csie.ntu.edu.tw/~cjlin/libsvm/ 参考网页 http://baike.baidu.com/view/598089.htm 实现语言:C语言 LIBSVM是台湾大学林智仁(Lin Chih-Jen)副教授等开发设计的一个简单、易于使用和快速有效的SVM模式识别与回归的软件包,他不但提供了编译好的可在Windows系列系统的执行文件,还提供了源代码,方便改进、修改以及在其它操作系统上应用;该软件还有一个特点,就是对SVM所涉及的参数调节相对比较少,提供了很多的默认参数,利用这些默认参数就可以解决很多问题;并且提供了交互检验(Cross Validation)的功能。该软件包可以在http://www.csie.ntu.edu.tw/~cjlin/免费获得。该软件可以解决C-SVM分类、-SVM分类、-SVM回归和-SVM回归等问题,包括基于一对一算法的多类模式识别问题。SVM用于模式识别或回归时,SVM方法及其参数、核函数及其参数的选择,目前国际上还没有形成一个统一的模式,也就是说最优SVM算法参数选择还只能是凭借经验、实验对比、大范围的搜寻或者利用软件包提供的交互检验功能进行寻优。

汽车电缆选型实战:基于ISO 19642-3~12的7类电缆电压/材料/场景对照表

本文详细解析了基于ISO 19642-3~12标准的7类汽车电缆选型实战,涵盖电压等级、导体材料和场景应用的对照表。通过全参数速查表和典型选型陷阱分析,帮助工程师快速掌握从低压信号线到高压动力电缆的选型逻辑,提升新能源汽车与智能驾驶技术的安全性和可靠性。

weixin_29043895的博客 364

LibSvm使用说明和LibSvm源码解析

综述SVM支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别、分类、以及回归分析。总得来说,SVM就是通过训练得到一个超平面 ,将样本分类,保证被分类的样本中离超平面近的一些点距离超平面距离(几何间隔)最大,这些离超平面近的点叫作支持向量(之所以叫支持向量而不叫支持样本是因为每个样本均认为是一个向量,每个特征是向量的一个元素)。LibSvm...

haoji007的博客 4万+

告别专业软件!用QGIS+GDAL免费搞定S-57电子海图,附全套符号库和样式文件

本文详细介绍了如何利用免费开源工具QGIS和GDAL处理S-57电子海图,包括数据转换、符号库配置和专业可视化方案。通过实战指南,用户无需依赖昂贵的商业软件,即可实现从S-57到SHP的转换及专业级海图制作,特别适合预算有限的个人和小型机构。

weixin_33701294的博客 391

LibSvm源码解析~算法

算法流程如下图所示,是2.6版本C-SVC型svm算法实现流程,核函数采用常用的RBF函数。 函数解析算法原理归纳

苏的专栏 2317

LMS Virtual.Lab二次开发:声学仿真结果导出方法(VBScript、Python)

Siemens LMS Virtual.Lab 提供一套集成软件平台用以模拟机械系统的品质属性,如结构完整性、振动噪声、耐久性、系统动力学特性、驾驶的平顺性及操纵的稳定性等。

爱看书的小沐 6015

NDVI空间分布变化Slope趋势分析与F检验(自用)

1.NDVI数据预处理2.一元线性回归分析3.Slope趋势分析与F检验

什么都学亿点点的博客 9017

libsvm源码解析2

关于svm_train函数分析 svm_train结构 1 svm_model 参考: http://doc.okbase.net/bentuwuying/archive/259870.html 关于svm_train函数分析 java使用svm_train时,有如下格式: public static void main(String[] args) thro...

王小禾 468

【可不卸载重装】VS2019新建项目里没有CUDA选项

问题:VS2019 新建项目里没有CUDA选项,vs也属性没有cuda。这是因为你在Visual Studio 2019安装之前,先安装了CUDA Toolkit。

qq_62844901的博客 1318

LibSVM支持向量回归详解

LibSVM是是台湾林智仁(Chih-Jen Lin)教授2001年开发的一套支持向量机的库,可以很方便的对数据做分类或回归。由于LibSVM程序小,运用灵活,输入参数少,并且是开源的,易于扩展,因此成为目前国内应用最多的SVM的库,同时sklearn.svm也是使用的该库。 网络上对于LibSVM源码的讲解有很多,但个人感觉绝大多数讲解的不够清晰,很多都是贴个理论公式图片再粘段代码就一带而过。并...

KunBB的博客 7755

2025虚幻游戏逆向工程解包尝试

2025虚幻游戏逆向工程解包指南 本文详细介绍了虚幻引擎5游戏逆向解包的完整流程,主要包括获取AES密钥、生成映射文件和导出资源三个关键步骤。作者在实际操作中遇到诸多难题:AES密钥获取工具存在加壳保护问题,映射文件生成器依赖复杂的VS编译环境,DLL注入工具的使用也存在技术门槛。通过多次尝试,作者发现部分游戏可直接搜索现成的AES密钥,而映射文件生成需要额外下载Memcury依赖库才能正常编译。文章提供了相关工具的下载链接和具体操作说明,但同时也指出每个环节都可能出现意外状况,逆向工程实际执行过程远比理论

wsdchong的博客 6144

数十个锂电池充放电电路,锂电池充放电芯片

关乎锂电池供电的产品,在锂电池上,需要三个电路系统:1,锂电池保护电路,2,锂电池充电电路,3,锂电池输出电路。 内容目录: 单节的锂电池保护电路单节为3.7V锂电池(也叫4.2V)和3.8V锂电池(也叫4.35V) 单节的锂电池充电电路即锂电池保护板 单节的锂电池输出电路锂电池转换稳压输出为:1.2V,3.3V,5V,12V等等 两节的锂电池保护电路两节串联7.4V锂电池(也叫8.4V) 两节的锂电池充电电路即两节锂电池保护板 两节...

kuakewei123的博客 1万+

SVM支持向量机和libsvm的使用

svn支持向量机和libsvm的使用

木木雨的博客 1949

「UG/NX」多功能dll集成一个dll的三种方法

C++多功能集成一个dll的三种方法。

何曾参静谧的博客 1390

libsvm 2.6 的代码注释

这是我在网上找的pdf转成txt的。希望对触svm的新手有点帮助.上海交通大学模式分析与机器智能实验室LibSVM-2.6 程序代码注释上海交通大学模式分析与机器智能实验室我不经心地,服下你调好的毒我知道今后我将万劫不复但是你的红唇仍让我屈服四月的樱花火红满天我和你的梦,却要一以何处去缱绻?虽然人间的情爱万万千千世上已有太多崩毁的誓言七个黑夜,七个白天我为你写下的歌,彩绘的纸笺却只

zfjiayoujiayou的专栏 420

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

别再为MinGW报错发愁了!手把手教你搞定Matlab 2023b下的LibSVM 3.32安装

本文详细指导如何在Matlab 2023b环境下正确安装和配置LibSVM 3.32,解决MinGW编译器报错问题。从MinGW-w64的精准安装到LibSVM源码的优化编译,提供完整的实战步骤和常见故障排查方案,帮助用户高效完成机器学习工具包的部署。

weixin_30617695的博客 410

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

libSVM源码分析

转载请注明原载地址:http://blog.youkuaiyun.com/xinhanggebuguake/article/details/8705648    在此之前,上海交大模式分析与机器智能实验室对2.6版本的svm.cpp做了部分注解,《LibSVM学习(四)——逐步深入LibSVM》也介绍了libSVM的思路,很精彩。而我写这篇博客更侧重与理解算法流程与具体代码的结合点。(环境:LibSVM2

冰枫的随笔 8838

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: 《数据算法Hadoop/Spark》读书笔记4--topN
下一篇: libsvm源码解析2
王小禾
博客等级 码龄11年 80粉丝 291原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值