ByT5
概述
ByT5 模型在 Linting Xue、Aditya Barua、Noah Constant、Rami Al-Rfou、Sharan Narang、Mihir Kale、Adam Roberts 和 Colin Raffel 发表的论文 ByT5:利用预训练的字节到字节模型迈向无标记的未来 中提出。
论文摘要如下:
大多数广泛使用的预训练语言模型都作用于对应于单词或子词单元的标记序列。将文本编码为标记序列需要分词器,分词器通常作为与模型独立的构件创建。相反,直接作用于原始文本(字节或字符)的无标记模型具有许多优点:它们可以开箱即用地处理任何语言的文本,它们对噪声更鲁棒,并且通过消除复杂且容易出错的文本预处理管道来最大程度地减少技术债务。由于字节或字符序列比标记序列更长,因此过去关于无标记模型的工作通常引入了旨在摊销直接作用于原始文本的成本的新模型架构。在本文中,我们表明,标准 Transformer 架构可以在进行最少修改的情况下用于处理字节序列。我们仔细描述了参数数量、训练 FLOPs 和推理速度方面的权衡,并表明字节级模型与它们对应的标记级模型具有竞争力。我们还证明,字节级模型对噪声的鲁棒性明显更强,并且在对拼写和发音敏感的任务上表现更好。作为我们贡献的一部分,我们发布了一套新的基于 T5 架构的预训练字节级 Transformer 模型,以及我们实验中使用的所有代码和数据。
此模型由 patrickvonplaten 贡献。原始代码可以 在这里 找到。
ByT5 的架构基于 T5v1.1 模型,有关 API 参考,请参阅 T5v1.1 的文档页面。它们仅在如何为模型准备输入方面有所不同,请参见下面的代码示例。
由于 ByT5 是无监督地进行预训练的,因此在单任务微调期间使用任务前缀没有真正的优势。如果您正在进行多任务微调,则应使用前缀。
使用示例
ByT5 使用原始 UTF-8 字节,因此无需分词器即可使用。
>>> from transformers import T5ForConditionalGeneration
>>> import torch
>>> model = T5ForConditionalGeneration.from_pretrained("google/byt5-small")
>>> num_special_tokens = 3
>>> # Model has 3 special tokens which take up the input ids 0,1,2 of ByT5.
>>> # => Need to shift utf-8 character encodings by 3 before passing ids to model.
>>> input_ids = torch.tensor([list("Life is like a box of chocolates.".encode("utf-8"))]) + num_special_tokens
>>> labels = torch.tensor([list("La vie est comme une boîte de chocolat.".encode("utf-8"))]) + num_special_tokens
>>> loss = model(input_ids, labels=labels).loss
>>> loss.item()
2.66
但是,对于批处理推理和训练,建议使用分词器。
>>> from transformers import T5ForConditionalGeneration, AutoTokenizer
>>> model = T5ForConditionalGeneration.from_pretrained("google/byt5-small")
>>> tokenizer = AutoTokenizer.from_pretrained("google/byt5-small")
>>> model_inputs = tokenizer(
... ["Life is like a box of chocolates.", "Today is Monday."], padding="longest", return_tensors="pt"
... )
>>> labels_dict = tokenizer(
... ["La vie est comme une boîte de chocolat.", "Aujourd'hui c'est lundi."], padding="longest", return_tensors="pt"
... )
>>> labels = labels_dict.input_ids
>>> loss = model(**model_inputs, labels=labels).loss
>>> loss.item()
17.9
与 T5 类似,ByT5 在跨度掩码去噪任务上进行训练。但是,由于模型直接作用于字符,因此预训练任务略有不同。让我们破坏输入句子“The dog chases a ball in the park.” 的一些字符,并要求 ByT5 为我们预测这些字符。
>>> from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
>>> import torch
>>> tokenizer = AutoTokenizer.from_pretrained("google/byt5-base")
>>> model = AutoModelForSeq2SeqLM.from_pretrained("google/byt5-base")
>>> input_ids_prompt = "The dog chases a ball in the park."
>>> input_ids = tokenizer(input_ids_prompt).input_ids
>>> # Note that we cannot add "{extra_id_...}" to the string directly
>>> # as the Byte tokenizer would incorrectly merge the tokens
>>> # For ByT5, we need to work directly on the character level
>>> # Contrary to T5, ByT5 does not use sentinel tokens for masking, but instead
>>> # uses final utf character ids.
>>> # UTF-8 is represented by 8 bits and ByT5 has 3 special tokens.
>>> # => There are 2**8+2 = 259 input ids and mask tokens count down from index 258.
>>> # => mask to "The dog [258]a ball [257]park."
>>> input_ids = torch.tensor([input_ids[:8] + [258] + input_ids[14:21] + [257] + input_ids[28:]])
>>> input_ids
tensor([[ 87, 107, 104, 35, 103, 114, 106, 35, 258, 35, 100, 35, 101, 100, 111, 111, 257, 35, 115, 100, 117, 110, 49, 1]])
>>> # ByT5 produces only one char at a time so we need to produce many more output characters here -> set `max_length=100`.
>>> output_ids = model.generate(input_ids, max_length=100)[0].tolist()
>>> output_ids
[0, 258, 108, 118, 35, 119, 107, 104, 35, 114, 113, 104, 35, 122, 107, 114, 35, 103, 114, 104, 118, 257, 35, 108, 113, 35, 119, 107, 104, 35, 103, 108, 118, 102, 114, 256, 108, 113, 35, 119, 107, 104, 35, 115, 100, 117, 110, 49, 35, 87, 107, 104, 35, 103, 114, 106, 35, 108, 118, 35, 119, 107, 104, 35, 114, 113, 104, 35, 122, 107, 114, 35, 103, 114, 104, 118, 35, 100, 35, 101, 100, 111, 111, 35, 108, 113, 255, 35, 108, 113, 35, 119, 107, 104, 35, 115, 100, 117, 110, 49]
>>> # ^- Note how 258 descends to 257, 256, 255
>>> # Now we need to split on the sentinel tokens, let's write a short loop for this
>>> output_ids_list = []
>>> start_token = 0
>>> sentinel_token = 258
>>> while sentinel_token in output_ids:
... split_idx = output_ids.index(sentinel_token)
... output_ids_list.append(output_ids[start_token:split_idx])
... start_token = split_idx
... sentinel_token -= 1
>>> output_ids_list.append(output_ids[start_token:])
>>> output_string = tokenizer.batch_decode(output_ids_list)
>>> output_string
['<pad>', 'is the one who does', ' in the disco', 'in the park. The dog is the one who does a ball in', ' in the park.']
ByT5Tokenizer
类 transformers.ByT5Tokenizer
< 源代码 >( eos_token = '</s>' unk_token = '<unk>' pad_token = '<pad>' extra_ids = 125 additional_special_tokens = None **kwargs )
参数
- eos_token (
str
, 可选, 默认为"</s>"
) — 序列结束标记。当使用特殊标记构建序列时,这不是用于序列结束的标记。使用的标记是
sep_token
。 - unk_token (
str
, 可选, 默认为"<unk>"
) — 未知标记。不在词汇表中的标记无法转换为 ID,而是设置为此标记。 - pad_token (
str
, 可选, 默认为"<pad>"
) — 用于填充的标记,例如在批处理不同长度的序列时。 - extra_ids (
int
, 可选, 默认为 125) — 添加一定数量的额外 ID 到词汇表的末尾,用作哨兵。这些标记可以访问为“id{%d}>” 其中“{%d}” 是 0 到 extra_ids-1 之间的数字。额外标记从词汇表的末尾到开头进行索引(“ ” 是词汇表中的最后一个标记,如 ByT5 预处理中所见,请参阅 此处)。 - additional_special_tokens (
List[str]
, 可选) — 分词器使用的其他特殊标记。
构建 ByT5 分词器。ByT5 简单地使用原始字节 utf-8 编码。
此分词器继承自 PreTrainedTokenizer,其中包含大多数主要方法。用户应参考此超类以获取有关这些方法的更多信息。
build_inputs_with_special_tokens
< 源代码 >( token_ids_0: List token_ids_1: Optional = None ) → List[int]
通过连接和添加特殊标记,从序列或一对序列构建用于序列分类任务的模型输入。一个序列具有以下格式
- 单个序列:
X </s>
- 序列对:
A </s> B </s>
将一系列标记(字符串)转换为单个字符串。
create_token_type_ids_from_sequences
< 源代码 >( token_ids_0: List token_ids_1: Optional = None ) → List[int]
创建一个从两个传递的序列生成的掩码,用于序列对分类任务。ByT5 不使用标记类型 ID,因此返回一个零列表。
get_special_tokens_mask
< 源代码 >( token_ids_0: List token_ids_1: Optional = None already_has_special_tokens: bool = False ) → List[int]
从未添加特殊令牌的令牌列表中检索序列 ID。当使用分词器 prepare_for_model
方法添加特殊令牌时,会调用此方法。
有关所有详细信息,请参阅 ByT5Tokenizer。
< > 在 GitHub 上更新