Azure ML:如何在多个实例上训练模型

Azure ML: How to train a model on multiple instances

我有一个最小和最大节点设置为 2 的 AML 计算集群。当我执行一个管道时,我希望集群 运行 在两个实例上并行训练。但是集群状态报告只有一个节点忙,另一个空闲。

这是我提交管道的代码,如您所见,我正在解析集群名称并将其传递给我的第 1 步,即在 Keras 上训练模型。

aml_compute = AmlCompute(ws, "cluster-name")
step1 = PythonScriptStep(name="train_step",
                         script_name="Train.py", 
                         arguments=["--sourceDir", os.path.realpath(source_directory) ],
                         compute_target=aml_compute, 
                         source_directory=source_directory,
                         runconfig=run_config,
                         allow_reuse=False)
pipeline_run = Experiment(ws, 'MyExperiment').submit(pipeline1, regenerate_outputs=False)

每个 python 脚本步骤都在单个节点上运行,即使您在集群中分配了多个节点也是如此。我不确定在 AML 中是否可以现成地对不同实例进行训练,但肯定有可能更有效地使用该单个节点(考虑使用所有核心等)

真是个好问题。 TL;DR 是目前没有一种简单的方法可以做到这一点。恕我直言,你的问题中有几个问题 -- 这里是所有问题的一个刺。

分布式训练 keras

我不是 keras 专家,但来自 their distributed training guide,我很想知道您想要的 parallelism?模型并行还是数据并行?

对于数据并行性,tf.distribute API 似乎是可行的方法。在开始使用 Pipelines 之前,我强烈建议在没有 Azure ML 的情况下在单个多 GPU 机器(本地或 Azure VM)上工作。

使用 Azure ML 进行分布式训练

This Azure ML notebook shows how to use PyTorch with Horovod on AzureML. Seems not too tricky to change this to work with keras.

至于如何让分布式训练在 Azure ML Pipeline 中工作,一个 spitball 解决方法是让 PythonScriptStep 成为一个控制器,它会创建一个新的计算集群并将训练脚本提交给它。我不太自信,但我会做一些挖掘。

多节点PythonScripSteps

这是可能的(至少 pyspark)。下面是我们的一个 PythonScriptStep 生产流水线,可以 运行 在多个节点上。它使用预装了 Spark 的 Docker 映像和 pyspark RunConfiguration。在下面的屏幕截图中,您可以看到其中一个节点是主协调器,另一个是辅助工作节点。

from azureml.core import Environment, RunConfiguration

env = Environment.from_pip_requirements(
    'spark_env',
    os.path.join(os.getcwd(), 'compute', 'spark-requirements.txt'))
env.docker.enabled = True
env.docker.base_image = 'microsoft/mmlspark:0.16'
spark_run_config = RunConfiguration(framework="pyspark")
spark_run_config.environment = spark_env
spark_run_config.node_count = 2

roll_step = PythonScriptStep(
    name='roll.py',
    script_name='roll.py',
    arguments=['--input_dir', joined_data,
                '--output_dir', rolled_data],
    compute_target=compute_target_spark,
    inputs=[joined_data],
    outputs=[rolled_data],
    runconfig=spark_run_config,
    source_directory=os.path.join(os.getcwd(), 'compute', 'roll'),
    allow_reuse=pipeline_reuse
)