USING TRANSFORMERS(一) | Transformers可以做哪些Task?

目录

 

前言

基本用法

预处理文本序列对

关于填充(padding)和截断(truncation)的所有信息

Pre-tokenized输入


前言

在本教程中,我们将探讨如何使用 Transformers来预处理数据,主要使用的工具称为tokenizer。 tokenizer可以与特定的模型关联的tokenizer类来创建,也可以直接使用AutoTokenizer类来创建。

正如我在素轻:HuggingFace | 一起玩预训练语言模型吧中写到的那样,tokenizer首先将给定的文本拆分为通常称为tokens的单词(或单词的一部分,标点符号等,在中文里可能就是词或字,根据模型的不同拆分算法也不同)。然后tokenizer能够将tokens转换为数字,以便能够构建张量并输入到模型中。当然了,大多数预训练语言模型都需要额外的tokens才能作为一次正常的输入(例如,BERT中的[CLS]),这些都会由tokenizer自动完成。

要自动下载在特定模型在预训练或微调期间使用的vocab,可以使用from_pretrained()方法:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')

基本用法

PreTrainedTokenizer有很多方法,但是你需要记住的唯一方法是它的__call__:你只需要将文本序列提供给tokenizer对象即可:

encoded_input = tokenizer("Hello, I'm a single sentence!")
print(encoded_input)
# {'input_ids': [101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102],
# 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

返回的是一个字典,里面的列表包含了int类别的数据。其中:

  • “input_id”是对应于文本序列中每个token的索引(在vocab中的索引);
  • “attention_mask”是对应于注意力机制的计算,各元素的值为0或1,如果当前token被mask或者是只是用来作为填充的元素,那么其不需要进行注意力机制的计算,其值为0;
  • “token_type_ids”是对应于不同的文本序列,例如在NSP(BERT及某些语言模型中的“Next Sentence Prediction”)任务中需要输入两个文本序列。

当然,如果输入的是索引,tokenizer可以进行反向解码:

tokenizer.decode(encoded_input["input_ids"])
# "[CLS] Hello, I'm a single sentence! [SEP]"

上面解码的[CLS]字符就是大多数预训练语言模型会自动加入的特殊token。tokenizer会自动添加了模型期望的一些特殊token。但是并非所有模型都需要特殊token。例如,如果我们使用gpt2-medium来创建tokenizer,那么解码后的文本序列不会有特殊的token了。你可以通过传递add_special_tokens = False来禁用加入特殊token(仅当你自己添加了这些特殊token时才建议这样做)。

如果要处理多个文本序列,则可以通过将它们作为列表输入到tokenizer:

batch_sentences = ["Hello I'm a single sentence",
                   "And another sentence",
                   "And the very very last one"]
encoded_inputs = tokenizer(batch_sentences)
print(encoded_inputs)
# {'input_ids': [[101, 8667, 146, 112, 182, 170, 1423, 5650, 102],
#               [101, 1262, 1330, 5650, 102],
#               [101, 1262, 1103, 1304, 1304, 1314, 1141, 102]],
# 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
#                    [0, 0, 0, 0, 0],
#                    [0, 0, 0, 0, 0, 0, 0, 0]],
# 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1],
#                    [1, 1, 1, 1, 1],
#                    [1, 1, 1, 1, 1, 1, 1, 1]]}

当然了,在神经网络中,我们常常是通过一个batch的形式来作为一次输入,这个时候你可能想要:

  • 如果必要,将每个文本序列填充到最大的长度;
  • 如果必要,将每个文本序列截断到模型可以接受的最大长度;
  • 返回张量。

将文本序列列表提供给tokenizer时,可以使用以下选项来完成所有这些操作(即设置padding=True, truncation=True, return_tensors="pt"):

注:这里是以PyTorch的tensor形式返回,如果需要以TensorFlow tensor形式返回,只需定义为:return_tensors="pt"。具体参见原文档。​​​​​​

