这里尝试一下网上找到pyorch模型训练加速技巧,尝试一下,看看加速的效果,然后尽可能分析一下加速在哪个地方。
主要是因为,模型可能在不断的产生临时变量,这个时候,我们可以设置程序每隔多少次进行一次清除操作:torch.cuda.empty_cache()
PyTorch 会默认使用 cuDNN 加速,并且cuDNN 里面是有很多加速算法,有些加速算法是针对大矩阵,有些加速算法是针对小矩阵,但 torch.backends.cudnn.benchmark=False,会导致,模型所选择的cuDNN里面的加速算法只是一个通用的,并不是最优。当 torch.backends.cudnn.benchmark=True的时候,模型就会为每一步选择一个最优cuDNN 加速算法,所以第一步的训练速度是慢于常规,但后面都是快于常规。
但使用这个是有一个前提,模型结构在训练过程中是不变化的,传入数据批次和大小数也是不变的。
计算梯度、梯度更新,这两个步骤在每一个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