02_svm_多分类

描述

支持向量机(SVM)最初是设计用于二分类问题的,但在实际应用中经常要处理多分类问题。为了使用SVM解决多分类问题,研究者们提出了多种策略,主要分为两类:一对多(one-vs-all )和一对一(one-vs-one)。

sklearn 中的svm多分类算法实现采用的是one-vs-one;dlib虽然提供了多分类算法实现,但使用起来相对繁琐(也可以说是太灵活了)。

one-vs-one

one-vs-one 策略是一种将多类分类问题转化为多个二元分类问题的经典方法。对于具有 N 个类别的分类任务,它会训练 N*(N-1)/2 个二元分类器,每个分类器专门用于区分两个不同的类别。在预测阶段,所有二元分类器都会对测试样本进行投票,最终得票最多的类别即为预测结果。

定义trainer

这里以鸢尾花分类为例(鸢尾花分类的例子相当于编程入门的"hello world",很多机器学习的入门案例都是这三朵花)

c++ 复制代码
typedef dlib::matrix<double, 4, 1> iris_type;
typedef dlib::one_vs_one_trainer<dlib::any_trainer<iris_type>> ovo_trainer; // one-vs-one 训练器
typedef dlib::polynomial_kernel<iris_type> poly_kernel;  // 多项式核
typedef dlib::radial_basis_kernel<iris_type> rbf_kernel; // 径向基函数核

训练过程:ovo_trainer可以设置多个二分类trainer(首先要设置一个默认的二分类训练器);可以根据数据特征,指定哪些类别用特定的trainer,具体可见下例。

c++ 复制代码
void SvmOvoClassifier(const string &pfile)
{
    vector<iris_type> train_datas;
    vector<double> train_labels;
    map<int, string> label_map = LoadIrisVec(pfile, train_datas, train_labels);

    ovo_trainer trainer;
    dlib::svm_c_trainer<rbf_kernel> rbf_trainer;
    rbf_trainer.set_kernel(rbf_kernel(0.001)); // gamma 参数
    rbf_trainer.set_c(10);                     // 大C参数
    trainer.set_trainer(rbf_trainer);          // 设置默认trainer,这里是3分类问题,需要创建三个trainer,如果后面不指定,三个分类器都一样

    dlib::svm_nu_trainer<poly_kernel> poly_trianer;
    poly_trianer.set_kernel(poly_kernel(0.1, 2, 3)); // 多项式核参数
    trainer.set_trainer(poly_trianer, 2, 3);         // 指定poly_trianer处理(2,3)标签的分类;另外的(1,2)、(1,3)的分类使用rbf_trainer处理

    dlib::one_vs_one_decision_function<ovo_trainer,
                                       dlib::decision_function<rbf_kernel>,
                                       dlib::decision_function<poly_kernel>>
        learned_func = trainer.train(train_datas, train_labels);
    int ok_count = 0;
    for (int i = 0; i < train_datas.size(); i++)
    {
        iris_type ii_type = train_datas.at(i);
        double ret = learned_func(ii_type);
        if (ret == train_labels.at(i))
            ok_count += 1;
        cout << "predicted label:" << ret << "(" << label_map[ret] << ");"
             << "real label:" << label_map[train_labels.at(i)] << endl;
    }
    cout << "accurary:" << (ok_count * 1.0) / train_datas.size() << endl;
}

one-vs-all

与 one-vs-one 策略相比,one-vs-all 的优势是需要训练的分类器数量更少(N 个 vs N*(N-1)/2 个),对于类别较多的任务计算成本更低。但它可能受类别不平衡影响更大,因为每个二元分类器都要处理 "该类别" 与 "所有其他类别" 的不平衡数据。

该实现的灵活性体现在可以轻松替换基础二元分类器,例如将svm_nu_trainer替换为kernel_ridge_regression_trainer,而无需修改 one-vs-all 框架本身。

定义trainer

还以鸢尾花为例

c++ 复制代码
typedef dlib::one_vs_all_trainer<dlib::any_trainer<iris_type>> ova_trainer;

