29、基于Spark的实用机器学习与GPU计算入门

基于Spark的实用机器学习与GPU计算入门

1. 特征矩阵构建

在机器学习任务中,特征矩阵的构建是关键步骤。我们可以使用 VectorAssembler 类来帮助构建特征矩阵。具体操作如下:

from pyspark.ml.feature import VectorAssembler
assembler = VectorAssembler(
    inputCols=features_header,
    outputCol="features")
Xy_train = (assembler
                .transform(train_num_df)
                .select("features", "target_cat"))
Xy_test = (assembler
                .transform(test_num_df)
                .select("features", "target_cat"))

VectorAssembler 默认会生成 DenseVectors SparseVectors 。由于特征向量中包含许多零,这里返回的是稀疏向量。我们可以通过打印第一行来查看输出内容:

Xy_train.first()
2. 训练分类器

接下来进入到训练分类器的环节。分类器包含在 pyspark.ml.classification 包中,这里我们使用随机森林分类器。

Spark 1.6中可用的分类器如下:
- 分类器( pyspark.ml.classification 包)
- LogisticRegression
- DecisionTreeClassifier
- GBTClassifier (基于决策树的梯度提升分类实现)
- RandomForestClassifier
- NaiveBayes
- MultilayerPerceptronClassifier

除了分类器,Spark 1.6中还有其他类型的学习器:
- 聚类( pyspark.ml.clustering 包)
- KMeans
- 回归( pyspark.ml.regression 包)
- AFTSurvivalRegression (加速失效时间生存回归)
- DecisionTreeRegressor
- GBTRegressor (基于回归树的梯度提升回归实现)
- IsotonicRegression
- LinearRegression
- RandomForestRegressor
- 推荐器( pyspark.ml.recommendation 包)
- ALS (基于交替最小二乘法的协同过滤推荐器)

下面我们实例化一个随机森林分类器并设置其参数:

from pyspark.ml.classification import RandomForestClassifier
clf = RandomForestClassifier(
    labelCol="target_cat", featuresCol="features", 
    maxBins=100, seed=101)
fit_clf = clf.fit(Xy_train)

训练后的分类器是一个不同的对象,名称会在原分类器名称后加上 Model 后缀。我们可以打印分类器和训练后的分类器:

print clf
print fit_clf

然后使用训练后的分类器对训练集和测试集进行预测,并打印测试集的第一行:

Xy_pred_train = fit_clf.transform(Xy_train)
Xy_pred_test = fit_clf.transform(Xy_test)
print "First observation after classification stage:"
print Xy_pred_test.first()
3. 评估学习器性能

在数据科学任务中,评估学习器在训练集和测试集上的性能是重要的一步。这里我们使用F1分数来评估,它是一种综合了精确率和召回率的指标。

from pyspark.ml.evaluation import MulticlassClassificationEvaluator
evaluator = MulticlassClassificationEvaluator(
    labelCol="target_cat", predictionCol="prediction", 
    metricName="f1")
print "F1-score train set:", evaluator.evaluate(Xy_pred_train)
print "F1-score test set:", evaluator.evaluate(Xy_pred_test)

得到的F1分数较高,但训练集和测试集的性能存在较大差异。除了多分类评估器,该包中还提供了回归器(指标可以是MSE、RMSE、R2或MAE)和二分类器的评估器。

4. ML管道的强大之处

我们可以将之前的操作串联起来,设置为管道的各个阶段。这样做更高效,但会失去逐步分析的探索能力。数据科学家建议在完全确定内部操作后,仅用于构建生产模型。

full_stages = preproc_stages + [assembler, clf]
full_pipeline = Pipeline(stages=full_stages)
full_model = full_pipeline.fit(train_df)
predictions = full_model.transform(test_df)
print "F1-score test set:", evaluator.evaluate(predictions)

我们还可以使用 matplotlib 库来可视化分析结果,例如绘制归一化的混淆矩阵:

import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
def plot_confusion_matrix(cm):
    cm_normalized = \
        cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
    plt.imshow(
        cm_normalized, interpolation='nearest', cmap=plt.cm.Blues)
    plt.title('Normalized Confusion matrix')
    plt.colorbar()
    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

from pyspark.mllib.evaluation import MulticlassMetrics
metrics = MulticlassMetrics(
    predictions.select("prediction", "target_cat").rdd)
conf_matrix = metrics.confusionMatrix().toArray()
plot_confusion_matrix(conf_matrix)
5. 手动调优

尽管F1分数接近0.97,但归一化的混淆矩阵显示类别严重不平衡,分类器只学会了正确分类最常见的类别。我们可以通过对稀有类别进行过采样和对过于常见的类别进行欠采样来改善性能。

首先,统计训练数据集中每个类别的样本数量:

