PyTorch Lighting 常见问题整理

0 系统版本

PyTorch Lighting 1.1.7

1 错误:object has no attribute '_metrics_to_agg'

当使用自定义的 Logger 时,如果出现上面的错误,一个很可能的原因是在自定义的 __init__ 函数中忘记调用 super().__init__(),正确的自定义初始化函数用法如下:

2 错误:RuntimeError: grad can be implicitly created only for scalar outputs

在使用 DataParallel 模式时,由于 Loss 是每个 train_step 分别返回的,在单个 GPU 中返回是一个标量,但是多个 GPU 返回就是一个 Tensor 向量了,而 Loss 要求必须是标量。
解决这一问题可以增加如下 training_step_end 函数,将 loss 求 mean:

需要注意的是上述函数默认在 train_step 返回的是如下形式,如果不是的话请进行相应修改。

同时 PyTorch Lightning 默认是接收直接返回 Loss 或者在 Dict 中返回 {'loss': loss},其他形式可能需要再做其他修改。

3 问题:分布式训练中 training_step、validation_step、test_step 的线程安全

在 PyTorch Lightning 的一些例子中,可能会在 training_step 中进行一些 matplotlib 的绘制操作,这在单线程中是没有问题的,但是在例如用 dp、ddp 等多线程模式时,training_step、validation_step、test_step 实际上是并行的,而 matplotlib 并不是线程安全的,就会出现死锁或者崩溃等问题。
因此如果是用分布式训练,请务必确保这几个函数中的代码都是线程安全的。

参考官方文档可以更好地理解这个问题:
https://pytorch-lightning.readthedocs.io/en/latest/lightning_module.html#methods

对于单线程训练其流程类似:

对于分布式训练其流程类似:

一个可行的解决办法对于这部分代码使用线程锁,例如:
在 LightningModule 的 __init__ 函数中加上:

在 train_step 等函数非线程安全的代码中使用:

4 技巧:使用 @rank_zero_only 修饰多线程中只在 RANK=0 调用的函数

在分布式训练中,如果有一些日志或者测试进程只应该在 RANK=0 中调用,可以考虑将相关的代码放入一个函数,同时该函数使用 @rank_zero_only 进行修饰,例如:

注意需要引用头文件:

5 错误:AttributeError: Missing attribute "training_step_output_for_epoch_end"

在使用 DDP 等分布式训练模式时如果当前的 batch 返回 None,可能会出现如下错误:

通过对照其代码,一个可能的问题是在 batch=None 的时候可能有一个逻辑错误。在 trainer/training_loop.py 文件中:

而在 run_training_batch 函数中:

也就是说在 batch == None 的时候会返回 signal=0 的 batch_output,而这个并不存在 batch_output.training_step_output_for_epoch_end 属性,因此就出现的错误。

目前并不清楚在哪个版本中会解决这个问题,一个中间的处理方式是不要返回 None 的 batch,可以返回类似:

然后在 training_step 增加如下处理:

6 使用 ReduceLROnPlateau 的方式

在 PyTorch Lightning 默认的 automatic_optimization = True 方式下,你需要这样配置:

与其他略有不同,ReduceLROnPlateau 需要配置 monitor 参数,如果没有配置则会出现如下错误:
configure_optimizers must include a monitor when a ReduceLROnPlateau scheduler is used.

7 使用 Manual Optimization 方式手工控制优化步骤

如果你需要更精细的控制,可以不启用 PyTorch Lightning 的 automatic_optimization 功能(设置为 False),采用类似如下方式手动优化:
比如采用 Optimizer 方式:

比如采用 lr_scheduler 方式:

参考:
[1] https://pytorch-lightning.readthedocs.io/en/latest/common/optimizers.html#manual-optimization
[2] https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau
[3] https://pytorch-lightning.readthedocs.io/en/latest/common/optimizers.html#learning-rate-scheduling-manual

8 使用 LearningRateMonitor 监控 learning rate 变化

使用 LearningRateMonitor 监控 learning rate 变化方式方式,参考代码如下,作为 callback 输入 trainer:

为了获取 learning rate,可以在 Logger::log_metrics(self, metrics, step) 中获取,通常这个名字为 lrAdam 之类的:

参考:
[1] https://pytorch-lightning.readthedocs.io/en/stable/extensions/generated/pytorch_lightning.callbacks.LearningRateMonitor.html?highlight=LearningRateMonitor

9 在 LightningModule 获取当前 epoch 和 step

获得当前 epoch:

获得当前 step:

Add a Comment

您的电子邮箱地址不会被公开。 必填项已用 * 标注