1. 程式人生 > >Spark機器學習之模型選擇和超引數調整

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%用於驗證。

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()