【问题标题】:How to calculate optimal batch size如何计算最佳批量大小
【发布时间】:2018-03-21 03:12:50
【问题描述】:

有时我会遇到问题:

用形状分配张量时的OOM

e.q.

分配形状为 (1024, 100, 160) 的张量时的 OOM

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

是否有一种通用的方法可以根据模型和 GPU 内存计算最佳批量大小,从而使程序不会崩溃?

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

【问题讨论】:

    标签: machine-learning neural-network deep-learning keras gradient-descent


    【解决方案1】:

    来自 Goodfellow 等人最近的深度学习书籍,chapter 8

    小批量大小通常受以下因素影响:

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

    这在实践中通常意味着“2 的幂,越大越好,前提是批次适合您的 (GPU) 内存”。

    您可能还想参考 Stack Exchange 中的几个好帖子:

    请记住,Keskar 等人的论文。上面几篇文章引用的“On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima”已收到深度学习社区其他受人尊敬的研究人员的some objections

    希望这会有所帮助...

    更新(2017 年 12 月):

    Yoshua Bengio & team 发表了一篇新论文,Three Factors Influencing Minima in SGD(2017 年 11 月);值得一读的是,它报告了关于学习率和批量大小之间相互作用的新理论和实验结果。

    更新(2021 年 3 月):

    有趣的是 2018 年的另一篇论文 Revisiting Small Batch Training for Deep Neural Networks(H/T 致 Nicolas Gervais),这与 越大越好 的建议相反;引用摘要:

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

    【讨论】:

    • 它并没有真正回答我的问题。就我的模型而言,我想要最大的批量大小,这将适合我的 GPU 内存。
    • 明白。在实践中,特别是如果您使用 GPU,2 的幂要求是如此有限,以至于即使您获得了 800 的“最佳”大小,您也永远不会使用它;你要做的是从一个 n(2 的幂)开始,如果你得到一个 OOM,尝试使用 n/2,然后使用 n/4 等(如果没有,你尝试 2*n) - 请参阅上面的第 4 个项目符号跨度>
    • 在您尝试超参数和拓扑时,如果发生错误,减小尺寸是一件很麻烦的事情。一个通用的公式会很棒。即使结果会四舍五入到 2 的幂。
    • 我看不出您的摘录如何使您得出“越大越好”的结论。也许您可以查明使您得出结论的确切来源?
    • @NicolasGervais 第一个项目符号怎么样,“大批量提供更准确的梯度估计”??
    【解决方案2】:

    您可以使用以下方法估算最大批量大小:

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

    【讨论】:

    • 如何获得张量大小可训练参数个数?您没有遗漏方程式中的模型尺寸吗?
    • @gisek 模型大小实际上是训练参数的数量,在 Keras 中你可以使用 model.summary()
    • @desertnaut 呵呵,我没明白“no”代表“number”。现在它是有道理的:)
    • 什么是张量大小?我仍然对那部分感到困惑。
    • @Melike 每一层都有其张量 + 一个或多个权重矩阵(通常称为可训练参数)。例如:如果您为网络提供 200x200 RGB 图像,那么输入张量的大小(以字节为单位)为 [batch size] * 3 * 200 * 200(如果使用 64 位整数,则为 * 4)
    【解决方案3】:

    使用 pytorchsummary (pip install) 或 keras (builtin) 提供的摘要。

    例如

    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
    ----------------------------------------------------------------
    

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

    在增加批量大小时不要忘记线性增加学习率。

    假设我们手头有一台具有 16 GB 内存的 Tesla P100。

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

    【讨论】:

      【解决方案4】:

      这是一个查找用于训练模型的批量大小的函数:

      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
      

      【讨论】:

      • 您能否解释一下代码以及为什么 if 条件指向特定的批量大小?您的代码是否处理每个样本的内存大小?
      【解决方案5】:

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

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

      见:google colaboratory `ResourceExhaustedError` with GPU

      【讨论】:

      • 不幸的是,它对大型网络没有任何改变:(
      • 是的。在我的情况下,colaboratory 以 12GB 启动,但启用该选项后,它可以增长到 52GB
      • 在tf2.0中,你应该先from tensorflow.compat.v1 import ConfigProto
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-05
      • 1970-01-01
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多