train_composition = train_df.groupBy("target").count().rdd.collectAsMap()
train_composition

然后,创建采样率并广播到整个集群:

def set_sample_rate_between_vals(cnt, the_min, the_max):
    if the_min <= cnt <= the_max:
        # no sampling
        return 1
    elif cnt < the_min:
        # Oversampling: return many times the same observation
        return the_min/float(cnt)
    else:
        # Subsampling: sometime don't return it
        return the_max/float(cnt)
sample_rates = {k:set_sample_rate_between_vals(v, 1000, 25000) 
                for k,v in train_composition.iteritems()} 
bc_sample_rates = sc.broadcast(sample_rates)

接着,对训练数据集进行重采样:

def map_and_sample(el, rates):
    rate = rates.value[el['target']]
    if rate > 1:
        return [el]*int(rate)
    else:
        import random
        return [el] if random.random() < rate else []
sampled_train_df = (train_df
                   .flatMap(
                     lambda x: map_and_sample(x, bc_sample_rates))
                   .toDF()
                   .cache())

最后,使用新的训练数据集进行预测并打印F1分数:

full_model = full_pipeline.fit(sampled_train_df)
predictions = full_model.transform(test_df)
print "F1-score test set:", evaluator.evaluate(predictions)

我们还可以测试一个包含50棵树的分类器:

clf = RandomForestClassifier(
    numTrees=50, maxBins=100, seed=101,
    labelCol="target_cat", featuresCol="features")
stages = full_pipeline.getStages()[:-1]
stages.append(clf)
refined_pipeline = Pipeline(stages=stages)
refined_model = refined_pipeline.fit(sampled_train_df)
predictions = refined_model.transform(test_df)
print "F1-score test set:", evaluator.evaluate(predictions)
6. 交叉验证

手动调优可能会导致时间浪费和过拟合测试数据集。交叉验证是进行超参数优化的正确方法。

首先,缓存训练数据:

pipeline_to_clf = Pipeline(
    stages=preproc_stages + [assembler]).fit(sampled_train_df)
train = pipeline_to_clf.transform(sampled_train_df).cache()
test = pipeline_to_clf.transform(test_df)

然后,使用 ParamGridBuilder 构建参数网格,使用 CrossValidator 进行交叉验证:

from pyspark.ml.tuning import ParamGridBuilder, CrossValidator
rf = RandomForestClassifier(
    cacheNodeIds=True, seed=101, labelCol="target_cat", 
    featuresCol="features", maxBins=100)
grid = (ParamGridBuilder() 
        .addGrid(rf.maxDepth, [3, 6, 9, 12]) 
        .addGrid(rf.numTrees, [20, 50]) 
        .build())
cv = CrossValidator(
    estimator=rf, estimatorParamMaps=grid, 
    evaluator=evaluator, numFolds=3)
cvModel = cv.fit(train)

最后,使用交叉验证后的模型进行预测并打印F1分数:

predictions = cvModel.transform(test)
print "F1-score test set:", evaluator.evaluate(predictions)

通过绘制归一化的混淆矩阵,我们可以发现该解决方案能够检测到更多种类的攻击。

metrics = MulticlassMetrics(predictions.select(
        "prediction", "target_cat").rdd)
conf_matrix = metrics.confusionMatrix().toArray()
plot_confusion_matrix(conf_matrix)
7. 最终清理

完成分类任务后,记得清除使用的变量和临时表:

bc_sample_rates.unpersist()
sampled_train_df.unpersist()
train.unpersist()

8. GPU计算与Theano框架入门

到目前为止,我们使用常规CPU进行神经网络和深度学习任务。近年来,GPU的计算优势变得越来越广泛。下面我们来了解GPU计算和Theano框架的基础知识。

8.1 GPU计算的优势与局限性

当使用常规CPU计算包进行机器学习时,并行化程度通常很有限,因为默认情况下算法只使用一个核心,即使有多个核心可用。而GPU单元从设计上就是为并行工作而优化的。

GPU和CPU的架构不同,适用于不同的任务。CPU由几个为顺序串行处理优化的核心组成,而GPU由数千个更小、更高效的核心组成,能够同时处理数千个任务。GPU可以以更低的成本比CPU快100倍。此外,现代GPU相对于最先进的CPU来说相对便宜。

然而,GPU只擅长执行特定类型的任务。由于其架构的原因,GPU在执行检查、调试和切换等任务时效率不高。

为了在机器学习中使用GPU,需要特定的平台。目前,除了CUDA之外,没有稳定的GPU计算平台。这意味着必须在计算机上安装NVIDIA显卡才能使用GPU计算。虽然有一些项目如OpenCL提供了其他GPU品牌的计算支持,但它们还在大力开发中,并且没有针对Python中的深度学习应用进行充分优化。

