PyTorch模型训练的几个加速技巧

这里尝试一下网上找到pyorch模型训练加速技巧,尝试一下,看看加速的效果,然后尽可能分析一下加速在哪个地方。

1.有时我们会发现,使用Pytorch的模型,训着训着,越来慢了或者outofmemory,这时我们该怎么解决呢?

    主要是因为,模型可能在不断的产生临时变量,这个时候,我们可以设置程序每隔多少次进行一次清除操作:torch.cuda.empty_cache()

2.在数据读取速度不变的情况下,怎样进一步提高模型的训练速度呢?

    PyTorch 会默认使用 cuDNN 加速,并且cuDNN 里面是有很多加速算法,有些加速算法是针对大矩阵,有些加速算法是针对小矩阵,但 torch.backends.cudnn.benchmark=False,会导致,模型所选择的cuDNN里面的加速算法只是一个通用的,并不是最优。当 torch.backends.cudnn.benchmark=True的时候,模型就会为每一步选择一个最优cuDNN 加速算法,所以第一步的训练速度是慢于常规,但后面都是快于常规。

    但使用这个是有一个前提,模型结构在训练过程中是不变化的,传入数据批次和大小数也是不变的。

3.使用累计梯度做加速。

计算梯度、梯度更新,这两个步骤在每一个batch,都会执行。这里减少梯度更新的次数,来起到加速模型训练的作用。变相的增大了batch_size。不足之处是:会损失一定的精度。我尝试了一下该方法,对加速很有效,查到的资料显示,可以累积[1,10],具体选择 多少,没有说,做了一些实验,发现4的时候效果最好,算是速度和精度的一个balance。

示例:

    for epoch in range(config.num_epochs):
        print('Epoch [{}/{}]'.format(epoch + 1, config.num_epochs))
        for step, batch in enumerate(train_dataloader):
            batch[0] = torch.LongTensor(batch[0]).to(config.device)
            batch[1] = torch.LongTensor(batch[1]).to(config.device)
            loss, logits, hidden_states = model(batch[0], attention_mask=(batch[0] > 0), labels=batch[1])   # Forward pass
            loss_avg = loss / config.accumulation_steps # 多卡训练时,loss的计算方式
            loss_avg.mean().backward()  # Backward pass
            if (step + 1) % config.accumulation_steps == 0:  # Wait for several backward steps
                torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
                optimizer.step()
                model.zero_grad()   # Reset gradients tensors
            if total_batch % config.print_eval_info_step == 0:  # 可以设定打印acc等指标的步长
                label = batch[1].data.cpu()
                predic = torch.max(logits, 1)[1].cpu()
                train_acc = metrics.accuracy_score(label, predic)
                dev_acc, dev_loss = evaluate(model, val_dataloader, config)

4.训练数据预加载。

主要起作用的是BackgroundGenerator,示例:

新建一个文件datax.py,内容:

from torch.utils.data import DataLoader
from prefetch_generator import BackgroundGenerator

class DataLoaderX(DataLoader):

    def __iter__(self):
        return BackgroundGenerator(super().__iter__())

然后再加载数据的地方,将原来的DataLoader替换为DataLoaderX,即可。如下所示:

def split_train_eval_data(train, config):
    # Get text values and labels
    text_values = train['text'] # 训练数据
    tokenizer = config.tokenizer 
    all_input_ids = encode_fn(text_values, tokenizer, config) # 对训练数据编码  
    labels = encode_fn_labels(text_values, tokenizer) # 训练 数据的标签
    # Split data into train and validation
    dataset = TensorDataset(all_input_ids, labels)  # 将训练数据和labels捆绑起来
    train_size = int(config.ratio * len(dataset)) # 将完整的数据划分为训练数据和eval数据
    val_size = len(dataset) - train_size
    train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
    # Create train and validation dataloaders :: , num_workers=10, pin_memory=True
    train_dataloader = DataLoaderX(train_dataset, batch_size=config.batch_size, shuffle=True) # 数据预加载
    val_dataloader = DataLoaderX(val_dataset, batch_size=config.batch_size, shuffle=True)
    return train_dataloader, val_dataloader

 

参考:

1.九大加速训练技巧:https://towardsdatascience.com/9-tips-for-training-lightning-fast-neural-networks-in-pytorch-8e63a502f565(翻译:https://jishuin.proginn.com/p/763bfbd31a84)

2.轻量化模型加速思考:https://jishuin.proginn.com/p/763bfbd31a84

 

你可能感兴趣的:(pytorch,深度学习,算法)