dlib库中svm 例程解析

int main()
{
    // svm函数使用列向量,这里我们先定义一个方面的typedef
    // 这个 typedef 声明了一个2行1列的矩阵。如果你像包含更多维,把2修改成更多即可。
    //如果你不知道特征有多少维,你可以先把这个值设置为零,然后用的时候,用matrix.set_size()函数即可。 
    typedef matrix sample_type;


    // 核函数的定义
    //我选择了一个radial basis kernel,这个核适合我们的2维的样本。
    //你也可以使用自己定义的任何kernels,可以参考 custom_trainer_ex.cpp
    typedef radial_basis_kernel kernel_type;


    // 现在我们声明 samples和labels表示样本和其对应的标记
    std::vector samples;
    std::vector labels;




    // 给samples和labels赋值。用一个循环生成一系列的点,然后一句他们到圆心的距离来标记
    for (int r = -20; r <= 20; ++r)
    {
        for (int c = -20; c <= 20; ++c)
        {
            sample_type samp;
            samp(0) = r;
            samp(1) = c;
            samples.push_back(samp);




            //如果到圆心的距离小于10
            if (sqrt((double)r*r + c*c) <= 10)
                labels.push_back(+1);
            else
                labels.push_back(-1);




        }
    }








    // 归一化样本,减去均值,除以标准差。这是去除数值稳定性问题的好办法,防止某些值过大。
    // 做这一步,对本例的问题来说,并不是那么重要。下面的代码会教你怎么做归一化。  
    vector_normalizer normalizer;
    // 计算均值和方差,放入normalizer的成员变量中
    normalizer.train(samples);
    // 然后分别归一化每一个
    for (unsigned long i = 0; i < samples.size(); ++i)
        samples[i] = normalizer(samples[i]); 








    // 数据有了,开始训练。这里有两个超参数:C and gamma.这两个超参数
    // 将影响分类函数的性能。为了测试并选择出好的超参数,我们可以用cross_validate_trainer()
    // 来进行n-ford 交叉验证。然而,我们数据的分布还有些问题。数据有顺序,一部分全是正样本,
    // 一部分全是负样本。 前办部分和后办部分分别来自不同的分布。这将使交叉验证无效。所以我们进行
    // 随机化操作,打乱样本的严格顺序。用randomize_samples函数。
    randomize_samples(samples, labels);








    // 用我们声明的核函数来实例化svm_c_trainer对象
    svm_c_trainer trainer;




    // 现在我们循环调用一些不同的 C 和 gamma 的值来测试决策函数的性能。这是非常简单的方式。
    // 你可以看看model_selection_ex.cpp 来看看更多用复杂策略来选择较好超参数的方法
    cout << "doing cross validation" << endl;
    for (double gamma = 0.00001; gamma <= 1; gamma *= 5)
    {
        for (double C = 1; C < 100000; C *= 5)
        {
            //设置我们用的超参数
            trainer.set_kernel(kernel_type(gamma));
            trainer.set_c(C);




            cout << "gamma: " << gamma << "    C: " << C;
            // 输出交叉验证的准确度。
            // cross_validate_trainer()返回一个行向量,第一个元素为正例的准确度,第二个元素
            // 负例的准确度。
            cout << "     cross validation accuracy: " 
                 << cross_validate_trainer(trainer, samples, labels, 3);
        }
    }








    //查看上面的输出,发现C=5,gamma=0.15625 is good.so we will use them




    // 现在我们用所有的样本训练,然后得到决策函数。
    // 正样本时,决策函数将返回大于零的值。负样本是决策函数返回小于零的值。


    trainer.set_kernel(kernel_type(0.15625));
    trainer.set_c(5);
    typedef decision_function dec_funct_type;
    typedef normalized_function funct_type;




    // 这里我们实例化一个对象,这个对象可以提供一个方便的方式来存储归一化后的信息和训练得到的决策函数。
    funct_type learned_function;
    learned_function.normalizer = normalizer;  // 保存归一化信息。
    learned_function.function = trainer.train(samples, labels); // 训练并保存结果到这个对象的function中


    // 输出支持向量的数据
    cout << "\nnumber of support vectors in our learned_function is " 
         << learned_function.function.basis_vectors.size() << endl;




    // 现在来测试我们得到的决策函数在新样本上的性能
    sample_type sample;




    sample(0) = 3.123;
    sample(1) = 2;
    cout << "这是正例,分类器的输出是 " << learned_function(sample) << endl;




    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "这是正例,分类器的输出是  " << learned_function(sample) << endl;




    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "这是负例,分类器的输出是  " << learned_function(sample) << endl;




    sample(0) = 13.123;
    sample(1) = 0;
    cout << "这是负例,分类器的输出是  " << learned_function(sample) << endl;








    // 我们也可以训练一个可以返回概率的决策函数,不单单只看大于小于零的情况,下面是例子:
    typedef probabilistic_decision_function probabilistic_funct_type;  
    typedef normalized_function pfunct_type;




    pfunct_type learned_pfunct; 
    learned_pfunct.normalizer = normalizer;
    learned_pfunct.function = train_probabilistic_decision_function(trainer, samples, labels, 3);
    // 现在我们拥有的可以返回概率的决策函数.


    // 输出决策函数含有的支持向量的数目,应该与上面相同
    cout << "\nnumber of support vectors in our learned_pfunct is " 
         << learned_pfunct.function.decision_funct.basis_vectors.size() << endl;




    sample(0) = 3.123;
    sample(1) = 2;
    cout << "正例应该输出高概率值,输出概率为: " 
         << learned_pfunct(sample) << endl;




    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "正例应该输出高概率值,输出概率为: " 
         << learned_pfunct(sample) << endl;




    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "负例应该输出低概率值,输出概率为: " 
         << learned_pfunct(sample) << endl;




    sample(0) = 13.123;
    sample(1) = 0;
    cout << "负例应该输出低概率值,输出概率为: " 
         << learned_pfunct(sample) << endl;












    // 值得注意的是,dlib中的所有对象都可以序列化到文件中。所以你可以把学到的分类函数保存到磁盘中,然后稍后再从磁盘读出,使用。
    serialize("saved_function.dat") << learned_pfunct;




    //从文件中读入学到的分类函数
    deserialize("saved_function.dat") >> learned_pfunct;




    // 这里还有个例子:file_to_code_ex.cpp,输入为文件,输出为 c++代码。所以你可以用这个和std::istringstream 来保存你学习到的决策函数














    // 最后,注意到我们训练得到的决策函数包含200个支持向量。支持向量越多,计算量越大,所以dlib提供近似的性能,但更少的支持向量
    cout << "\ncross validation accuracy with only 10 support vectors: " 
         << cross_validate_trainer(reduced2(trainer,10), samples, labels, 3);




    // 打印出原来的交叉验证得分用于对比
    cout << "cross validation accuracy with all the original support vectors: " 
         << cross_validate_trainer(trainer, samples, labels, 3);




    // 你可以在保证交叉验证的性能的同时,减少支持向量的数目,减少到10个。








    // 通过如下函数操作获取减小后的决策函数:
    learned_function.function = reduced2(trainer,10).train(samples, labels);
    // 对于概率决策函数,也用类似的方法得到:
    learned_pfunct.function = train_probabilistic_decision_function(reduced2(trainer,10), samples, labels, 3);
}

你可能感兴趣的:(测试)