8.2 GPU计算的操作限制

目前,只有NVIDIA似乎在积极投入研究开发GPU平台,未来几年内不太可能看到该领域有新的重大发展。对于大多数Mac用户来说,这是一个不利的消息。尽管有OpenCL项目,但它只有AMD积极参与,对AMD GPU有益,短期内不太可能有硬件无关的机器学习GPU应用。不过,我们可以关注OpenCL项目的新闻和发展。

综上所述,GPU计算在机器学习中具有巨大的潜力,但目前存在一定的限制。在选择使用GPU计算时,需要考虑硬件要求和平台的稳定性。同时,我们也可以期待未来在GPU计算领域有更多的创新和发展。

基于Spark的实用机器学习与GPU计算入门

9. 不同学习器类型总结

为了更清晰地了解Spark 1.6中不同类型的学习器,下面用表格进行总结:
| 学习器类型 | 具体学习器 |
| — | — |
| 分类器( pyspark.ml.classification 包) | LogisticRegression DecisionTreeClassifier GBTClassifier RandomForestClassifier NaiveBayes MultilayerPerceptronClassifier |
| 聚类( pyspark.ml.clustering 包) | KMeans |
| 回归( pyspark.ml.regression 包) | AFTSurvivalRegression DecisionTreeRegressor GBTRegressor IsotonicRegression LinearRegression RandomForestRegressor |
| 推荐器( pyspark.ml.recommendation 包) | ALS |

10. 机器学习流程总结

下面通过mermaid格式的流程图来展示整个机器学习流程:

graph LR
    A[数据准备] --> B[特征矩阵构建]
    B --> C[训练分类器]
    C --> D[评估学习器性能]
    D --> E{性能是否满意}
    E -- 否 --> F[手动调优]
    F --> C
    E -- 是 --> G[使用ML管道]
    G --> H[交叉验证]
    H --> I[最终清理]
11. 手动调优与交叉验证对比

手动调优和交叉验证是优化模型的两种方法,它们各有优缺点,以下是对比:
| 方法 | 优点 | 缺点 |
| — | — | — |
| 手动调优 | 可以灵活尝试不同的参数组合,对模型有更深入的理解 | 耗费大量时间,容易过拟合测试数据集,代码复用性差 |
| 交叉验证 | 能有效避免过拟合,自动搜索最优参数组合 | 需要一定的计算资源和时间,对参数网格的设置有一定要求 |

12. GPU与CPU架构差异分析

为了更好地理解GPU和CPU在架构上的差异,下面详细分析:
- CPU架构 :CPU由少数几个核心组成,这些核心经过优化,适合进行顺序串行处理。在处理需要高度控制和逻辑判断的任务时,如检查、调试和分支操作,CPU表现出色。但由于核心数量有限,其并行处理能力相对较弱。
- GPU架构 :GPU由数千个较小的核心构成,这些核心专门设计用于同时处理大量任务。在处理需要大量并行计算的任务时,如矩阵乘法和图像处理,GPU能够发挥其优势,以较低的成本实现比CPU快100倍的计算速度。然而,由于其架构侧重于并行处理,对于需要复杂逻辑判断和控制流的任务,GPU的效率较低。

13. GPU计算平台现状

目前GPU计算平台的现状如下:
- CUDA :是目前唯一稳定的GPU计算平台,但它依赖于NVIDIA显卡。这意味着用户必须在计算机上安装NVIDIA显卡才能使用GPU计算,限制了其应用范围。
- OpenCL :虽然提供了其他GPU品牌的计算支持,但仍处于大力开发阶段。它没有针对Python中的深度学习应用进行充分优化,并且只有AMD积极参与,对AMD GPU有益。短期内不太可能有硬件无关的机器学习GPU应用。

14. 对未来发展的展望

尽管目前GPU计算存在一定的限制,但随着技术的不断发展,我们可以期待未来在以下方面有所突破:
- 硬件方面 :可能会出现更通用的GPU硬件,减少对特定品牌显卡的依赖,使更多用户能够受益于GPU计算的优势。
- 平台方面 :OpenCL等项目可能会得到进一步发展和优化,提供更稳定、高效的GPU计算支持。同时,可能会出现新的GPU计算平台,打破现有格局。
- 应用方面 :随着GPU计算的普及,机器学习和深度学习的应用将更加广泛,能够处理更复杂的任务,为各个领域带来更多的创新和发展。

总之,基于Spark的实用机器学习为大规模数据处理和模型训练提供了强大的工具,而GPU计算则为机器学习带来了新的计算能力提升。虽然目前存在一些限制,但我们可以通过合理选择方法和关注技术发展,充分发挥它们的优势,推动机器学习领域的进步。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值