使用Spark分发scikit-learn

时间:2017-07-16 23:14:46

标签: python apache-spark machine-learning scikit-learn

所以我一直致力于使用不同的参数组合来分配和并行化不同ML算法的执行。我正在集群环境中进行实验,我想尽可能多地利用所有可用资源。 有关详细信息:How are tasks distributed within a Spark cluster?

我的输入包含JSON格式的算法和参数列表。基于这种情况,我有两种方法:

  1. 对于我拥有的每个ML算法,我创建了一个SparkGridSearch对象(来自official integration)并将其放入列表中。然后,我在不同的线程上触发这些网格搜索对象的执行,如下所示:

    ...
    for experiment in experiments:
        # experiment contains the algorithm and its list of parameters
        gridSearchCV = SparkGridSearchCV(spark_context, experiment[0], experiment[1], scoring=experiment[2], cv=experiment[3])
        experiment_thread = Thread(target=run_experiment, args=(bcast_dataframe, gridSearchCV))
        experiment_thread.start()
    
  2. 输入:

    experiments_dict = {
        'Decision Tree': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {'criterion': ['entropy'], 'class_weight': ['balanced']}},
        'Naive Bayes': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {}},
        'Random Forests': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {'n_estimators': [5, 7]}},
        'Random Forests_2': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'bootstrap': [True, False], 'criterion': ['entropy'], 'class_weight': ['balanced']}},
        'Decision Tree_2': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [2, 3, None], 'max_depth': [None], 'class_weight': ['balanced', None]}},
        ...
    }
    
    1. 我还创建了一个列表,其中每个元素都是一个具有一个参数组合的算法。因此,该列表的大小比前一种方法大得多,因为每个组合是列表的一个元素。在这种情况下,我只需在此列表中使用spark.parallelize并将其映射到我运行每个ML算法的函数中:

      def run_experiment(dataframe, experiment):
         ...
         model = estimator.fit(train_data, train_target)
      
         predicted = model.predict(test_data)
      
         score = accuracy_score(predicted, expected)
         return [model, score]
      
      
      def main(): 
        ...
        bcast_dataset = spark_context.broadcast(df)
      
        experimentsRDD = spark_context.parallelize(experiments_dict)
      
        print experimentsRDD.map(lambda experiment: run_experiment(bcast_dataset, experiment)).collect()
      
        bcast_dataset.unpersist()
      
    2. 输入:

      experiments_dict = {
          'Decision Tree': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {'criterion': ['entropy'], 'class_weight': ['balanced']}},
          'Naive Bayes': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {}},
          'Random Forests': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {'n_estimators': [5]}},
          'Random Forests_1_2': {'num_folds': 2, 'evaluation': 'accuracy', 'parameters': {'n_estimators': [7]}},
          'Random Forests_2': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'bootstrap': [True, False], 'criterion': ['entropy'], 'class_weight': ['balanced']}},
          'Random Forests_2_1': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'bootstrap': [False], 'criterion': ['entropy'], 'class_weight': ['balanced']}},
          'Decision Tree_2': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [2], 'max_depth': [None], 'class_weight': ['balanced']}},
          'Decision Tree_2_1': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [3], 'max_depth': [None], 'class_weight': ['balanced']}},
          'Decision Tree_2_2': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [None], 'max_depth': [None], 'class_weight': ['balanced']}},
          'Decision Tree_2_3': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [2], 'max_depth': [None], 'class_weight': ['None']}},
          'Decision Tree_2_4': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [3], 'max_depth': [None], 'class_weight': ['None']}},
          'Decision Tree_2_5': {'num_folds': 3, 'evaluation': 'accuracy', 'parameters': {'splitter': ['random'], 'max_leaf_nodes': [None], 'max_depth': [None], 'class_weight': ['None']}},
              ...
      }
      

      我已经进行了一些实验,并用第二种方法获得了更好的结果。但是,当更改分区数(等于实验数,或可用内核数的2或3倍)时,执行时间不会发生变化。 在多线程方法中使用Spark广播数据集时我也遇到了一些问题,但显然这是一个已知的issue

      我的问题:这些结果有意义吗?为什么分区数不会影响执行时间?我错过了什么或者有什么我可以改进的吗?

      谢谢!

0 个答案:

没有答案