65.9K
CodeProject 正在变化。 阅读更多。
Home

用于数据分析和机器学习的性能库

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2016 年 11 月 3 日

CPOL

8分钟阅读

viewsIcon

20937

探索 Intel® Data Analytics Acceleration Library C++ 编码,用于手写数字识别。

点击此处注册并下载免费的 Intel® Parallel Studio XE 30天试用版.

Intel® 数据分析加速库 (Intel® DAAL) 是一个面向数据分析的高性能库,它为在 Intel® 平台上进行数据分析和机器学习提供了优化的构建模块。Intel DAAL 中的函数涵盖了机器学习数据处理的所有阶段,从预处理、转换、分析、建模到决策制定。对于每个处理阶段,Intel DAAL 都包含针对 Intel® 架构(包括 Intel® Atom™、Intel® Core™、Intel® Xeon® 和 Intel® Xeon Phi™ 处理器)进行优化的函数和实用程序。Intel DAAL 支持批量、在线和分布式处理模式,并支持三种编程 API:C++、Java* 和 Python*。

在这里,我们将探讨一个使用 Intel DAAL 应用程序进行手写数字识别的 C++ 示例——这是一个经典的机器学习问题。有几种应用算法与之相关。支持向量机 (SVM)、主成分分析 (PCA)、朴素贝叶斯和神经网络都可以用于解决这个问题,并具有不同的预测精度。Intel DAAL 包含了其中大多数算法。我们选择 SVM 来演示 Intel DAAL 中的库算法如何在手写数字识别中使用。

在 Intel DAAL 中加载数据

在手写数字识别中,识别本质上是机器学习管道中的预测或推理阶段。给定一个手写数字,系统应该能够识别或推断出写的是哪个数字。为了让系统能够根据给定的输入预测输出,它需要一个从训练数据集学习到的训练模型,该模型赋予系统进行推理或预测的能力。在构建训练模型之前的第一步是收集训练数据。

对于我们的示例应用程序,我们使用的是可从 UCI 机器学习库 下载的公共数据,其中包含 3,823 条预处理的训练数据和 1,797 条预处理的测试数据。Intel DAAL 支持多种数据格式(CSV、SQL、HDFS 和 KDB+),以及用户定义的数据格式。在我们的示例中,我们将使用 CSV 格式。假设我们将训练数据存储在名为 digits_tra.csv 的文件中,并将测试数据存储在名为 digits_tes.csv 的文件中。

Intel DAAL 提供了一些实用程序来帮助从数据源将数据加载到内存中。在这里,我们首先定义了 trainDataSource 对象,它是一个 CSVFeatureManager,可以从 CSV 文件加载数据到内存中。在 Intel DAAL 内部,内存中的数据存储为数值表。使用 CSVFeatureManager,会自动创建一个数值表。要从 CSV 文件加载数据,只需调用成员函数 loadDataBlock()。现在数据已加载到内存中作为数值表,可以进行进一步计算。用于从 CSV 文件加载训练数据的主要 C++ 代码片段显示在 **图 1** 中。

/* Input data set parameters */
    string trainDatasetFileName = "digits_tra.csv";
    string testDatasetFileName = "digits_tes.csv";

/* Initialize FileDataSource<CSVFeatureManager> to retrieve input data from .csv file */
    FileDataSource<CSVFeatureManager> trainDataSource(trainDatasetFileName,
    DataSource::doAllocateNumericTable, DataSource::doDictionaryFromContext);

/* Load data from the data files */
    trainDataSource.loadDataBlock(nTrainObservations);
图 1 - 加载训练数据的 C++ 代码

训练基于 SVM 的手写数字识别模型

现在训练数据已加载到内存中,就可以从数据中学习并构建训练模型了。我们选择 SVM 算法进行训练。在此示例中,由于训练数据集很小,数据可以一次性全部放入内存。我们将演示使用批量处理模式。定义算法后,设置算法所需的相应参数,例如类数(在本例中为 10)。然后通过训练数据数值表 trainDataSource.getNumericTable() 将训练数据传递给算法。

通过调用 algorithm.compute(),SVM 计算将被激活。之后,训练完成。训练好的模型嵌入在 trainingResult 对象中,该对象通过调用 algorithm.getResult() 获取。训练过程的示例代码显示在 **图 2** 中。