训练过程:ova_trainer也可以指定多个分类器(不推荐,如果需要多个不同的分类器,建议使用one-vs-one)

c++ 复制代码
void SvmOvaClassifier(const string &pfile)
{
    vector<iris_type> train_datas;
    vector<double> train_labels;
    map<int, string> label_map = LoadIrisVec(pfile, train_datas, train_labels);

    ova_trainer trainer;

    dlib::svm_nu_trainer<poly_kernel> poly_trianer;
    poly_trianer.set_kernel(poly_kernel(0.1, 2, 3)); // 多项式核参数
    trainer.set_trainer(poly_trianer);               // 也可以指定多个trianer,但不推荐

    // dlib::svm_c_trainer<rbf_kernel> rbf_trainer;
    // rbf_trainer.set_kernel(rbf_kernel(0.001)); // gamma 参数
    // rbf_trainer.set_c(10);                     // 大C参数
    // trainer.set_trainer(rbf_trainer, 1);       // 指定处理分类1

    dlib::one_vs_all_decision_function<ova_trainer, dlib::decision_function<poly_kernel>>
        learned_func = trainer.train(train_datas, train_labels);
    int ok_count = 0;
    for (int i = 0; i < train_datas.size(); i++)
    {
        iris_type ii_type = train_datas.at(i);
        double ret = learned_func(ii_type);
        if (ret == train_labels.at(i))
            ok_count += 1;
        cout << "predicted label:" << ret << "(" << label_map[ret] << ");"
             << "real label:" << label_map[train_labels.at(i)] << endl;
    }
    cout << "accurary:" << (ok_count * 1.0) / train_datas.size() << endl;
}

数据加载

加载iris.csv数据

c++ 复制代码
typedef struct
{
    float ft[4];
    std::string specie;
} Iris;

vector<Iris> LoadIris(const string &fpath)
{
    vector<Iris> vec;
    fstream input_file(fpath);
    string line;
    if (input_file.is_open())
    {
        getline(input_file, line); // 跳过头
        while (getline(input_file, line))
        {
            vector<string> sp_vec = SplitString(line, ',');
            if (sp_vec.size() == 0)
                continue;
            Iris iris;
            for (int i = 0; i < 4; i++)
            {
                iris.ft[i] = atof(sp_vec.at(i).c_str());
            }
            iris.specie = sp_vec.at(sp_vec.size() - 1);
            vec.push_back(iris);
        }
    }
    return vec;
}
相关推荐
Yeats_Liao1 小时前
MindSpore开发之路(二十四):MindSpore Hub:快速复用预训练模型
人工智能·分布式·神经网络·机器学习·个人开发
格林威2 小时前
传送带上运动模糊图像复原:提升动态成像清晰度的 6 个核心方案,附 OpenCV+Halcon 实战代码!
人工智能·opencv·机器学习·计算机视觉·ai·halcon·工业相机
Aurora-Borealis.3 小时前
Day27 机器学习流水线
人工智能·机器学习
黑符石5 小时前
【论文研读】Madgwick 姿态滤波算法报告总结
人工智能·算法·机器学习·imu·惯性动捕·madgwick·姿态滤波
JQLvopkk5 小时前
智能AI“学习功能”在程序开发部分的逻辑
人工智能·机器学习·计算机视觉
jiayong235 小时前
model.onnx 深度分析报告(第2篇)
人工智能·机器学习·向量数据库·向量模型
张祥6422889046 小时前
数理统计基础一
人工智能·机器学习·概率论
悟乙己6 小时前
使用TimeGPT进行时间序列预测案例解析
机器学习·大模型·llm·时间序列·预测
云和数据.ChenGuang6 小时前
人工智能实践之基于CNN的街区餐饮图片识别案例实践
人工智能·深度学习·神经网络·机器学习·cnn
人工智能培训7 小时前
什么是马尔可夫决策过程(MDP)?马尔可夫性的核心含义是什么?
人工智能·深度学习·机器学习·cnn·智能体·马尔可夫决策