使用 Intel® 数据分析加速库解决现实世界的机器学习问题
在本文中,我们将基于来自著名的 Kaggle 平台(用于预测建模和数据挖掘竞赛)的两个实际机器学习问题,讨论可用于选择正确算法的标准,这些竞赛中数据挖掘人员竞争以创建最佳模型。
Oleg Kremnyov,技术实习生; Ivan Kuzmin,软件工程经理; 以及 Gennady Fedorov,软件技术咨询工程师; 英特尔公司
机器学习在统计学、数据挖掘和人工智能领域扮演着重要且日益增长的角色。随着数据的飞速增长,有充分的理由相信从数据中学习将变得更加普遍——并且是未来业务增长的必要组成部分。同时,选择正确的算法和库来解决给定问题取决于许多因素,包括
- 问题类别(例如,分类、回归)
- 输入数据
- 所需性能
- 预测准确性
- 模型可解释性
这给机器学习的广泛采用带来了障碍,因为机器学习需要多样化的技能集。
在本文中,我们将基于来自著名的 Kaggle 平台(用于预测建模和数据挖掘竞赛)的两个实际机器学习问题,讨论可用于选择正确算法的标准。我们将使用实现以下算法的库:
- Scikit-learn*,Python* 数据科学家中最受欢迎的库,
- R,数据分析和统计计算的语言,以及
- Intel® 数据分析加速库 (Intel® DAAL),一个性能库,为英特尔® 平台上的数据分析和机器学习提供优化的构建块。
实际机器学习通常需要较高的 CPU 和内存要求,这使得 Intel® Xeon Phi™ 处理器成为理想平台。Intel DAAL 提供了一种快速构建针对 Intel® Xeon® 和 Intel Xeon Phi 处理器进行优化的机器学习应用程序的方法。我们将演示如何在两个实际机器学习问题上使用 Intel DAAL 进行 KNN(K-近邻)、Boosting 和支持向量机 (SVM),这两个问题都来自 Kaggle:叶子分类 和 Titanic:从灾难中学习的机器学习,并与 scikit-learn 和 R 的相同算法进行比较结果。
为什么选择 Kaggle?
Kaggle 是一个预测建模和分析竞赛平台,公司和研究人员在此发布他们的数据,来自世界各地的统计学家和数据挖掘人员竞争创建最佳模型。1 截至 2016 年 5 月,Kaggle 已拥有超过 536,000 名注册用户,即“Kagglers”。该社区遍布 194 个国家,是世界上最大的、最多样化的社区之一。自成立以来,Kaggle 已举办了 200 多场数据科学竞赛。
每场竞赛的目标是为给定的实际问题创建最佳模型。模型通常通过分析其在测试数据集上的预测准确性来评估。您可以通过提交在测试数据集上的预测,并在排行榜上查看结果来即时评估您的模型。
我们将评估由不同算法和库创建的模型,以查看它们在 Kaggle 竞赛中的表现。
叶子分类
世界上有近五十万种植物。物种分类历来是一个难题,常常导致重复识别。这项 Kaggle 挑战是利用叶子图像和提取的特征(例如形状、边缘和纹理)来准确识别 99 种植物,以训练一个分类器。训练数据包含 990 张叶子图像,测试数据包含 594 张图像(图 1)。每个图像还提供了三组特征:形状连续描述符、内部纹理直方图和精细边缘直方图(图 2)。对于每种特征,每个叶子样本都提供一个 64 属性向量。
一种方法是将一系列机器学习算法应用于训练数据,评估其在验证数据上的准确性,然后找到最优算法和超参数。Scikit-learn,Python 数据科学家中最受欢迎的机器学习库,提供了广泛的算法。在 Kaggle kernel 中,我们分析了 10 种算法的预测准确性。线性判别分析和 KNN 算法在验证数据上表现最佳(有关详细结果,请参阅 Kaggle kernel)。
这是 Python (scikit-learn) 中的线性判别分析
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
clf = LinearDiscriminantAnalysis()
clf.fit(X_train, y_train)
test_predictions = favorite_clf.predict(X_test)
以及 Python (scikit-learn) 中的 KNN
from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(k=4)
clf.fit(X_train, y_train)
test_predictions = favorite_clf.predict(X_test)
在 R 中,您也可以应用线性判别分析和 KNN。
R 中的线性判别分析
library (MASS) r <- lda(formula = Species ~ ., data = train) plda = predict(object = r, newdata = test) test_predictions = plda$class
R 中的 KNN
library(class)
test_predictions = knn(X_train, X_test, y_train, k=4)
Intel DAAL 提供了一个可扩展的 KNN2 版本,它使用 KD-tree 算法和底层优化,使其在 Intel® 架构上速度极快,同时还能提供更好的准确性。
Python (Intel DAAL) 中的 KNN 训练阶段
from daal.algorithms.kdtree_knn_classification import training, prediction
from daal.algorithms import classifier, kdtree_knn_classification
trainAlg = kdtree_knn_classification.training.Batch()
trainAlg.input.set(classifier.training.data, X_train)
trainAlg.input.set(classifier.training.labels, y_train)
trainAlg.parameter.k = 4
trainingResult = trainAlg.compute()
Python (Intel DAAL) 中的 KNN 预测阶段
predictAlg = kdtree_knn_classification.prediction.Batch()
predictAlg.input.setTable(classifier.prediction.data, X_test)
predictAlg.input.setModel(classifier.prediction.model, trainingResult.get(classifier.training.model))
predictAlg.compute()
predictionResult = predictAlg.getResult()
test_predictions = predictionResult.get(classifier.prediction.prediction)
图 3 和图 4 显示了性能比较图。有关用于基准测试的系统配置的详细信息,请参阅本文末尾的“配置和使用的工具”。
图 5 显示了准确性比较图
如果将 KNN 应用于低维数据,可以提高 KNN 的准确性。根据统计决策理论,如果我们知道条件(离散)分布P(G|X),其中G)是需要预测的标签,并且我们使用 0-1 损失函数,那么我们预测Ĝ(x) = GkifP(Gk|X = x) = maxgEGP(g|X = x)。KNN 分类假设P(Gk|X = x)在x的邻域内是常数。显然,维度数越大,包含 k 个训练样本的邻域就越大。在此问题中,我们没有大量的样本,因此将邻域作为条件的替代将惨败。收敛性仍然成立,但收敛速度随着维度的增加而降低。有关更详细的解释,请参阅《统计学习要素》3 的第 2.4 至 2.5 节。
通过使用线性判别分析 (LDA) 算法预处理原始数据,可以提高 KNN 的准确性。在我们的方法中,我们使用 LDA (nComponents=40) 预处理输入数据,并在预处理数据上训练 KNN 模型。
使用 LDA 进行预处理 (Python)
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis lda = LinearDiscriminantAnalysis(n_components = 40) X_train_reduced = lda.fit_transform(X_train, y_train) X_test_reduced = lda.transform(X_test)
Python (scikit-learn) 中的 KNN
from sklearn.neighbors import KNeighborsClassifier clf = KNeighborsClassifier(k=4) clf.fit(X_train_reduced, y_train) test_predictions = favorite_clf.predict(X_test_reduced)
使用 LDA 进行预处理 (R)
library (MASS) r <- lda(formula = Species ~ ., data = train) plda = predict(object = r, newdata = train) X_train_reduced = plda$x plda = predict(object = r, newdata = test) X_test_reduced = plda$x
R (class) 中的 KNN
library (class) test_predictions = knn(X_train_reduced, X_test_reduced, y_train, k=4)
Python (Intel DAAL) 中的 KNN 训练阶段
from daal.algorithms.kdtree_knn_classification import training, prediction from daal.algorithms import classifier, kdtree_knn_classification trainAlg = kdtree_knn_classification.training.Batch() trainAlg.input.set(classifier.training.data, X_train_reduced) trainAlg.input.set(classifier.training.labels, y_train_reduced) trainAlg.parameter.k = 4 trainingResult = trainAlg.compute()
Python (Intel DAAL) 中的 KNN 预测阶段
predictAlg = kdtree_knn_classification.prediction.Batch() predictAlg.input.setTable(classifier.prediction.data, X_test_reduced) predictAlg.input.setModel(classifier.prediction.model, trainingResult.get(classifier.training.model)) predictAlg.compute() predictionResult = predictAlg.getResult() test_predictions = predictionResult.get(classifier.prediction.prediction)
图 6、7 和 8 显示了应用数据预处理的结果。
显然,特征工程在机器学习中起着关键作用,并且良好的特征选择对于实现准确的预测至关重要。此外,Intel DAAL 在测试的库中实现了最佳的准确性和性能。
Titanic:从灾难中学习的机器学习
另一个 Kaggle 竞赛基于 RMS Titanic 的沉没,这是历史上最臭名昭著的沉船事故之一。1912 年 4 月 15 日,在首次航行中,Titanic 在撞上冰山后沉没,导致 2,224 名乘客和船员中有 1,502 人死亡。这场耸人听闻的悲剧震惊了世界,并促使制定了更严格的船舶安全法规。这里的挑战是分析不同类别的乘客和船员,并预测他们之中谁在这场悲剧中幸存下来。输入数据包含图 9 中显示的特征。有关详细信息,请参阅 Kaggle 上的 数据概述。
一种方法是将数据预处理成信息丰富的特征向量,用于训练机器学习模型。然后应在预处理数据上尝试几种分类器,以找出哪些算法表现最佳。在此 Kaggle kernel 中,进行了特征工程。从原始特征中构建了以下特征(见图 10):乘客等级、性别、年龄(通过特征分箱转换)、乘客票价(通过特征分箱转换)、登船港口、是否独自一人(如果该人没有兄弟姐妹/配偶/子女/父母在 Titanic 上,则为真)、头衔(Mrs./Miss/Mr./Master)。然后,测试了 scikit-learn 中的 10 种算法,并比较了它们的预测准确性。具有高斯核的 SVM 分类器提供了最佳准确性(有关详细结果,请参阅 Kaggle kernel)。SVM 参数是通过交叉验证获得的。
Python (scikit-learn) 中的 SVM
from sklearn.svm import SVC clf = SVC(C = 5, gamma = 1.5) clf.fit(X_train, y_train) test_predictions = favorite_clf.predict(X_test)
R 中的 SVM
model <- svm(X_train, y_train, gamma=1.5, cost=5) test_predictions <- predict(model, X_test)
具有高斯核的 SVM 涉及大量耗时的指数计算。在 Intel DAAL 中,这些计算针对 Intel 架构进行了高度优化,使我们能够快速创建 SVM 模型。
Python (Intel DAAL) 中的 SVM 训练阶段
from daal.algorithms.svm import prediction, training from daal.algorithms import kernel_function, classifier import daal.algorithms.kernel_function.rbf trainAlg = svm.training.Batch() trainAlg.input.set(classifier.training.data, X_train) trainAlg.input.set(classifier.training.labels, y_train) kernel = kernel_function.rbf.Batch() kernel.parameter.sigma = 1.5 trainAlg.parameter.C = 5 trainAlg.parameter.kernel = kernel trainAlg.parameter.cacheSize = 60000000 trainingResult = trainAlg.compute()
Python (Intel DAAL) 中的 SVM 预测阶段
predictAlg = svm.prediction.Batch() predictAlg.input.setTable(classifier.prediction.data, X_test) predictAlg.input.setModel(classifier.prediction.model, trainingResult.get(classifier.training.model)) predictAlg.parameter.kernel = kernel predictAlg.compute() predictionResult = predictAlg.getResult() test_predictions = predictionResult.get(classifier.prediction.prediction)
图 11 和图 12 显示了性能比较图。
图 13 显示了准确性比较图
我们发现 Intel DAAL 和 scikit-learn 产生了最佳准确性,并且 Intel DAAL 具有最佳性能。
现在我们将 Boosting 分类器应用于此分类问题。Boosting 是过去 20 年中引入的最强大的学习思想之一。Boosting 的思想是结合许多弱分类器的输出来产生一个强大的委员会3。我们将考虑以下 Boosting 算法:
- AdaBoost*
- BrownBoost*
- LogitBoost*
- 梯度提升
有许多资源4, 5, 6 提供了对这些算法的详细解释。
Python (scikit-learn), AdaBoost
from sklearn.ensemble import AdaBoostClassifier clf = AdaBoostClassifier(n_estimators=1000) clf.fit(X_train, y_train) test_predictions = favorite_clf.predict(X_test)
Python (scikit-learn), 梯度提升
from sklearn.ensemble import GradientBoostingClassifier clf = GradientBoostingClassifier(n_estimators=1000) clf.fit(X_train, y_train) test_predictions = favorite_clf.predict(X_test)
Python (Intel DAAL), AdaBoost (训练)
from daal.algorithms.adaboost import prediction, training from daal.algorithms import classifier trainAlg = training.Batch() trainAlg.input.set(classifier.training.data, X_train) trainAlg.input.set(classifier.training.labels, y_train) trainAlg.parameter. maxIterations = 1000 trainingResult = trainAlg.compute()
Python (Intel DAAL), AdaBoost (预测)
predictAlg = prediction.Batch() predictAlg.input.setTable(classifier.prediction.data, X_test) predictAlg.input.setModel(classifier.prediction.model, trainingResult.get(classifier.training.model)) predictAlg.compute() predictionResult = predictAlg.getResult() test_predictions = predictionResult.get(classifier.prediction.prediction)
Python (Intel DAAL), BrownBoost (训练)
from daal.algorithms.brownboost import prediction, training from daal.algorithms import classifier trainAlg = training.Batch() trainAlg.input.set(classifier.training.data, X_train) trainAlg.input.set(classifier.training.labels, y_train) trainAlg.parameter. maxIterations = 1000 trainingResult = trainAlg.compute()
Python (Intel DAAL), BrownBoost (预测)
predictAlg = prediction.Batch() predictAlg.input.setTable(classifier.prediction.data, X_test) predictAlg.input.setModel(classifier.prediction.model, trainingResult.get(classifier.training.model)) predictAlg.compute() predictionResult = predictAlg.getResult() test_predictions = predictionResult.get(classifier.prediction.prediction)
Python (Intel DAAL), LogitBoost (训练)
from daal.algorithms.brownboost import prediction, training from daal.algorithms import classifier trainAlg = training.Batch() trainAlg.input.set(classifier.training.data, X_train) trainAlg.input.set(classifier.training.labels, y_train) trainAlg.parameter. maxIterations = 1000 trainingResult = trainAlg.compute()
Python (Intel DAAL), LogitBoost (预测)
predictAlg = prediction.Batch() predictAlg.input.setTable(classifier.prediction.data, X_test) predictAlg.input.setModel(classifier.prediction.model, trainingResult.get(classifier.training.model)) predictAlg.compute() predictionResult = predictAlg.getResult() test_predictions = predictionResult.get(classifier.prediction.prediction)
AdaBoost R (fastAdaBoost)
library(fastAdaBoost) model <- adaboost(Survived ~ ., train, 1000) pred <- predict(model, newdata=test)
LogitBoost R (caTools)
library(caTools) model <- LogitBoost(X_train, Y_train, nIter=1000) pred <- predict(model, X_test)
Gradient boosting R (gbm)
library(caTools) model <- LogitBoost(X_train, Y_train, nIter=1000) pred <- predict(model, X_test)
图 14 显示了不同 Boosting 算法的准确性。
正如我们所见,Intel DAAL 的 BrownBoost 算法表现出最佳的预测准确性。
使用机器学习和 Intel DAAL 解决数据分析问题
选择算法来解决机器学习问题是一个非同小可的问题,需要仔细考虑。Intel DAAL 或 scikit-learn 等库提供了各种机器学习算法,因此用户可以选择最适合其问题的算法。
我们演示了如何使用 Intel DAAL 来利用 Intel 平台的全部功能,从而实现更快的模型训练和预测。我们的基准测试表明,Intel DAAL 在性能上优于 scikit-learn 和 R 实现,同时也能产生更准确的模型。
了解更多关于 Intel® 数据分析库 Intel® DAAL 的信息
参考文献
- 维基百科上的 Kaggle 概述.
- Patwary, Md. Mostofa Ali; Satish, Nadathur Rajagopalan; Sundaram, Narayanan; Liu, Jialin; Sadowski, Peter; Racah, Evan; Byna, Suren; Tull, Craig; Bhimji, Wahid; Prabhat, Dubey, Pradeep. 2016. “PANDA:分布式架构上的极大规模并行 K-近邻,” IEEE 国际并行和分布式处理研讨会。
- Hastie, Trevor; Tibshirani, Robert; and Friedman, Jerome. 2009. 《统计学习要素》,第二版。Springer International Publishing AG。
- Freund, Yoav, and Schapire, Robert E. 1999. “Additive Logistic Regression: A Statistical View of Boosting,” Journal of Japanese Society for Artificial Intelligence (14[5]), pp. 771–780。
- Friedman, Jerome; Hastie, Trevor; and Tibshirani, Robert. 2000. “Additive Logistic Regression: A Statistical View of Boosting,” The Annals of Statistics, 28(2), pp. 337–407。
- Friedman, Jerome. 2001. “Greedy Function Approximation: A Gradient Boosting Machine,” The Annals of Statistics 29(5), pp. 1189–1232。
配置和使用的工具
用于基准测试的系统配置
Intel® Xeon®
型号名称:Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20 GHz
每个插槽的核心数:22
插槽数:2
总内存:256 GB
Intel® Xeon Phi™
型号名称:Intel(R) Xeon Phi(TM) Processor 000A @ 1.40 GHz
每个插槽的核心数:68
插槽数:1
RAM:16 GB
此示例中使用的软件工具
- Intel® DAAL 2017 Beta update 2
- R 版本 3.3.2
- scikit-learn 版本 0.19.1
- Class 包版本 7.3-14
- MASS 包版本 7.3-45
- e1071 包版本 1.6-8
- fastAdaBoost 包版本 1.0.0
- caTools 包版本 1.17.1
- gbm 包版本 2.1.1