services::SharedPtr<svm::training::Batch<> > training(new
    svm::training::Batch<>());

/* Create algorithm object for multi-class SVM training */
    multi_class_classifier::training::Batch<> algorithm;
    algorithm.parameter.nClasses = nClasses;
    algorithm.parameter.training = training;

/* Pass training dataset and dependent values to the algorithm */
    algorithm.input.set(classifier::training::data,
    trainDataSource.getNumericTable());

/* Build multi-class SVM model */
    algorithm.compute();

/* Retrieve algorithm results */
    trainingResult = algorithm.getResult();

/* Serialize the learned model into a disk file */
    ModelFileWriter writer("./model");
    writer.serializeToFile(trainingResult->get(classifier::training::model));
图 2 - 训练过程的示例代码

Intel DAAL 还提供了序列化函数,可以将训练好的模型从内存读出到文件,以及反序列化函数,可以将训练好的模型文件加载到内存中。如 **图 2** 中最后两行代码所示,我们定义了一个 ModelFileWriter,它写入一个名为 model 的文件。通过调用 writer.serializeToFile(),嵌入在 trainingResult 中的训练模型将被写入名为 model 的文件。这种序列化/反序列化实用程序在训练后,服务器可以将训练好的模型移植到客户端,客户端可以在不进行训练的情况下使用训练好的模型进行预测或推理的情况下非常有用。我们将在“手写数字识别应用”部分看到此模型文件的使用方法。

测试训练好的模型

有了训练好的模型,我们就可以进行测试了。和训练一样,我们将来自 UCI 机器学习库 的测试数据存储在一个 CSV 文件中,并使用 testDataSourceloadDataBlock() 加载。我们仍然需要为预测定义 SVM 算法对象 algorithm。算法有两个输入:测试数据和训练好的模型。测试数据通过 testDataSource.getNumericTable() 传递。在批量测试中,训练好的模型通过 trainingResult->get() 的指针传递。(在“手写数字识别应用”部分,我们将看到如何通过文件传递训练好的模型。)

设置好算法输入后,调用 algorithm.compute() 将完成测试过程。测试的示例代码显示在 **图 3** 中。可以通过调用 algorithm.getResult() 来检索测试后的预测结果。

services::SharedPtr<svm::prediction::Batch<> > prediction(new
    svm::prediction::Batch<>());

/* Initialize FileDataSource<CSVFeatureManager> to retrieve the test data from .csv file */
    FileDataSource<CSVFeatureManager> testDataSource(testDatasetFileName,
        DataSource::doAllocateNumericTable,
        DataSource::doDictionaryFromContext);
    testDataSource.loadDataBlock(nTestObservations);

/* Create algorithm object for prediction of multi-class SVM values */
    multi_class_classifier::prediction::Batch<> algorithm;

    algorithm.parameter.prediction = prediction;

/* Pass testing dataset and trained model to the algorithm */
    algorithm.input.set(classifier::prediction::data,
        testDataSource.getNumericTable());
    algorithm.input.set(classifier::prediction::model,
        trainingResult->get(classifier::training::model));

/* Predict multi-class SVM values */
    algorithm.compute();

/* Retrieve algorithm results */
    predictionResult = algorithm.getResult();
图 3 - 测试的示例代码

Intel DAAL 还包含用于计算质量指标的函数,例如混淆矩阵、平均准确率、错误率等。对于来自 UCI 机器学习库 的测试数据集,使用 SVM 得到的质量指标显示在 **图 4** 中,在整个测试数据上达到了 99.6% 的平均准确率。

图 4 - 质量指标

Intel DAAL 与 scikit-learn* 的 SVM 性能比较

SVM 算法是一个经典算法,许多机器学习框架或库在其包中都有。scikit-learn* 是一个流行的 Python 机器学习库。在 scikit-learn SVM 分类示例中,使用相同的数据集进行手写数字应用的训练和测试。我们比较了 Intel DAAL 和 scikit-learn 在训练和预测方面的 SVM 性能。结果显示在 **图 5** 中。

图 5 - Intel® 数据分析加速库 (Intel® DAAL) 相较于 scikit-learn* 在 Intel® CPU 上的 SVM 性能提升

