如何禁用TOKENIZERS_PALLELISM=(true|false)警告



我使用pytorch来训练拥抱面变压器模型,但每个历元,总是输出警告:

The current process just got forked. Disabling parallelism to avoid deadlocks... To disable this warning, please explicitly set TOKENIZERS_PARALLELISM=(true | false)

如何禁用此警告?

将环境变量设置为字符串"false"

通过

TOKENIZERS_PARALLELISM=false

在你的外壳

或通过:

import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"

在Python脚本中

我将在这里留下这条评论,以帮助任何想知道是否可以保持并行性的人。此外,因为这是第一个直接在谷歌上搜索错误的stackoverflow页面。

根据github上的这条评论,FastTokenizer似乎是问题所在。此外,根据gitmemory上的另一条评论,在分叉进程之前,不应该使用标记化器(这基本上意味着在通过数据加载器迭代之前)

因此,解决方案是在训练/微调使用普通令牌之前不要使用FastTokenizer。

查看huggingface文档,了解您是否真的需要FastTokenizer。

如果您明确选择了快速(Rust代码)标记器,那么这样做可能是有原因的。当处理大型数据集时,基于Rust的标记器处理数据的速度要快得多,并且可以通过设置";use_fast";选项。现在几乎所有的HF型号都有这个选项。虽然从警告消息中看不明显,但TOKENIZERS_PALLELISM是一个env变量&而不是一个标记器超参数。通过将其设置为False,问题确实消失了,但正如上面的一些评论所示,这一变化的影响令人困惑。例如,这会影响模型级别的并行性吗?让我们看看Rust代码,看看默认行为是什么,如果我们关闭它来解决问题,会发生什么。

https://docs.rs/tokenizers/latest/src/tokenizers/utils/parallelism.rs.html在大多数情况下,我们(最终用户)不会将TOKENIZERS_PALLELISM显式设置为True或False。对于所有这样的情况,标记器代码都假定它为TRUE。我们可以通过将其设置为False来显式禁用它。但您可以看到,在这种情况下,代码会使迭代器串行化。即使您没有将这个env变量设置为False,如果稍后遇到Python分叉,执行代码本身也会这样做(这就是导致首先显示警告的原因)。我们能避免这种情况吗?

让我们从警告本身后退一步。

"在已经使用了并行性之后,当前进程刚刚分叉。正在禁用并行以避免死锁。。。要禁用此警告,您可以:-如果可能的话,避免在fork之前使用tokenizers-显式设置环境变量TOKENIZERS_PALLELISM=(true|false)">

这种情况只发生在HF的FastTokenizer上,因为它们在Rust中进行并行处理。在这种情况下,当我们在Python中通过多处理派生进程时,会发生冲突。之所以会发生分叉,是因为我们已经开始在train()方法中的数据加载程序(num_workers>0)上循环。这种组合被认为是不安全的,如果遇到这种情况,标记器会关闭自身的并行性以避免死锁。当我们在这里谈论并行性时,我们严格指代标记器代码,而不是其他任何代码。换句话说,只有我们将输入文本数据转换为令牌的代码部分(比如使用tokenizer.encode_plus或任何其他函数)才会受到影响。因此,这不应该影响num_workers使用并行线程,因为num_worker利用了多个GPU内核。。。就像数据加载器功能一样。我们该怎么说呢?好吧,我们可以尝试在数据集get_item函数中添加5秒的延迟和print语句,然后通过在数据加载器上循环num_workers的diff值来自己查看。当num_workers=0时,主进程执行繁重的任务,两次获取之间有5秒的间隔。当num_workers=1发生分叉时,我们会收到上面关于并行性的警告,并且由于主进程不参与数据提升,因此两次获取之间仍有5秒的间隔。来自num_workers>2,在5秒的时间间隔内,根据num_workers有多个回迁。

事实上,这导致了这样一个结论,即修复上述警告的一个简单选项可能是在数据加载器定义中简单地使num_workers=0。如果num_workers为0,那么就没有Python fork,所有的数据提升都由主进程自己完成。这是可行的,我们现在能够最大限度地利用快速标记器的功能,但要在Python端消除并行处理。考虑到数据加载程序在并行模式下的最佳工作方式是从主机(CPU)并行预取批到GPU以供执行,这通常不是一个好的选择。

如果我们将TOKENIZERS_PALLELISM设置为true,会发生什么?在Pytorch、transformers、tokenisers等的最新版本上,如果你这样做,然后尝试使用num_workers>0,则您的训练将冻结,而不会出现任何错误甚至警告消息。事实上,这个问题促使我发布这个答案,因为我在任何地方都找不到解决训练冻结问题的方法。根本原因实际上是数据加载器在这种情况下由于上述冲突而失败(由于担心死锁,它拒绝"分叉")。

因此,回到我们的核心问题,基于RUST的并行性似乎与我们在Python中使用的fork相冲突。然而,这可以通过在训练调用之前(即在使用数据加载器之前)简单地去除所有标记器的使用来容易地解决。很多时候,我们可能会通过执行my_dataset_name[0]来使用标记器来查看标记输出等。只需移除所有这样的标记器调用,并让train()函数循环成为第一次访问标记器的循环。这个简单的修复程序使RUST并行化发生在Python分叉之后,这应该可以工作。

或者,预先将数据转换为令牌,并将其存储在dict中。然后,数据集根本不应该使用令牌化器,而是在运行时简单地调用dict(key),其中key是索引。这样可以避免冲突。警告仍然存在,但您在训练过程中不再使用标记器(注意,对于此类场景,为了节省空间,避免在标记过程中进行填充,稍后使用collegel_fn添加)

话虽如此,Rust令牌化器的实现速度非常快,即使在令牌化器内部调用串行化选项,也通常无关紧要,即在令牌化程序中自动禁用并行性。它仍然胜过传统的代币持有者。

因此,在大多数情况下,可以忽略警告,并在执行过程中禁用标记器并行化。。。或者从一开始就明确地将TOKENIZERS_ PARALLERSM设置为False。在极少数情况下,速度至关重要,可以探索上述建议的选项之一。

我通过将huggingface的转染子库版本从3.0.0降级到2.11.0,并将标记器的库版本从0.8.0rc4降级到0.7.0来解决这个问题。

这似乎是huggingface的标记库版本的问题;0.8.0rc4〃;。目前,似乎还没有解决方案可以将TOKENIZERS_PALLELISM=(true|false)设置为错误消息。

参考:https://github.com/ThilinaRajapakse/simpletransformers/issues/515

将环境变量设置为字符串"false":

  1. 在Bash
export TOKENIZERS_PARALLELISM=false
  1. 在Python上
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"

最新更新