Spark机器学习之模型选择和超参数调整

来源:互联网 发布:手机拼图软件哪个好 编辑:程序博客网 时间:2024/05/17 01:25
模型选择(超参数调谐)

ML中的一个重要任务是模型选择,或使用数据找到给定任务的最佳模型或参数。 这也叫调音。 可以针对个体估算器(如Logistic回归)或包括多个算法,特征化和其他步骤的整个管道完成调整。 用户可以一次调整整个流水线,而不是单独调整管道中的每个元素。

MLlib支持使用CrossValidator和TrainValidationSplit等工具进行模型选择。 这些工具需要以下项目:

Estimator:算法或管道调整
Set of ParamMaps:可供选择的参数,有时称为“参数网格”进行搜索
Evaluator:衡量拟合模型对延伸测试数据有多好的度量

在高层次上,这些模型选择工具的工作如下:

他们将输入数据分成单独的训练和测试数据集。
对于每个(训练,测试)对,遍历一组ParamMaps:
对于每个ParamMap,它们使用这些参数适合Estimator,获得拟合的Model,并使用Evaluator评估Model的性能。
选择由最佳性能参数组合生成的模型。

评估者可以是回归问题的回归估值器,二进制数据的BinaryClassificationEvaluator或多类问题的MulticlassClassificationEvaluator。 用于选择最佳ParamMap的默认度量可以被这些评估器中的每一个的setMetricName方法覆盖。为了帮助构建参数网格,用户可以使用ParamGridBuilder实用程序。

交叉验证
CrossValidator首先将数据集分成一组折叠,这些折叠用作单独的训练和测试数据集。 例如,k = 3倍,CrossValidator将生成3个(训练,测试)数据集对,每个数据集使用2/3的数据进行训练,1/3进行测试。 为了评估一个特定的ParamMap,CrossValidator通过在3个不同的(训练,测试)数据集对上拟合Estimator来计算3个模型的平均评估度量。
在确定最佳ParamMap之后,CrossValidator最终使用最好的ParamMap和整个数据集重新拟合Estimator。

示例:通过交叉验证进行模型选择
以下示例演示如何使用CrossValidator从参数网格中进行选择。
请注意,通过参数网格的交叉验证是昂贵的。 例如,在下面的示例中,参数网格具有3个值,用于hashingTF.numFeatures,2个值用于lr.regParam,CrossValidator使用2个折叠。 这被乘以(3×2)×2 = 12个不同的模型被训练。 在现实的设置中,尝试更多参数并使用更多的折叠(k = 3,k = 10是常见的)是常见的。 换句话说,使用CrossValidator可能非常昂贵。 然而,它也是一种成熟的方法,用于选择比启发式手动调谐更具统计学意义的参数。

from pyspark.ml import Pipelinefrom pyspark.ml.classification import LogisticRegressionfrom pyspark.ml.evaluation import BinaryClassificationEvaluatorfrom pyspark.ml.feature import HashingTF, Tokenizerfrom pyspark.ml.tuning import CrossValidator, ParamGridBuilder# Prepare training documents, which are labeled.training = spark.createDataFrame([    (0, "a b c d e spark", 1.0),    (1, "b d", 0.0),    (2, "spark f g h", 1.0),    (3, "hadoop mapreduce", 0.0),    (4, "b spark who", 1.0),    (5, "g d a y", 0.0),    (6, "spark fly", 1.0),    (7, "was mapreduce", 0.0),    (8, "e spark program", 1.0),    (9, "a e c l", 0.0),    (10, "spark compile", 1.0),    (11, "hadoop software", 0.0)], ["id", "text", "label"])# Configure an ML pipeline, which consists of tree stages: tokenizer, hashingTF, and lr.tokenizer = Tokenizer(inputCol="text", outputCol="words")hashingTF = HashingTF(inputCol=tokenizer.getOutputCol(), outputCol="features")lr = LogisticRegression(maxIter=10)pipeline = Pipeline(stages=[tokenizer, hashingTF, lr])# We now treat the Pipeline as an Estimator, wrapping it in a CrossValidator instance.# This will allow us to jointly choose parameters for all Pipeline stages.# A CrossValidator requires an Estimator, a set of Estimator ParamMaps, and an Evaluator.# We use a ParamGridBuilder to construct a grid of parameters to search over.# With 3 values for hashingTF.numFeatures and 2 values for lr.regParam,# this grid will have 3 x 2 = 6 parameter settings for CrossValidator to choose from.paramGrid = ParamGridBuilder() \    .addGrid(hashingTF.numFeatures, [10, 100, 1000]) \    .addGrid(lr.regParam, [0.1, 0.01]) \    .build()crossval = CrossValidator(estimator=pipeline,                          estimatorParamMaps=paramGrid,                          evaluator=BinaryClassificationEvaluator(),                          numFolds=2)  # use 3+ folds in practice# Run cross-validation, and choose the best set of parameters.cvModel = crossval.fit(training)# Prepare test documents, which are unlabeled.test = spark.createDataFrame([    (4, "spark i j k"),    (5, "l m n"),    (6, "mapreduce spark"),    (7, "apache hadoop")], ["id", "text"])# Make predictions on test documents. cvModel uses the best model found (lrModel).prediction = cvModel.transform(test)selected = prediction.select("id", "text", "probability", "prediction")for row in selected.collect():    print(row)
Train-Validation Split

除了CrossValidator Spark,还提供了用于超参数调整的TrainValidationSplit。 TrainValidationSplit仅对参数的每个组合进行一次评估,而在CrossValidator的情况下,则不是k次。 因此,它较便宜,但在训练数据集不够大时不会产生可靠的结果。
与CrossValidator不同,TrainValidationSplit创建一个(训练,测试)数据集对。 它使用trainRatio参数将数据集分成这两个部分。 例如,trainRatio = 0.75,TrainValidationSplit将生成训练和测试数据集对,其中75%的数据用于训练,25%用于验证。

Example: model selection via train validation split

from pyspark.ml.evaluation import RegressionEvaluatorfrom pyspark.ml.regression import LinearRegressionfrom pyspark.ml.tuning import ParamGridBuilder, TrainValidationSplit# Prepare training and test data.data = spark.read.format("libsvm")\    .load("data/mllib/sample_linear_regression_data.txt")train, test = data.randomSplit([0.9, 0.1], seed=12345)lr = LinearRegression(maxIter=10)# We use a ParamGridBuilder to construct a grid of parameters to search over.# TrainValidationSplit will try all combinations of values and determine best model using# the evaluator.paramGrid = ParamGridBuilder()\    .addGrid(lr.regParam, [0.1, 0.01]) \    .addGrid(lr.fitIntercept, [False, True])\    .addGrid(lr.elasticNetParam, [0.0, 0.5, 1.0])\    .build()# In this case the estimator is simply the linear regression.# A TrainValidationSplit requires an Estimator, a set of Estimator ParamMaps, and an Evaluator.tvs = TrainValidationSplit(estimator=lr,                           estimatorParamMaps=paramGrid,                           evaluator=RegressionEvaluator(),                           # 80% of the data will be used for training, 20% for validation.                           trainRatio=0.8)# Run TrainValidationSplit, and choose the best set of parameters.model = tvs.fit(train)# Make predictions on test data. model is the model with combination of parameters# that performed best.model.transform(test)\    .select("features", "label", "prediction")\    .show()