比较是在一台配备双路 Intel® Xeon® 处理器 E5-2680 v3 @ 2.50 GHz、24 核、每个 CPU 30 MB L3 缓存、256 GB RAM 的系统上进行的。使用的操作系统是 Red Hat Enterprise Linux* Server release 6.6, 64 位。使用的库版本是 Intel DAAL 2016 Update 2 和 scikit-learn 0.16.1。

如 **图 5** 所示,在训练和测试方面,Intel DAAL 中的 SVM 都优于 scikit-learn。在训练方面,Intel DAAL 中的 SVM 比 scikit-learn 快 6.77 倍;在测试或预测方面,Intel DAAL 中的 SVM 比 scikit-learn 快 11.25 倍。

手写数字识别应用

如前所述,在服务器中学习到的训练模型可以移植到客户端进行应用。这里有一个简单的手写数字识别应用程序,其中移植了训练好的模型。这个交互式应用程序中只有预测或测试。该应用程序界面的快照显示在 **图 6** 中,为一个涂鸦框。在涂鸦框中,有两个白色的面板框。左侧较大的白色框是可以在其中一次写一个 0 到 9 的数字的地方;右侧较小的白色框显示系统认为是写在左侧面板上的数字。在 **图 6** 中,数字 3 被手写在左侧框中,系统识别出该数字,然后在右侧框中显示推断结果 3。

图 6 - 数字识别应用程序

对于此应用程序,我们一次只测试或预测一个数字。对于任何输入的数字,都会生成一个测试 CSV 文件,其中包含通过一些预处理技术提取的手写数字特征。(预处理超出了本文的范围,此处不作介绍。)现在我们有了测试数据,仍然需要一个训练好的模型作为算法对象的输入。

如上所述,我们已经构建了一个训练好的模型,并且实际上已将模型写入一个名为 model 的文件中。现在是时候从文件中加载该训练好的模型了,这意味着将模型反序列化到内存中。我们定义一个 ModelFileReader 来通过调用 reader.deserializeFromFile(pModel) 从名为 model 的文件中读取。训练好的模型将被加载到内存中,其中 pModel 是指向模型的指针。C++ 代码显示在 **图 7** 中,其中大部分代码与 **图 3** 中的相同。调用 algorithm.compute() 后,我们得到预测结果 predictionResult1,其中包含给定输入数字的标签或预测数字。

services::SharedPtr<svm::prediction::Batch<> > prediction1(new
    svm::prediction::Batch<>());

/* Initialize FileDataSource<CSVFeatureManager> to retrieve the test data from .csv file */
    FileDataSource<CSVFeatureManager> testDataSource(testDatasetFileName,
        DataSource::doAllocateNumericTable,
        DataSource::doDictionaryFromContext);
    testDataSource.loadDataBlock(1);

/* Create algorithm object for prediction of multi-class SVM values */
    multi_class_classifier::prediction::Batch<> algorithm;

algorithm.parameter.prediction = prediction1;

/* Deserialize a model from a disk file */
    ModelFileReader reader("./model");
    services::SharedPtr<multi_class_classifier::Model> pModel(new
multi_class_classifier::Model());
    reader.deserializeFromFile(pModel);

/* Pass testing dataset and trained model to the algorithm */
    algorithm.input.set(classifier::prediction::data,
testDataSource.getNumericTable());
    algorithm.input.set(classifier::prediction::model, pModel);

/* Predict multi-class SVM values */
    algorithm.compute();

/* Retrieve algorithm results */
    predictionResult1 = algorithm.getResult();

/* Retrieve predicted labels */
    predictedLabels1 = predictionResult1->get(classifier::prediction::prediction);
图 7 - C++ 代码

摘要

Intel DAAL 提供了机器学习整个管道的构建模块。通过 SVM C++ 代码片段,我们展示了如何在应用程序中使用 Intel DAAL:具体来说,如何从文件加载数据、如何构建训练模型以及如何在应用程序中应用训练好的模型。

由于 Intel DAAL 中的函数针对 Intel 架构进行了优化,因此开发人员在使用 Intel DAAL 的构建模块在 Intel 平台上进行机器学习应用时,可以获得最佳性能。正如我们所见,Intel DAAL 中的 SVM 性能优于 scikit-learn 中的 SVM。

© . All rights reserved.