batch = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="pt")
print(batch)
# {'input_ids': tensor([[ 101, 8667,  146,  112,  182,  170, 1423, 5650,  102],
#                      [ 101, 1262, 1330, 5650,  102,    0,    0,    0,    0],
#                      [ 101, 1262, 1103, 1304, 1304, 1314, 1141,  102,    0]]),
# 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0],
#                           [0, 0, 0, 0, 0, 0, 0, 0, 0],
#                           [0, 0, 0, 0, 0, 0, 0, 0, 0]]),
# 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1],
#                           [1, 1, 1, 1, 1, 0, 0, 0, 0],
#                           [1, 1, 1, 1, 1, 1, 1, 1, 0]])}

在输出中可以看到,如果是填充的元素,其attention_mask中对应的位置即为0。

预处理文本序列对

有时你需要为模型提供一对文本。例如,如果你要分类成对的两个句子是否相似,或者是在阅读理解的问题中,需要同时输入上下文和问题。对于BERT模型,输入表示如下:[CLS]序列A [SEP]序列B [SEP]。

您可以通过将两个文本序列作为两个模型期望的参数来提供(这不是一个列表,因为两个文本序列的列表将会被模型理解为一个batch中的两个单个文本序列,就像我们之前看到的那样):

encoded_input = tokenizer("How old are you?", "I'm 6 years old")
print(encoded_input)
# {'input_ids': [101, 1731, 1385, 1132, 1128, 136, 102, 146, 112, 182, 127, 1201, 1385, 102],
# 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
# 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

可以看到这里面token_type_ids的值就是上面所解释的那样。

同样地,如果我们对获得的token ID进行解码,则会看到已正确文本序列对:

tokenizer.decode(encoded_input["input_ids"])
# "[CLS] How old are you? [SEP] I'm 6 years old [SEP]"

如果要处理的是文本序列对列表,则应将它们作为两个列表提供给tokenizer:第一个所有文本序列的列表和第二个所有文本序列的列表:

batch_sentences = ["Hello I'm a single sentence",
                   "And another sentence",
                   "And the very very last one"]
batch_of_second_sentences = ["I'm a sentence that goes with the first sentence",
                             "And I should be encoded with the second sentence",
                             "And I go with the very last one"]
encoded_inputs = tokenizer(batch_sentences, batch_of_second_sentences)
print(encoded_inputs)
# {'input_ids': [[101, 8667, 146, 112, 182, 170, 1423, 5650, 102, 146, 112, 182, 170, 5650, 1115, 2947, 1114, 1103, 1148, 5650, 102],
#               [101, 1262, 1330, 5650, 102, 1262, 146, 1431, 1129, 12544, 1114, 1103, 1248, 5650, 102],
#               [101, 1262, 1103, 1304, 1304, 1314, 1141, 102, 1262, 146, 1301, 1114, 1103, 1304, 1314, 1141, 102]],
#'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
#                   [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
#                   [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
#'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
#                   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
#                   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}

当然你仍然可以反向解码:

for ids in encoded_inputs["input_ids"]:
    print(tokenizer.decode(ids))
# [CLS] Hello I'm a single sentence [SEP] I'm a sentence that goes with the first sentence [SEP]
# [CLS] And another sentence [SEP] And I should be encoded with the second sentence [SEP]
# [CLS] And the very very last one [SEP] And I go with the very last one [SEP]

关于填充(padding)和截断(truncation)的所有信息

三个参数padding,truncationmax_length将做进一步的介绍

  1. padding用于填充。它的参数可以是布尔值或字符串:
  • True或”longest“:填充到最长序列(如果你仅提供单个序列,则不会填充);
  • “max_length”:用于指定你想要填充的最大长度,如果max_length=Flase,那么填充到模型能接受的最大长度(这样即使你只输入单个序列,那么也会被填充到指定长度);
  • False或“do_not_pad”:不填充序列。如前所述,这是默认行为。

2. truncation用于截断。它的参数可以是布尔值或字符串:

  • 如果为True或“only_first”,则将其截断为max_length参数指定的最大长度,如果未提供max_length = None,则模型会截断为模型接受的最大长度。如果提供的是一对文本序列,则只会截断这一对中的第一个文本序列(因为参数“only_first”),如果参数是“only_second”,则只会截断这一对中的第二个文本序列;
  • “longest_first”截断为max_length参数指定的最大长度,如果max_length = None,则截断到模型接受的最大长度;
  • False或“do_not_truncate”不截断序列。如前所述,这是默认行为。

下表总结了设置填充和截断的推荐方法:

 

Pre-tokenized输入

tokenizer还接受pre-tokenized的输入。在命名实体识别(NER)或词性标记(POS)中计算标签并提取预测时,此功能特别有用。

注意:Pre-tokenized并不意味着输入已被tokenized(如果是这种情况,则无需将它们传递给tokenizer了),而只是拆分为多个单词(这通常是subword tokenization算法(如BPE)的第一步)。例如,在下面这个代码中,输入的token为5个,而实际上输入的token索引为9个,这说明了其内部仍需要进行tokenized。

如果要使用pre-tokenized的输入,则在将输入传递给tokenizer时只需设置is_split_into_words=True即可。例如:

encoded_input = tokenizer(["Hello", "I'm", "a", "single", "sentence"], is_split_into_words=True)
print(encoded_input)
# {'input_ids': [101, 8667, 146, 112, 182, 170, 1423, 5650, 102],
# 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
# 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

 请注意,除非传递add_special_tokens = False,否则tokenizer仍会添加特殊token的ID(如果适用)

当然,你可以和前面一样输入文本序列对之类的,或者添加填充和截断的参数。

batch = tokenizer(batch_sentences,
                  batch_of_second_sentences,
                  is_split_into_words=True,
                  padding=True,
                  truncation=True,
                  return_tensors="pt")

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`transformers` 是一个基于 PyTorch 和 TensorFlow 的自然语言处理模型库,它提供了丰富的函数和类,可以用于构建、训练和使用各种预训练的语言模型。下面列举一些常用的函数: - `AutoTokenizer.from_pretrained(model_name_or_path, *args, **kwargs)`: 根据模型名称或路径创建一个 tokenizer 对象,用于将文本转换为模型可以处理的输入格式。 - `AutoModel.from_pretrained(model_name_or_path, *args, **kwargs)`: 根据模型名称或路径创建一个模型对象,用于进行文本的编码、解码和生成等操作。 - `AutoConfig.from_pretrained(model_name_or_path, *args, **kwargs)`: 根据模型名称或路径创建一个配置对象,用于配置模型的参数和超参数。 - `Trainer(model, args, train_dataset, eval_dataset=None, data_collator=None, tokenizer=None, compute_metrics=None, callbacks=None, optimizers=None, lr_scheduler=None, model_init=None, **kwargs)`: 创建一个训练器对象,用于对模型进行训练、评估和预测等操作。 - `pipeline(task, model=None, tokenizer=None, framework='pt', **kwargs)`: 创建一个管道对象,用于对输入文本进行特定任务的处理,例如文本分类、实体识别、问答等。 - `set_seed(seed)`: 设置随机数种子,用于确保实验的可重复性。 - `get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, last_epoch=-1)`: 创建一个学习率调度器对象,用于在训练过程中动态调整学习率。 - `AdamW(params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0.0, correct_bias=True)`: 创建一个 AdamW 优化器对象,用于优化模型的参数。 - `get_cosine_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=0.5, last_epoch=-1)`: 创建一个余弦退火学习率调度器对象,用于在训练过程中动态调整学习率。 - `get_polynomial_decay_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, lr_end=0.0, power=1.0, last_epoch=-1)`: 创建一个多项式衰减学习率调度器对象,用于在训练过程中动态调整学习率。 这些函数只是 `transformers` 提供的众多函数中的几个常用函数,具体使用方式和参数可以参考 `transformers` 的文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值