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

模型选择(超参数调谐)

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 Pipeline
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.ml.feature import HashingTF, Tokenizer
from 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%用于验证。

扫描二维码关注公众号,回复: 2859421 查看本文章

Example: model selection via train validation split

from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.ml.regression import LinearRegression
from 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()

模型选择(超参数调谐)

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 Pipeline
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.ml.feature import HashingTF, Tokenizer
from 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 RegressionEvaluator
from pyspark.ml.regression import LinearRegression
from 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()

猜你喜欢

转载自blog.csdn.net/zhangbaoanhadoop/article/details/77749807