4

我正在使用 PyTorch Lightning 训练图像分类模型并在具有多个 GPU 的机器上运行,因此我使用推荐的分布式后端以获得最佳性能ddp(DataDistributedParallel)。这自然会拆分数据集,因此每个 GPU 只会看到数据的一部分。

但是,对于验证,我想计算整个验证集的准确性等指标,而不仅仅是部分。我该怎么做?我在官方文档中发现了一些提示,但它们没有按预期工作或让我感到困惑。正在发生的事情是每个validation_epoch_end都称为验证数据的num_gpus时间1/num_gpus。我想汇总所有结果并且只运行validation_epoch_end一次。

本节中,他们声明在使用 dp/ddp2 时,您可以添加一个附加函数,如下所示

def validation_step(self, batch, batch_idx):
    loss, x, y, y_hat = self.step(batch)
    return {"val_loss": loss, 'y': y, 'y_hat': y_hat}

def validation_step_end(self, self, *args, **kwargs):
    # do something here, I'm not sure what, 
    # as it gets called in ddp directly after validation_step with the exact same values
    return args[0]

然而,结果并没有被聚合,validation_epoch_end仍然被称为num_gpu时间。这种行为不可用ddp吗?还有其他方法可以实现这种聚合行为吗?

4

2 回答 2

1

training_epoch_end()validation_epoch_end()汇总来自特定过程的所有训练/验证批次的数据。他们只是创建一个列表,列出您在每个培训或验证步骤中返回的内容。

使用 DDP 后端时,每个 GPU 都有一个单独的进程运行。没有简单的方法可以访问另一个进程正在处理的数据,但是有一种机制可以在进程之间同步特定的张量。最简单的方法是分段计算度量,然后例如通过取平均值来同步张量。当您使用. 时,self.log()调用将自动在 GPU 之间同步值sync_dist=True。值的同步方式由reduce_fx参数确定,默认情况下为torch.mean.

如果您也对批量平均指标感到满意,则无需覆盖training_epoch_end()validation_epoch_end()-self.log()将为您进行平均。

也可以在每一步更新一些状态变量,然后定义一个自定义指标,该指标将在每个 epoch 之后根据您保存的值进行计算。推荐的方法是创建一个派生自Metric类的类(现在移至TorchMetrics项目)。使用and方法在构造函数中添加状态变量add_state()并覆盖。API 将负责在进程之间同步状态变量。update()compute()

TorchMetrics 中已经有一个准确度指标,源代码是如何使用 API 的一个很好的例子。

于 2021-04-07T16:29:12.763 回答
0

我认为您正在寻找training_step_end/ validation_step_end

...因此,当 Lightning 调用任何 training_step、validation_step、test_step 时,您将只对其中一个部分进行操作。(...) 对于大多数指标,这并不重要。但是,如果您想使用所有批处理部分向您的计算图(如 softmax)添加一些东西,您可以使用 training_step_end 步骤。

于 2020-11-25T13:07:30.120 回答