Google Colab Fine Tuning BERT Base Cased with Transformers and PyTorch 中出现间歇性“RuntimeError: CUDA out

Posted

技术标签:

【中文标题】Google Colab Fine Tuning BERT Base Cased with Transformers and PyTorch 中出现间歇性“RuntimeError: CUDA out of memory”错误【英文标题】:Intermittent "RuntimeError: CUDA out of memory" error in Google Colab Fine Tuning BERT Base Cased with Transformers and PyTorch 【发布时间】:2020-10-09 14:16:12 【问题描述】:

我正在运行以下代码来微调 Google Colab 中的 BERT Base Cased 模型。有时代码第一次运行良好而没有错误。其他时候,使用相同数据的相同代码会导致“CUDA 内存不足”错误。以前,重新启动运行时或退出笔记本,回到笔记本,进行工厂运行时重启,然后重新运行代码可以成功运行而不会出错。就在刚才,我尝试了重新启动并重试了 5 次,每次都出现错误。

问题似乎不是我正在使用的数据和代码的组合,因为有时它可以正常工作。所以这似乎与 Google Colab 运行时有关。

有谁知道为什么会发生这种情况、为什么会出现间歇性和/或我能做些什么?

我正在使用 Huggingface 的 transformers 库和 PyTorch

导致错误的代码单元:

# train the model
%%time

history = defaultdict(list)

for epoch in range(EPOCHS):

  print(f'Epoch epoch + 1/EPOCHS')
  print('-' * 10)

  train_acc, train_loss = train_epoch(
    model,
    train_data_loader,    
    loss_fn, 
    optimizer, 
    device, 
    scheduler, 
    train_set_length
  )

  print(f'Train loss train_loss accuracy train_acc')

  dev_acc, dev_loss = eval_model(
    model,
    dev_data_loader,
    loss_fn, 
    device, 
    evaluation_set_length
  )

  print(f'Dev   loss dev_loss accuracy dev_acc')

  history['train_acc'].append(train_acc)
  history['train_loss'].append(train_loss)
  history['dev_acc'].append(dev_acc)
  history['dev_loss'].append(dev_loss)

  model_filename = f'model_epoch_state.bin'
  torch.save(model.state_dict(), model_filename)

完整的错误:


RuntimeError                              Traceback (most recent call last)
<ipython-input-29-a13774d7aa75> in <module>()
----> 1 get_ipython().run_cell_magic('time', '', "\nhistory = defaultdict(list)\n\nfor epoch in range(EPOCHS):\n\n  print(f'Epoch epoch + 1/EPOCHS')\n  print('-' * 10)\n\n  train_acc, train_loss = train_epoch(\n    model,\n    train_data_loader,    \n    loss_fn, \n    optimizer, \n    device, \n    scheduler, \n    train_set_length\n  )\n\n  print(f'Train loss train_loss accuracy train_acc')\n\n  dev_acc, dev_loss = eval_model(\n    model,\n    dev_data_loader,\n    loss_fn, \n    device, \n    evaluation_set_length\n  )\n\n  print(f'Dev   loss dev_loss accuracy dev_acc')\n\n  history['train_acc'].append(train_acc)\n  history['train_loss'].append(train_loss)\n  history['dev_acc'].append(dev_acc)\n  history['dev_loss'].append(dev_loss)\n  \n  model_filename = f'model_epoch_state.bin'\n  torch.save(model.state_dict(), model_filename)")

15 frames
<decorator-gen-60> in time(self, line, cell, local_ns)

<timed exec> in <module>()

/usr/local/lib/python3.6/dist-packages/transformers/modeling_bert.py in forward(self, hidden_states, attention_mask, head_mask, encoder_hidden_states, encoder_attention_mask)
    234         # Take the dot product between "query" and "key" to get the raw attention scores.
    235         attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2))
--> 236         attention_scores = attention_scores / math.sqrt(self.attention_head_size)
    237         if attention_mask is not None:
    238             # Apply the attention mask is (precomputed for all layers in BertModel forward() function)

RuntimeError: CUDA out of memory. Tried to allocate 24.00 MiB (GPU 0; 7.43 GiB total capacity; 5.42 GiB already allocated; 8.94 MiB free; 5.79 GiB reserved in total by PyTorch)

【问题讨论】:

这意味着你试图一次在你的 GPU 上放置大量数据,减少批量大小可能有助于解决这个问题,或者如果你有可能需要增加 GPU 的内存 但我每次都提供完全相同的数据 - 有时会出错,有时不会。所以它似乎不是输入数据的大小。我想知道即使在重新启动/终止会话并重新连接之后,会话是否会保留上一个会话的一些数据? 有多个类似one、antoher one、...的帖子都在讨论过。似乎减少 batch_size 是一个常见的解决方案。但是您可以深入研究并尝试释放无用的内存 【参考方案1】:

我在变形金刚中遇到了同样的问题,变形金刚非常memory intensive。因此,在训练更大的模型或更长的 epoch 时,我们很有可能会耗尽内存或运行时限制。

有一些很有前途的开箱即用策略可以解决这些问题,并且每种策略都有其自身的好处。

动态填充和统一长度批处理(智能批处理) 梯度累积 冻结嵌入 数值精度降低 梯度检查点

在一批序列上训练神经网络需要它们具有完全相同的长度来构建批矩阵表示。因为现实生活中的 NLP 数据集总是由可变长度的文本组成,我们经常需要通过截断它们来缩短一些序列,而通过在末尾添加一个称为“pad”标记的重复假标记来延长另一些序列。

因为 pad token 不代表真实的单词,所以当大多数计算完成后,在计算损失之前,我们通过每个样本的“注意掩码”矩阵将 pad token 信号乘以 0 来擦除 pad token 信号,该矩阵标识[PAD] 标记并告诉 Transformer 忽略它们。

动态填充: 这里我们限制添加的 pad tokens 的数量达到每个 mini batch 的最长序列的长度,而不是为整个 train set 设置一个固定值因为添加的 token 的数量在 mini batch 之间发生变化,我们称之为“动态”padding .

统一长度批处理:

我们通过生成由相似长度序列组成的批次来进一步推动逻辑,因此我们避免了极端情况,即迷你批次中的大多数序列都很短,并且我们需要为每个序列添加大量填充标记,因为 1 个序列相同mini batch 很长。

【讨论】:

以上是关于Google Colab Fine Tuning BERT Base Cased with Transformers and PyTorch 中出现间歇性“RuntimeError: CUDA out的主要内容,如果未能解决你的问题,请参考以下文章

fine-tuning:预训练中的迁移

keras系列︱迁移学习:利用InceptionV3进行fine-tuning及预测完美案例

fine-tuning

Pytorch Note56 Fine-tuning 通过微调进行迁移学习

LLMs Fine-tuning 学习笔记:trl+peft

深度学习前沿应用图像分类Fine-Tuning