如何计算最佳批量



有时我会遇到一个问题:

OOM when allocating tensor with shape

例如

OOM when allocating tensor with shape (1024, 100, 160)

1024是我的批量大小,我不知道剩下的是什么。如果我减少批量大小或模型中神经元的数量,它运行得很好。

有没有一种通用的方法可以根据模型和GPU内存计算最佳批量大小,这样程序就不会崩溃?

简言之:就我的模型而言,我想要尽可能大的批量,这将适合我的GPU内存,不会使程序崩溃。

来自Goodfellow等人最近出版的《深度学习》一书,第8章:

小批量大小通常由以下因素驱动:

  • 较大的批次可以更准确地估计梯度,但具有小于线性的回报
  • 多核架构通常小批量使用不足。这促使使用绝对最小批处理大小,低于该大小处理迷你批次的时间
  • 如果批次中的所有示例并行处理(通常情况下),然后内存随批处理大小而变化。对于许多硬件设置,这是批量大小的限制因素
  • 某些类型的硬件实现使用特定大小的数组可以获得更好的运行时间。尤其是在使用时GPU,通常情况下,2个批量大小的功率可以提供更好的运行时间。2个批次的典型功率范围从32到256,有时为16正在尝试用于大型模型
  • 小批量可以提供规则化效应(Wilson和Martinez,2003),可能是由于它们给学习过程增加了噪音。泛化错误经常最适合批量大小为1。小批量训练可能需要较小的学习率来保持稳定性,因为梯度估计中的高方差。总运行时间由于需要采取更多步骤,两者都可能非常高因为学习率降低,而且需要更多的步骤观察整个训练过程

这在实践中通常意味着">的幂,并且越大越好,前提是该批适合您的(GPU)内存";。

您可能还想在Stack Exchange中查阅几篇好文章:

  • 权衡批量大小与训练神经网络的迭代次数
  • 神经网络回归的小批量选择
  • 随机梯度下降的批量大小应该有多大

请记住,Keskar等人的论文《关于深度学习的大批量训练:泛化差距和Sharp Minima》被上面的几篇文章引用,遭到了深度学习界其他受人尊敬的研究人员的反对。

更新(2017年12月):

Yoshua Bengio&团队,《影响SGD极小值的三个因素》(2017年11月);值得一读的是,它报道了新的理论和实践;关于学习率和批量大小之间相互作用的实验结果。

更新(2021年3月):

这里感兴趣的还有2018年的另一篇论文,Revisiting Small Batch Training for Deep Neural Networks(h/t to Nicolas Gervais),该论文与建议相反,越大越好;引用摘要:

对于m=2和m=32之间的小批量大小,始终获得最佳性能,这与最近提倡使用数千个小批量大小的工作形成了鲜明对比。

您可以使用估计最大批量

最大批处理大小=可用GPU内存字节/4/(张量大小+可训练参数)

使用pytorchsummary(pip-install)或keras(内置)提供的摘要。

例如

from torchsummary import summary
summary(model)
.....
.....
================================================================
Total params: 1,127,495
Trainable params: 1,127,495
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.02
Forward/backward pass size (MB): 13.93
Params size (MB): 4.30
Estimated Total Size (MB): 18.25
----------------------------------------------------------------

您放入批处理中的每个实例都需要在内存中进行一次完整的前向/后向传递,而您的模型只需要一次。人们似乎更喜欢二次方的批量大小,可能是因为gpu上的自动布局优化。

当增加批量时,不要忘记线性增加学习率。

假设我们手头有一台16GB内存的特斯拉P100。

(16000 - model_size) / (forward_back_ward_size)
(16000 - 4.3) / 13.93 = 1148.29
rounded to powers of 2 results in batch size 1024

这里有一个函数可以找到训练模型的批量大小:

def FindBatchSize(model):
"""model: model architecture, that is yet to be trained"""
import os, sys, psutil, gc, tensorflow, keras
import numpy as np
from keras import backend as K
BatchFound= 16
try:
total_params= int(model.count_params());    GCPU= "CPU"
#find whether gpu is available
try:
if K.tensorflow_backend._get_available_gpus()== []:
GCPU= "CPU";    #CPU and Cuda9GPU
else:
GCPU= "GPU"
except:
from tensorflow.python.client import device_lib;    #Cuda8GPU
def get_available_gpus():
local_device_protos= device_lib.list_local_devices()
return [x.name for x in local_device_protos if x.device_type == 'GPU']
if "gpu" not in str(get_available_gpus()).lower():
GCPU= "CPU"
else:
GCPU= "GPU"
#decide batch size on the basis of GPU availability and model complexity
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params <1000000):
BatchFound= 64    
if (os.cpu_count() <16) and (total_params <500000):
BatchFound= 64  
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params <2000000) and (total_params >=1000000):
BatchFound= 32      
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params >=2000000) and (total_params <10000000):
BatchFound= 16  
if (GCPU== "GPU") and (os.cpu_count() >15) and (total_params >=10000000):
BatchFound= 8       
if (os.cpu_count() <16) and (total_params >5000000):
BatchFound= 8    
if total_params >100000000:
BatchFound= 1
except:
pass
try:
#find percentage of memory used
memoryused= psutil.virtual_memory()
memoryused= float(str(memoryused).replace(" ", "").split("percent=")[1].split(",")[0])
if memoryused >75.0:
BatchFound= 8
if memoryused >85.0:
BatchFound= 4
if memoryused >90.0:
BatchFound= 2
if total_params >100000000:
BatchFound= 1
print("Batch Size:  "+ str(BatchFound));    gc.collect()
except:
pass
memoryused= [];    total_params= [];    GCPU= "";
del memoryused, total_params, GCPU;    gc.collect()
return BatchFound

我遇到了一个类似的GPU内存错误,通过以下配置tensorflow会话解决了这个错误:

# See https://www.tensorflow.org/tutorials/using_gpu#allowing_gpu_memory_growth
config = tf.ConfigProto()
config.gpu_options.allow_growth = True

请参阅:带有GPU 的谷歌协作`ResourceExhaustedError`

最新更新