使用 pytorch-lightning

chirp / 2024-01-15 / 原文

在用 PyTorch 训练不同模型时,需要编写很多重复的逻辑。一个工程的代码无可避免地变得越来越长,难以管理。PyTorch Lightning 作为一个对 PyTorch 二次封装的框架,能让训练逻辑的编写像堆积木一样秩序井然。

虽然叫做 lightning,这个库的学习成本并低。好在一但熟悉,就能享受到很多便利。

安装

使用类似下面的指令安装 PyTorch Lightning。

python -m pip install lightning

完成后就可以在 Python 脚本里 import pytorch_lightning 了。

快速开始

PyTorch Lightning 的宗旨是:all in one。

不使用任何框架,写出来的训练代码会像是这样:


writer = SummaryWriter()
model = ResNet18().to(device)
optimizer = torch.optim.Adam(model.params, lr=1e-3)

for epoch in range(num_epochs):
    for i, batch in enumerate(train_data):
        x, y = batch
        x = x.to(device)
        output = model(x)
        loss = criterion(output, y)
        writer.add_scalar("train_loss", loss, num_epochs * len(train_data) + i)

        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

    with torch.no_grad():
        for batch in val_data:
            x, y = batch

                ···

若使用 PyTorch Lightning,可以把这一切封装到一个 class 内:

import pytorch_lightning as L

class LightningModel(L.LightningModule):
    def __init__(self):
        super().__init__()
        self.model = ResNet18()
    
    def forward(self, x):
        return model(x)

    def configure_optimizers(self):
        optimizer = torch.optim.Adam(self.model.parameters, lr=1e-3)
        return optimizer

    def training_step(self, train_batch, batch_idx):
        x, y = train_batch
        output = self.model(x)
        loss = criterion(output, y)
        self.log('train_loss', loss, on_step=True, on_epoch=False)
        return loss

    def validation_step(self, val_batch, batch_idx):
        x, y = val_batch
        output = criterion(output, y)
        loss = criterion(output, y)
        self.log('val_loss', loss)

可见 lightning 的特点以及省下的工作:

  • 将训练各步骤的代码分配到不同的函数,层次分明
  • 不需要 .to(device)。lightning 会自动转换
  • 不需要手动 loss.backward() optimizer.step() optimizer.zero_grad()
  • validation 阶段不需要手动 torch.no_grad()
  • 记录 log 时 lightning 会帮助填写当前 step 和 epoch
  • ……

接下来训练的代码就可以非常简明:

model = LightningModel()
trainer = L.Trainer(accelerator='gpu', max_epochs=15)
trainer.fit(model, train_data, val_data) # 正式开始训练

使用混合精度

若要在 lightning 的训练启用混合精度加速,需要先执行:

torch.set_float32_matmul_precision('high')

然后在实例化 trainer 时,传入参数 precision='bf16-mixed' 即可。参数可选的值随硬件条件改变而变化,请查阅文档。

学习率调度器(scheduler)

在自定义 configure_optimizers() 时,除了需要指定 optimizer,还可以设定一个学习率调度器 scheduler。

class LightningModel(L.LightningModule):
    ···
    def configure_optimizers(self):
        optimizer = torch.optim.Adam(self.model.parameters(), lr=0.001)
        scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)
        return [optimizer], [scheduler]

lightning 会自动执行 scheduler.step()