常用参数
由于文件过大,为了加速训练时间,先训练模型,然后再说其他的理由与打算。
训练器Trainer
Batch size一般会对模型的训练结果有影响i,一般越大的batch size模型训练的结果会越好,有时候,我们不知道自己的模型在当前机器上最多能用多大的batch size,,这时候通过Lightning Trainer的这个flag就可以帮助我们找到最大的batch size。
model = ...
# 设置为True,Trainer就会依次尝试用2的幂次方的batch size,直到超出内存
trainer = pl.Trainer(auto_scale_batch_size=True)
trainer.fit(model)
# 设置为'binsearch',Trainer会用Binary Search的方式帮你找到最大的Batch Size
trainer = pl.Trainer(auto_scale_batch_size='binsearch')
trainer.tune(model)
# 注意:如果要用这个功能,在Module里面的__init__()函数中要有:
self.batch_size = batch_size
# 或者在__init__()里面调用:
self.save_hyperparameters()
学习率learning rate是很重要的一个超参,选取一个合适的初始学习率也是很重要的,Lightning提供了这个有用的flag。
20)目前只支持单优化器(Optimizer),预计在未来的几个月内会支持多优化器
import pytorch_lightning as pl
model = ...
# 可以直接设置为True,Trainer会自动用不同的学习率运行model,然后画出loss和学习率的曲线,帮你找到最合适的学习率
trainer = pl.Trainer(auto_lr_find=True)
trainer.tune(model)
print(model.learning_rate)
# 有时候我们会在model中给学习率起其他的名字,比如:
self.my_learning_rate = lr
# 这个时候我们可以用变量名直接设置auto_lr_find:
trainer = pl.Trainer(auto_lr_find='my_learing_rate')
# 开始寻找合适的学习率
lr_finder = trainer.tuner.lr_find(model)
# 展示loss和学习率的曲线
fig = lr_finder.plot(suggest=True)
fig.show()
# 设置为推荐的学习率
model.hyparams.learning_rate = lr_finder.suggestion()
# 开始训练
model.fit(model, train_loader, val_loader)
一般数据只会在一开始加载一次**,即在epochs循环前面加载一次**,然后每个循环都会shuffle之类的(如果你设置shuffle为True的话)。有时候我们的数据在训练过程中是会改变的,这个时候我们就需要在每个epoch都要再加载一次数据,Lightning就提供了这样一个flag,将其设置为True即可
# 相当于:
# if False (default)
train_loader = model.train_dataloader()
for epoch in epochs:
for batch in train_loader:
...
# if True
for epoch in epochs:
train_loader = model.train_dataloader()
for batch in train_loader:
回调函数 (Callbacks) 在机器学习中也是很重要的工具,一般可以用来进行模型的断点断续,模型权重的存储,提早停止 (Early stop),动态调整训练参数以及tensorboard之类的训练可视化等等**。Lightning也支持非常灵活的Callbacks**,只需要把Callbacks放进flag:callbacks中即可。Lightning提供了一些built-in的callbacks,同样也支持自定义callbacks类,所以非常灵活
# 自定义Callback类
from pytorch_lightning.callbacks import Callback
class MyPrintingCallback(Callback):
def on_init_start(self, trainer):
print('Starting to init trainer!')
def on_init_end(self, trainer):
print('trainer is init now')
def on_train_end(self, trainer, pl_module):
print('do something when training ends')
trainer = Trainer(callbacks=[MyPrintingCallback()])
# 使用built-in的Callbacks
from pytorch_lightning.callbacks import EarlyStopping
# 可以直接使用默认的Callbacks
trainer = pl.Trainer(callbacks=[EarlyStopping('val_loss')])
# 也可以自己设置Callbacks的参数
early_stop = EarlyStopping(
monitor='val_loss',
patience=3,
strict=False,
verbose=False,
mode='min'
)
trainer = pl.Trainer(callbacks=[early_stop])
一般我们搭完模型都会去检查模型结构,计算模型的大小以及占用内存,之前需要安装一个额外的torchsummary的包可以用来输出pytorch模型的信息,Lightning则直接集成了这个功能,它提供三个参数:‘top’,'full’和None。
# (默认) 只展示顶层的模块
trainer = pl.Trainer(weights_summary='top')
# 展示所有的模块,包括子模块
trainer = pl.Trainer(weights_summary='full')
# 不打印模型信息
trainer = pl.Trainer(weights_summary=None)
进度条 (Progress Bar) 是非常有用的工具,在python中我们一般使用第三方包tqdm来创建进度条**,Lightning则集成了进度条,对应的值为steps,即每隔多少steps更新一次进度条,设置为0即不使用进度条**。
# 默认每个step更新一次
trainer = Trainer(progress_bar_refresh_rate=1)
# 关闭进度条
trainer = Trainer(progress_bar_refresh_rate=0)
训练的时候我们需要指定Epoch的数量,Lightning提供了相应的flags。
对min_steps和max_steps而言,中间validation的steps不计入其中。
如果同时指定max_epochs和max_steps,则max_steps优先。
trainer = Trainer(min_steps=100, max_steps=10000)
trainer = Trainer(min_epochs=10, max_epochs=100)
`
训练过程中一般我们也会做测试 (validation) 来看模型的泛化能力以及是否过拟合。Lightning提供了对应的flag,默认为1,即每个epoch结束都会做一次validation。有时候一个training epoch只需要几分钟,这时候没有必要每个epoch结束都去做一次validation,我们可以设置为10或者任意其他的整数。
# 每5个epochs做一次validation
trainer = Trainer(check_val_every_n_epochs=5)
对于某些大模型或者大数据集的训练,一个epoch可能会持续几个小时甚至几天,我们当然不能过这么久才做一次validation,这时候我们要用到这个新flag,它支持0到1的浮点数以及整数。比如0.25表示每隔四分之一的epoch做一次validation,1000表示每隔1000个steps做一次validation。
# 每隔四分之一个epoch做一次validation
trainer = Trainer(val_check_interval=0.25)
# 每隔1000个steps做一次validation
trainer = Trainer(val_check_interval=1000)
一般validation都会在training之后做,如果validation的代码中存在bugs,而training一个epoch可能持续很久,这时候会浪费大量的时间。Lightning提供一个flag来解决这个问题,它会在正式training开始前先做若干个batches的validation,如果没有问题才会正式训练**。它支持-1, 0以及正整数,-1表示做完整个validation,0表示不做**。
# (默认) 正式训练前先做2个batches的validation
trainer = Trainer(num_sanity_val_steps=2)
# 做完一整个validation epoch才开始训练
trainer = Trainer(num_sanity_val_steps=-1)
# 直接开始训练
trainer = Trainer(num_sanity_val_steps=0)
有时候我们为了检查代码或者做测试必须跑完一整个或者更多的epochs,如果一个epoch的时间过长则会浪费时间,Lightning提供了解决方案,它们支持0到1的浮点数和整数,比如0.1代表每个epoch只跑十分之一的数据,10代表每个epoch只跑10个batches:
# 每个训练epoch只跑十分之一的数据
trainer = Trainer(limit_train_batches=0.1)
# 每个测试epoch只跑10个batches
trainer = Trainer(limit_val_batches=10)
以前GPU基本用在游戏上,而现在被广泛应用在深度学习领域,因为GPU能高效地做矩阵运算,运算速度比CPU快进几百倍。而随着网络趋于复杂,计算量越来越大,一台GPU根本不够用,这时候就要多GPUs共同训练,Pytorch本身也支持多节点多GPUs训练,比如之前的DataParallel和DistributedDataParallel,但是开发人员需要自行修改很多代码,对刚刚接触分布式训练的开发人员不太友好,而Lightning则大大简化了这个过程,我们只需去掉代码中的.cuda()和.to(device),初始化Tensor的时候使用type_as和register_buffer**,然后在为Trainer添加对应的fla**g:gpus。
# 使用Lightning之前:
def forward(self, x):
z = torch.Tensor(2, 3)
z = z.cuda(0)
# 使用Lightning之后:
def forward(self, x):
z = torch.Tensor(2, 3)
z = z.type_as(x, device=self.device)
###########################################
# 使用一个GPU
trainer = pl.Trainer(gpus=1)
# 使用8个GPU
trainer = pl.Trainer(gpus=4)
# 使用所有可用的GPU
trainer = pl.Trainer(gpus=-1)
# 指定使用哪几个GPU
trainer = pl.Trainer(gpus=[0,3,4])
有时候,我们不知道那些GPU是被占用的,也就没办法指定GPU,Lightning为此提供了flag,它可以替我们检测可以使用的GPU个数以及序号。
# 不自动选择GPU (直接选择系统中的前两个GPU, 如果它们被占用则会失败)
trainer = Trainer(gpus=2, auto_select_gpus=False)
# 自动从系统中选择两个可用的GPU
trainer = Trainer(gpus=2, auto_select_gpus=True)
# 指定所有的GPU,不管它们是否被占用
Trainer(gpus=-1, auto_select_gpus=False)
# 指定所有可用的GPU (如果只有一个GPU可用,则只会使用一个GPU)
Trainer(gpus=-1, auto_select_gpus=True)
如果我们想要监测GPU内存的使用状况,Lightning也提供了相应的flag。使用的话可能会使训练变慢,因为它使用的是nvidia-smi的输出。
# 默认不监测GPU内存
trainer = Trainer(log_gpu_memory=None)
# 监测主节点上的所有GPU
trainer = Trainer(log_gpu_memory='all')
# 只记录主节点上的最小以及最大GPU内存使用
trainer = Trainer(log_gpu_memory='min_max')
如果你模型的输入大小保持不变,那么可以设置cudnn.benchmark为True,这样可以加速训练,如果输入大小不固定,那么反而会减慢训练
`
pytorch-lightning 中保存断点用的是回调函数 ModelCheckpoint,并且必须是在验证循环结束后才会保存。这样的方式不适合于一些特殊任务,例如 Transformer 结构下的语音识别模型一般都需要 average 最后10-20 个 epoch 的模型权重。而且对于自回归模型来说进行一次真正的(即不提供真实标签)验证需要的时间较长,实际上整个训练过程中可能并没有验证过程。
重写 ModelCheckpoint,实现每个训练 epoch 结束都保存 checkpoint
class SaveCheckpoint(ModelCheckpoint):
"""save checkpoint after each training epoch without validation.
if ``last_k == -1``, all models are saved. and no monitor needed in this condition.
otherwise, please log ``global_step`` in the training_step. e.g. self.log('global_step', self.global_step)
:param last_k: the latest k models will be saved.
:param save_weights_only: if ``True``, only the model's weights will be saved,
else the full model is saved.
"""
def __init__(self, last_k=5, save_weights_only=False):
if last_k == -1:
super().__init__(save_top_k=-1, save_last=False, save_weights_only=save_weights_only)
else:
super().__init__(monitor='global_step', mode='max', save_top_k=last_k,
save_last=False, save_weights_only=save_weights_only)
def on_train_epoch_end(self, trainer, pl_module, outputs):
"""
save checkpoint after each train epoch
"""
self.save_checkpoint(trainer, pl_module)
def on_validation_end(self, trainer, pl_module):
"""
overwrite the methods in ModelCheckpoint to avoid save checkpoint on the end of the val loop
"""
pass
更详细的说,深度学习项目代码可以分为如下四个部分: