在本文中,我描述并展示了我个人发现的4种不同Pytorch训练技巧的代码,这些技巧可以改进我的深度学习模型的训练。混合精度在常规训练循环中,PyTorch以32位精度存储所有浮点变量。对于那些在严格约束下训练的模型,这有时会导致他们的模型占用过多的内存,迫使他们使用更小的模型和更小的批次大小来进行更慢的训练过程。因此,在模型中存储所有具有16位精度的变量/数字可以改善和修复大部分这些问题,例如显着降低模型的内存消耗,加快训练循环,同时仍然保持模型的性能/准确性。在Pytorch中将所有计算转换为16位精度非常简单,只需要几行代码。这里是:scaler=torch.cuda.amp.GradScaler()上面的方法创建了一个梯度缩放标量,以在使用fp16进行操作时最小化梯度下溢。optimizer.zero_grad()withtorch.cuda.amp.autocast():output=model(input).to(device)loss=criterion(output,correct_answer).to(device)scaler.scale(loss).backward()scaler.step(optimizer)scaler.update()使用loss和optimizer进行反向传播时,需要使用scale.scale(loss)而不是loss.backward()和optimizer.step()。使用scaler.step(optimizer)更新优化器。这允许您的标量转换所有梯度,并以16位精度进行所有计算,最后使用scaler.update()更新缩放标量以适应训练梯度。当以16位精度执行所有操作时,可能会出现一些数值不稳定性,导致您可能使用的某些函数无法正常工作。只有某些操作才能以16位精度正确工作。详情请参考官方文档。进度条有一个进度条来指示每个阶段的训练完成百分比是很有用的。为了获得进度条,我们将使用tqdm库。下载和导入它的方法如下:pipinstalltqdmfromtqdmimporttqdm在你的训练和验证循环中,你必须做:forindex,batchintqdm(enumerate(loader),total=len(loader),position=0,leave=True):trainandAddingthe验证循环的tqdm代码将生成一个进度条,指示您的模型已完成训练的百分比。它应该是这样的:在图中,691表示我的模型需要完成多少批次,7:28表示我的模型在批次691上花费的总时间,1.54it/s表示我的模型在每个批次上花费的平均数量时间。梯度累积如果遇到CUDAoutofmemory错误,则意味着您已经超出了您的计算资源。您可以采取多种措施来解决此问题,包括将所有内容都转换为16位精度、减小模型的批量大小、将其替换为更小的模型等。但有时切换到16位精度并不能完全解决问题问题。解决此问题最直接的方法是减小批量大小,但假设您不想减小批量大小,您可以使用梯度累积来模拟所需的批量大小。请注意,另一种解决CUDA内存不足问题的方法是简单地使用多个GPU,但这是很多人无法使用的选项。假设您的机器/模型只能支持16的批量大小,增加它会导致CUDA内存不足错误,而您想要32的批量大小。梯度累积通过以16的批量大小运行模型两次来工作,总结每个批次的计算梯度,最后在这两个前向传递和梯度累积之后执行优化步骤。要理解梯度累积,重要的是要理解训练神经网络时正在完成的具体功能。假设您有以下训练循环:model=model.train()forindex,batchinenumerate(train_loader):input=batch[0].to(device)correct_answer=batch[1].to(device)optimizer.zero_grad()output=model(input).to(device)loss=criterion(output,correct_answer).to(device)loss.backward()optimizer.step()看上面的代码,关键要记住的是loss.backward()是模型创建和存储梯度,而optimizer.step()实际上是更新权重。如果在调用优化器之前调用loss.backward()两次,梯度将被累加。下面是PyTorch中梯度累加的实现方法:model=model.train()optimizer.zero_grad()forindex,batchinenumerate(train_loader):input=batch[0].to(device)correct_answer=batch[1].to(device)output=model(input).to(device)loss=criterion(output,correct_answer).to(device)loss.backward()if(index+1)%2==0:optimizer.step()optimizer.zero_grad()在上面的例子中,我们的机器只能支持16个批次,而我们想要32个批次,我们本质上是计算2个批次的梯度,然后更新实际权重。这导致有效批量大小为32。译者注:梯度累加只是一种折衷。经过我们的测试,如果梯度累加的话,最后一次loss.backward()的梯度会比前面几次反向传播的权重都高。为什么我们不清除,哈。虽然存在这样的问题,但是这样的训练还是有效果的。16位精度的梯度累加非常相似。model=model.train()optimizer.zero_grad()forindex,batchinenumerate(train_loader):input=batch[0].to(device)correct_answer=batch[1].to(device)withtorch.cuda.amp.autocast():output=model(input).to(device)loss=criterion(output,correct_answer).to(device)scaler.scale(loss).backward()if(index+1)%2==0:scaler.step(optimizer)scaler.update()optimizer.zero_grad()结果评估在大多数机器学习项目中,人们倾向于手动计算用于评估的指标。尽管计算准确性、精确度、召回率和F1等指标并不困难,但在某些情况下,您可能希望拥有这些指标的某些变体,例如加权精度、召回率和F1。计算这些可能需要更多工作,如果您的实现可能无法正确、高效、快速且无错误地计算所有这些指标,您可以使用sklearnsclassification_report库。这是一个专门为计算这些指标而设计的库。fromsklearn.metricsimportclassification_reporty_pred=[0,1,0,0,1]y_correct=[1,1,0,1,1]print(classification_report(y_correct,y_pred))上面的代码是二分类的。您可以配置此功能用于更多目的。第一个列表代表模型的预测,第二个列表代表正确的值。上面的代码将输出:结论在这篇文章中,我讨论了在pytorch中优化深度神经网络训练的4种方法。16位精度减少了内存消耗,可以使用更大的批量大小模拟梯度累积,tqdmprogressbar和sklearnsclassification_report是两个方便的库,可以轻松跟踪模型训练和评估模型性能。就个人而言,我总是使用上述所有训练技术来训练我的神经网络,并在必要时使用梯度累积。最后,如果你正在使用pytorch或者是pytorch的初学者,你可以使用这个库:github/deephub-ai/torch-handle会对你有很大的帮助。
