Transformers 4.37 中文文档(十一)(3)https://developer.aliyun.com/article/1564973
捕获记录器流
如果您需要验证记录器的输出,可以使用CaptureLogger
:
from transformers import logging from transformers.testing_utils import CaptureLogger msg = "Testing 1, 2, 3" logging.set_verbosity_info() logger = logging.get_logger("transformers.models.bart.tokenization_bart") with CaptureLogger(logger) as cl: logger.info(msg) assert cl.out, msg + "\n"
使用环境变量进行测试
如果您想测试特定测试的环境变量的影响,可以使用辅助装饰器transformers.testing_utils.mockenv
from transformers.testing_utils import mockenv class HfArgumentParserTest(unittest.TestCase): @mockenv(TRANSFORMERS_VERBOSITY="error") def test_env_override(self): env_level_str = os.getenv("TRANSFORMERS_VERBOSITY", None)
有时需要调用外部程序,这需要在os.environ
中设置PYTHONPATH
以包括多个本地路径。一个辅助类transformers.test_utils.TestCasePlus
来帮助:
from transformers.testing_utils import TestCasePlus class EnvExampleTest(TestCasePlus): def test_external_prog(self): env = self.get_env() # now call the external program, passing `env` to it
根据测试文件是在tests
测试套件还是examples
下,它将正确设置env[PYTHONPATH]
以包括这两个目录之一,并且还将src
目录设置为确保针对当前存储库进行测试,最后还将设置env[PYTHONPATH]
在调用测试之前已经设置的任何内容。
这个辅助方法创建了os.environ
对象的副本,因此原始对象保持不变。
获得可重现的结果
在某些情况下,您可能希望为测试去除随机性。要获得相同的可重现结果集,您需要修复种子:
seed = 42 # python RNG import random random.seed(seed) # pytorch RNGs import torch torch.manual_seed(seed) torch.backends.cudnn.deterministic = True if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) # numpy RNG import numpy as np np.random.seed(seed) # tf RNG tf.random.set_seed(seed)
调试测试
要在警告点启动调试器,请执行以下操作:
pytest tests/utils/test_logging.py -W error::UserWarning --pdb
使用 github actions 工作流
要触发自动推送工作流 CI 作业,必须:
- 在
transformers
源上创建一个新分支(不是分叉!)。 - 分支名称必须以
ci_
或ci-
开头(main
也会触发它,但我们不能在main
上创建 PR)。它还仅针对特定路径触发 - 如果自从编写本文以来发生了更改,您可以在此处找到最新的定义,位于*push:*下。 - 从此分支创建一个 PR。
- 然后您可以在这里看到该作业。如果有积压,它可能不会立即运行。
测试实验性 CI 功能
测试 CI 功能可能会有潜在问题,因为它可能会干扰正常的 CI 功能。因此,如果要添加新的 CI 功能,应按以下步骤进行。
- 创建一个新的专用作业,测试需要测试的内容
- 新作业必须始终成功,以便为我们提供绿色的 ✓(下面有详细信息)。
- 让它运行几天,看看各种不同类型的 PR 是否可以运行在上面(用户分支,非分叉分支,源自 github.com UI 直接文件编辑的分支,各种强制推送等等 - 有很多),同时监视实验性作业的日志(而不是整体作业绿色,因为它故意总是绿色)
- 当一切都很稳定时,然后将新更改合并到现有作业中。
这样,对 CI 功能本身的实验就不会干扰正常的工作流程。
现在我们如何确保工作始终成功,同时新的 CI 功能正在开发中?
一些 CI,如 TravisCI 支持 ignore-step-failure,并将整体作业报告为成功,但截至目前,CircleCI 和 Github Actions 不支持该功能。
因此,可以使用以下解决方法:
- 在运行命令的开头使用
set +euo pipefail
来抑制 bash 脚本中的大多数潜在故障。 - 最后一个命令必须成功:
echo "done"
或只需true
即可
这是一个例子:
- run: name: run CI experiment command: | set +euo pipefail echo "setting run-all-despite-any-errors-mode" this_command_will_fail echo "but bash continues to run" # emulate another failure false # but the last command must be a success echo "during experiment do not remove: reporting success to CI, even if there were failures"
对于简单的命令,您也可以这样做:
cmd_that_may_fail || true
当结果令人满意时,将实验步骤或作业与其余正常作业集成在一起,同时删除set +euo pipefail
或您可能添加的任何其他内容,以确保实验性作业不会干扰正常的 CI 功能。
如果只能为实验步骤设置类似于allow-failure
的内容,并且让它失败而不影响 PR 的整体状态,那么整个过程将变得更加容易。但正如前面提到的,CircleCI 和 Github Actions 目前不支持这一点。
您可以为此功能投票,并查看 CI 特定线程的进展:
拉取请求上的检查
当您在🤗 Transformers 上打开拉取请求时,将运行相当多的检查,以确保您添加的补丁不会破坏任何现有内容。这些检查有四种类型:
- 常规测试
- 文档构建
- 代码和文档样式
- 一般存储库一致性
在这份文档中,我们将尝试解释这些各种检查是什么,以及背后的原因,以及如果其中一个在您的 PR 上失败时如何在本地调试它们。
请注意,理想情况下,它们要求您进行开发安装:
pip install transformers[dev]
或者进行可编辑安装:
pip install -e .[dev]
在 Transformers 存储库内。由于 Transformers 的可选依赖项数量大大增加,您可能无法获得所有依赖项。如果开发安装失败,请确保安装您正在使用的深度学习框架(PyTorch、TensorFlow 和/或 Flax),然后执行以下操作:
pip install transformers[quality]
或者进行可编辑安装:
pip install -e .[quality]
测试
所有以ci/circleci: run_tests_
开头的作业都运行 Transformers 测试套件的部分。这些作业中的每一个都专注于库的某个部分在特定环境中运行:例如,ci/circleci: run_tests_pipelines_tf
在仅安装 TensorFlow 的环境中运行 pipelines 测试。
请注意,为了避免在测试的模块中没有真正更改时运行测试,每次只运行测试套件的一部分:运行一个实用程序来确定库中的差异在 PR 之前和之后(GitHub 在“文件更改”选项卡中显示给您的内容),并选择受该差异影响的测试。该实用程序可以在本地运行:
python utils/tests_fetcher.py
从 Transformers 存储库的根目录开始。它将:
- 检查差异中的每个文件,看看更改是在代码中还是仅在注释或文档字符串中。只保留具有真实代码更改的文件。
- 构建一个内部映射,为库源代码的每个文件提供递归影响的所有文件列表。如果模块 B 导入模块 A,则模块 A 被认为影响模块 B。对于递归影响,我们需要一个从模块 A 到模块 B 的模块链,其中每个模块导入前一个模块。
- 将此映射应用于第 1 步中收集的文件,这给出了 PR 影响的模型文件列表。
- 将这些文件映射到它们对应的测试文件,并获取要运行的测试列表。
在本地执行脚本时,您应该得到步骤 1、3 和 4 的结果打印出来,从而知道运行哪些测试。该脚本还将创建一个名为test_list.txt
的文件,其中包含要运行的测试列表,您可以使用以下命令在本地运行它们:
python -m pytest -n 8 --dist=loadfile -rA -s $(cat test_list.txt)
以防有任何遗漏,完整的测试套件也会每天运行。
文档构建
build_pr_documentation
作业构建并生成文档预览,以确保一切在合并您的 PR 后看起来都没问题。机器人将在您的 PR 中添加一个预览文档的链接。您对 PR 所做的任何更改都会自动更新到预览中。如果文档构建失败,请点击失败作业旁边的详细信息,查看出了什么问题。通常,错误可能只是toctree
中缺少文件。
如果您有兴趣在本地构建或预览文档,请查看文档文件夹中的README.md
。
代码和文档样式
对所有源文件、示例和测试应用代码格式化,使用black
和ruff
。我们还有一个自定义工具负责格式化文档字符串和rst
文件(utils/style_doc.py
),以及 Transformers __init__.py
文件中执行的延迟导入顺序(utils/custom_init_isort.py
)。所有这些都可以通过执行来启动
make style
CI 检查这些已应用于ci/circleci: check_code_quality
检查中。它还运行ruff
,它将基本查看您的代码,并在找到未定义的变量或未使用的变量时发出投诉。要在本地运行该检查,请使用
make quality
这可能需要很长时间,因此要仅对当前分支中修改的文件运行相同的操作,请运行
make fixup
这个最后的命令也将运行所有额外的检查,以确保存储库的一致性。让我们来看看它们。
存储库的一致性
这将汇总所有测试,以确保您的 PR 使存储库保持良好状态,并由ci/circleci: check_repository_consistency
检查执行。您可以通过执行以下操作在本地运行该检查:
make repo-consistency
这些检查包括:
- 所有添加到 init 中的对象都有文档记录(由
utils/check_repo.py
执行) - 所有
__init__.py
文件在其两个部分中具有相同的内容(由utils/check_inits.py
执行) - 所有被识别为从另一个模块复制的代码与原始代码一致(由
utils/check_copies.py
执行) - 所有配置类在其 docstrings 中至少提到一个有效的检查点(由
utils/check_config_docstrings.py
执行) - 所有配置类只包含在相应建模文件中使用的属性(由
utils/check_config_attributes.py
执行) - README 和文档索引的翻译与主 README 中的模型列表相同(由
utils/check_copies.py
执行) - 文档中的自动生成表是最新的(由
utils/check_table.py
执行) - 即使没有安装所有可选依赖项,库中仍有所有对象可用(由
utils/check_dummies.py
执行) - 所有 docstrings 都正确记录了对象签名中的参数(由
utils/check_docstrings.py
执行)
如果此检查失败,前两项需要手动修复,最后四项可以通过运行以下命令自动修复
make fix-copies
额外的检查涉及添加新模型的 PR,主要是:
- 所有添加的模型都在 Auto-mapping 中(由
utils/check_repo.py
执行) - 所有模型都经过适当的测试(由
utils/check_repo.py
执行)
检查副本
由于 Transformers 库在模型代码方面非常有主见,每个模型应该完全在单个文件中实现,而不依赖于其他模型,因此我们添加了一个机制,检查给定模型的层的代码副本是否与原始代码保持一致。这样,当有 bug 修复时,我们可以看到所有其他受影响的模型,并选择将修改传递下去或打破副本。
如果一个文件是另一个文件的完全副本,您应该在utils/check_copies.py
的常量FULL_COPIES
中注册它。
这个机制依赖于形式为# Copied from xxx
的注释。xxx
应包含被复制的类或函数的完整路径,该类或函数被复制在下面。例如,RobertaSelfOutput
是BertSelfOutput
类的直接副本,因此您可以在这里看到它有一个注释:
# Copied from transformers.models.bert.modeling_bert.BertSelfOutput
请注意,您可以将此应用于整个类,也可以将其应用于从中复制的相关方法。例如,在这里中,您可以看到RobertaPreTrainedModel._init_weights
是从BertPreTrainedModel
中的相同方法复制的,并带有注释:
# Copied from transformers.models.bert.modeling_bert.BertPreTrainedModel._init_weights
有时副本完全相同,除了名称:例如,在RobertaAttention
中,我们使用RobertaSelfAttention
而不是BertSelfAttention
,但除此之外,代码完全相同。这就是为什么# Copied from
支持简单的字符串替换,语法如下:Copied from xxx with foo->bar
。这意味着代码被复制,所有foo
的实例都被替换为bar
。您可以在RobertaAttention
中看到它是如何使用的这里。
# Copied from transformers.models.bert.modeling_bert.BertAttention with Bert->Roberta
请注意箭头周围不应该有任何空格(除非该空格是要替换的模式的一部分)。
您可以添加几个用逗号分隔的模式。例如,在这里CamemberForMaskedLM
是RobertaForMaskedLM
的直接副本,有两个替换:Roberta
替换为Camembert
和ROBERTA
替换为CAMEMBERT
。您可以在这里看到这是如何完成的,带有注释:
# Copied from transformers.models.roberta.modeling_roberta.RobertaForMaskedLM with Roberta->Camembert, ROBERTA->CAMEMBERT
如果顺序很重要(因为其中一个替换可能与先前的替换冲突),则替换从左到右执行。
如果替换改变了格式(例如,如果您用一个非常长的名称替换一个短名称),则在应用自动格式化程序后会检查副本。
当模式只是相同替换的不同大小写形式(具有大写和小写变体)时,另一种方法就是添加选项all-casing
。这里是MobileBertForSequenceClassification
中的一个示例,带有注释:
# Copied from transformers.models.bert.modeling_bert.BertForSequenceClassification with Bert->MobileBert all-casing
在这种情况下,代码是通过替换BertForSequenceClassification
复制的:
Bert
替换为MobileBert
(例如,在 init 中使用MobileBertModel
时)bert
替换为mobilebert
(例如在定义self.mobilebert
时)BERT
替换为MOBILEBERT
(在常量MOBILEBERT_INPUTS_DOCSTRING
中)
概念指南
哲学
🤗 Transformers 是一个为以下人群构建的主观库:
- 希望使用、研究或扩展大规模 Transformer 模型的机器学习研究人员和教育工作者。
- 希望微调这些模型或在生产中使用它们的实践者。
- 只想下载预训练模型并用于解决特定机器学习任务的工程师。
该库设计时有两个强烈的目标:
- 尽可能简单快捷地使用:
- 我们强烈限制了用户接触的抽象数量,事实上,几乎没有抽象,只需要三个标准类来使用每个模型:配置、模型和一个预处理类(NLP 的分词器、视觉的图像处理器、音频的特征提取器以及多模态输入的处理器)。
- 所有这些类都可以通过使用通用的
from_pretrained()
方法从预训练实例中简单统一地初始化,该方法会从Hugging Face Hub提供的预训练检查点或您自己保存的检查点下载(如果需要),缓存并加载相关的类实例和相关数据(配置的超参数、分词器的词汇和模型的权重)。 - 除了这三个基本类之外,该库还提供两个 API:pipeline()用于快速在给定任务上使用模型进行推断,以及 Trainer 用于快速训练或微调 PyTorch 模型(所有 TensorFlow 模型都兼容
Keras.fit
)。 - 因此,该库不是神经网络的模块化工具箱。如果您想扩展或构建该库,只需使用常规的 Python、PyTorch、TensorFlow、Keras 模块,并从库的基类继承以重用模型加载和保存等功能。如果您想了解更多关于我们模型编码哲学的信息,请查看我们的Repeat Yourself博客文章。
- 提供性能尽可能接近原始模型的最新模型:
- 我们至少为每种架构提供一个示例,该示例重现了该架构的官方作者提供的结果。
- 代码通常尽可能接近原始代码库,这意味着一些 PyTorch 代码可能不像pytorchic那样,因为它可能是转换为 TensorFlow 代码,反之亦然。
另外几个目标:
- 尽可能一致地暴露模型的内部:
- 我们使用单个 API 访问完整的隐藏状态和注意力权重。
- 预处理类和基础模型 API 被标准化,以便轻松在模型之间切换。
- 整合一组有前途的工具,用于微调和研究这些模型:
- 一种简单而一致的方法,用于向词汇表和嵌入中添加新的标记以进行微调。
- 简单的方法来屏蔽和修剪 Transformer 头。
- 轻松在 PyTorch、TensorFlow 2.0 和 Flax 之间切换,允许使用一个框架进行训练,使用另一个框架进行推断。
主要概念
该库围绕每个模型的三种类型的类构建:
- 模型类可以是 PyTorch 模型(torch.nn.Module)、Keras 模型(tf.keras.Model)或 JAX/Flax 模型(flax.linen.Module),可以使用库中提供的预训练权重。
- 配置类存储构建模型所需的超参数(例如层数和隐藏大小)。您不总是需要自己实例化这些。特别是,如果您使用预训练模型而没有任何修改,创建模型将自动处理实例化配置(这是模型的一部分)。
- 预处理类将原始数据转换为模型接受的格式。一个 tokenizer 存储每个模型的词汇表,并提供编码和解码字符串的方法,以便将其转换为要馈送给模型的标记嵌入索引列表。图像处理器预处理视觉输入,特征提取器预处理音频输入,以及一个处理器处理多模态输入。
所有这些类都可以从预训练实例实例化,保存在本地,并通过三种方法在 Hub 上共享:
from_pretrained()
允许您从库本身提供的预训练版本(支持的模型可以在Model Hub上找到)或用户本地(或服务器上)存储的模型、配置和预处理类实例化。save_pretrained()
允许您将模型、配置和预处理类保存在本地,以便可以使用from_pretrained()
重新加载。push_to_hub()
允许您将模型、配置和预处理类共享到 Hub,以便所有人都可以轻松访问。
Transformers 4.37 中文文档(十一)(5)https://developer.aliyun.com/article/1564975