HuggingFace文档中文翻译

其实学习的过程不过就是查文档,学习文档的过程,不可能什么事情都需要我们自己去造轮子呀,但是如果不读文档,你就不知道有哪些功能,不记得API可以去查,但是,不知道功能,怎么去查呢?
英文文档真的会降低速度,所以自己翻译过来就好了。

阅读文档的过程其实就是一个知识扩展累计的过程,提高认知很重要。

这篇文档是我在学习的过程中顺带翻译,以便后续继续阅读。
大模型和pytorch为主,keras和其他领域写的翻译的比较粗糙,或者直接没翻译

tokenizer做的事儿?

分词,分字以及特殊字符(起始,中止,间隔、分类等特殊字符(可自己设计))

对每个token映射唯一的id

辅助信息,比如当前词属于那个句子(还有一些mask,表示是否是原来的词还是特殊字符等)

from transformers import AutoTokenizer
from transformers import AutoModel
checkpoint = "" #模型名字
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

raw_input = [
    
]
# padding,把句子补充到512左右,truncation=截断词语,使用pytorch
inputs = tokenizer(row_input,padding=True,truncation=True,return_tensors="pt")
inputs是一个字典:
    ’input_ids':tensor(
    [
        [....],[.....]
    ])

也可以通过tokenizer.decode([.....])还原出原来的单词,多了特殊字符: 分类[cls] 终止:[sep]
#如何对数据进行处理
#定义处理函数
def deal(example句子):
    return 一个处理好的句子
raw_datas.map(deal,batched=True)

快速开始

安装:

pip install transformers datasets
pip install torch
pip install tensorflow

pipeline

最简单就可以让你去使用预训练的模型,可以跨NLP,cv的许多任务,包括,文本分类,图像分类等待。

from transformers import pipeline
>>> classifier = pipeline("sentiment-analysis")

情感分析,会加载默认的预训练模型(distilbert-base-uncased-finetuned-sst-2-english)和tokenizer。

就可以开始使用classifier。

classifier("We are very happy to show you the  Transformers library.")
[{'label': 'POSITIVE', 'score': 0.9998}]

如果你有多条输入呢

results = classifier(["We are very happy to show you the  Transformers library.", "We hope you don't hate it."])
>>> for result in results:
...     print(f"label: {result['label']}, with score: {round(result['score'], 4)}")
label: POSITIVE, with score: 0.9998
label: NEGATIVE, with score: 0.5309

pipeline() 也可以为任何你喜欢的任务遍历整个数据集. 在下面这个示例中, 让我们选择自动语音识别作为我们的任务:

speech_recognizer = pipeline("automatic-speech-recognition", model="facebook/wav2vec2-base-960h")

加载一个你想遍历的音频数据集 (查阅 Datasets 快速开始 获得更多信息). 比如, 加载 MInDS-14 数据集:

from datasets import load_dataset, Audio

>>> dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")

你需要确保数据集中的音频的采样率与 facebook/wav2vec2-base-960h 训练用到的音频的采样率一致:

dataset = dataset.cast_column("audio", Audio(sampling_rate=speech_recognizer.feature_extractor.sampling_rate))

当调用"audio" column时, 音频文件将会自动加载并重采样. 从前四个样本中提取原始波形数组, 将它作为列表传给pipeline:

result = speech_recognizer(dataset[:4]["audio"])
>>> print([d["text"] for d in result])
['I WOULD LIKE TO SET UP A JOINT ACCOUNT WITH MY PARTNER ']

对于输入非常庞大的大型数据集 (比如语音或视觉), 你会想到使用一个生成器, 而不是一个将所有输入都加载进内存的列表. 查阅 pipeline API 参考 来获取更多信息.

在pipeline中使用另一个模型和分词器

pipeline()可以容纳Hub中的任何模型, 这让pipeline()更容易适用于其他用例. 比如, 你想要一个能够处理法语文本的模型, 就可以使用Hub上的标记来筛选出合适的模型. 靠前的筛选结果会返回一个为情感分析微调的多语言的 BERT 模型, 你可以将它用于法语文本:

model_name = "nlptown/bert-base-multilingual-uncased-sentiment"

如果是pytorch:使用 AutoModelForSequenceClassificationAutoTokenizer来加载预训练模型和它关联的分词器 (更多信息可以参考下一节的 AutoClass):

from transformers import AutoTokenizer, AutoModelForSequenceClassification

>>> model = AutoModelForSequenceClassification.from_pretrained(model_name)
>>> tokenizer = AutoTokenizer.from_pretrained(model_name)

如果是tensorflow:使用 TFAutoModelForSequenceClassificationAutoTokenizer 来加载预训练模型和它关联的分词器 (更多信息可以参考下一节的 TFAutoClass):

from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

>>> model = TFAutoModelForSequenceClassification.from_pretrained(model_name)
>>> tokenizer = AutoTokenizer.from_pretrained(model_name)

在pipline中可以使用:

classifier = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)
>>> classifier("Nous sommes très heureux de vous présenter la bibliothèque  Transformers.")
[{'label': '5 stars', 'score': 0.7273}]

AutoTokenizer

自动分词器,使用:给模型,然后就可以得到了

from transformers import AutoTokenizer

>>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
>>> tokenizer = AutoTokenizer.from_pretrained(model_name)
encoding = tokenizer("We are very happy to show you the  Transformers library.")
encoding
{'input_ids': [101, 11312, 10320, 12495, 19308, 10114, 11391, 10855, 10103, 100, 58263, 13299, 119, 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]}
#pytorch的分词器
pt_batch = tokenizer(
...     ["We are very happy to show you the  Transformers library.", "We hope you don't hate it."],
...     padding=True, #0填充,语句小于max_length就0填充
...     truncation=True,#截断,语句大于max_length就截断
...     max_length=512,#最大长度
...     return_tensors="pt",#返回类型
... )
#tf的分词器
tf_batch = tokenizer(
...     ["We are very happy to show you the  Transformers library.", "We hope you don't hate it."],
...     padding=True,
...     truncation=True,
...     max_length=512,
...     return_tensors="tf",
... )

AutoModel

输入模型的名字,就可以通过对应的接口找到模型

如果是pytorch的情感分类

from transformers import AutoModelForSequenceClassification

>>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
>>> pt_model = AutoModelForSequenceClassification.from_pretrained(model_name)
现在可以把预处理好的输入批次直接送进模型. 你只需要添加**来解包字典:
pt_outputs = pt_model(**pt_batch)
模型在logits属性输出最终的激活结果. 在 logits上应用softmax函数来查询概率:
pt_predictions = nn.functional.softmax(pt_outputs.logits, dim=-1)

tensorflow的情感分类也是一样,少了一个TF

from transformers import TFAutoModelForSequenceClassification
import tensorflow as tf

>>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(model_name)
tf_outputs = tf_model(tf_batch)
tf_predictions = tf.nn.softmax(tf_outputs.logits, axis=-1)
tf_predictions

模型的最后输出是一个张量而不是一个概率,需要通过softmax转换成概率

保存模型

pytorch:

模型微调结束以后,需要保存模型可以使用PreTrainedModel.save_pretrained(),把分词器和模型都保存下来

pt_save_directory = "./pt_save_pretrained"
>>> tokenizer.save_pretrained(pt_save_directory)
>>> pt_model.save_pretrained(pt_save_directory)

下次使用时直接加载文件夹

pt_model = AutoModelForSequenceClassification.from_pretrained("./pt_save_pretrained")

tensorflow,也是一样滴:

tf_save_directory = "./tf_save_pretrained"
>>> tokenizer.save_pretrained(tf_save_directory)
>>> tf_model.save_pretrained(tf_save_directory)
tf_model = TFAutoModelForSequenceClassification.from_pretrained("./tf_save_pretrained")

将pt和tf之间的互相转换

from transformers import AutoModel

>>> tokenizer = AutoTokenizer.from_pretrained(tf_save_directory)
>>> pt_model = AutoModelForSequenceClassification.from_pretrained(tf_save_directory, from_tf=True)

tensorflow:

from transformers import TFAutoModel

>>> tokenizer = AutoTokenizer.from_pretrained(pt_save_directory)
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True)

参数构建

可以通过AutoConfig来加载模型的参数

比如修改多头

from transformers import AutoConfig

>>> my_config = AutoConfig.from_pretrained("distilbert-base-uncased", n_heads=12)

pytorch:使用AutoModel.from_config()根据你的自定义配置创建一个模型

from transformers import AutoModel

>>> my_model = AutoModel.from_config(my_config)

tensorflow:

使用TFAutoModel.from_config()根据你的自定义配置创建一个模型:

>>> from transformers import TFAutoModel

>>> my_model = TFAutoModel.from_config(my_config)

trainer-pytorch优化训练

所有的模型都是标准的torch.nn.Module,所以可以在训练的时候使用他们,当编写自己的循环时,Transformers为PyTorch提供了一个Trainer类, 它包含了基础的训练循环并且为诸如分布式训练, 混合精度等特性增加了额外的功能

1、使用PreTrainedModel或者torch.nn.Module:

from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased")#也可以自己去创建dataset,dataloader,然后自己去写pytorch的训练,但是这样的话,就没办法用到trainer里面的一些配置

#修改超参数
from transformers import TrainingArguments
training_args = TrainingArguments(
    output_dir="path/to/save/folder/",
    learning_rate=2e-5,
    per_device_train_batch_size=8,
    per_device_eval_batch_size=8,
    num_train_epochs=2,
)
#加载分词器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

#加载数据集
from datasets import load_dataset
dataset = load_dataset("rotten_tomatoes")  # doctest: +IGNORE_RESULT
#创建一个分词的函数,相当于词表,需要将文字映射到词表
def tokenize_dataset(dataset):
    return tokenizer(dataset["text"])
dataset = dataset.map(tokenize_dataset, batched=True)

#创建dataloader,在huggingface中叫DataCollatorWithPadding
from transformers import DataCollatorWithPadding

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

from transformers import Trainer

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    eval_dataset=dataset["test"],
    tokenizer=tokenizer,
    data_collator=data_collator,
) 
trainer.train()

tensorflow:

使用的是keras训练的

model = TFAutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased")
....和torch一样
tf_dataset = model.prepare_tf_dataset(
...     dataset, batch_size=16, shuffle=True, tokenizer=tokenizer
... )  
from tensorflow.keras.optimizers import Adam

model.compile(optimizer=Adam(3e-5))
model.fit(dataset)  # doctest: +SKIP

导航

使用pipelines推理

所有的任务都和pipline()有联系,如果只说明任务的话,那么就会返回默认的模型。

1、自动语言识别

from transformers import pipeline

>>> generator = pipeline(task="automatic-speech-recognition")
generator("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
text': 'I HAVE A DREAM BUT ONE DAY THIS'}

如果结果不好,那就换个模型就好了

generator = pipeline(model="openai/whisper-large")

如果结果不好,那就训练自己的。

如果你有几个输入,把input变成一个列表:

generator(
  ["https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac",   "https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/1.flac",  ]
)

Parameters

可以指定特定的参数

generator = pipeline(model="openai/whisper-large", my_parameter=1)
out = generator(...)  # This will use `my_parameter=1`.

设备device

指定特定的设备,tf,pt通用

generator = pipeline(model="openai/whisper-large", device=0)

如果模型对于单个GPU来说太大,您可以设置device_map="auto"以允许Accelerate自动确定如何加载和存储模型权重。

Batch size

默认情况下,不会使用批处理,因为会更慢

但是仍能够工作

generator = pipeline(model="openai/whisper-large", device=0, batch_size=2)
audio_filenames = [f"audio_{i}.flac" for i in range(10)]
texts = generator(audio_filenames)

任务的具体参数

下面是一个放回时间轴的例子

generator = pipeline(model="facebook/wav2vec2-large-960h-lv60-self", return_timestamps="word")
>>> generator("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
{'text': 'I HAVE A DREAM BUT ONE DAY THIS NATION WILL RISE UP AND LIVE OUT THE TRUE MEANING OF ITS CREED', 'chunks': [{'text': 'I', 'timestamp': (1.22, 1.24)},

正如您所看到的,模型对文本进行了推断,并在句子中读出各种单词时输出。

每个任务都有许多可用的参数,所以请查看每个任务的API参考,看看可以修改哪些参数!例如,AutomaticSpeechRecognitionPipeline有一个chunk_length_s参数,这有助于处理非常长的音频文件(例如,为整个电影或一小时长的视频添加字幕),而模型通常无法自己处理这些文件。

在dataset上使用piplines

pipeline可以在大型数据上使用,最简单的方法是创建一个迭代器

def data():
    for i in range(1000):
        yield f"My example {i}"
        
pipe = pipeline(model="gpt2", device=0)
generated_characters = 0
for out in pipe(data()):
    generated_characters += len(out[0]["generated_text"])

yield可以迭代每一个data()的结果,pipline可以自动的识别input是否可迭代,然后将数据放到GPU,这样我们就不需要把数据之间放入到内存了。

但是这样是一个一个迭代,我们需要的是一个batch,所以,我们可以将它在Datasets上面加载。

from transformers.pipelines.pt_utils import KeyDataset
from datasets import load_dataset

pipe = pipeline(model="hf-internal-testing/tiny-random-wav2vec2", device=0)
dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation[:10]")

for out in pipe(KeyDataset(dataset, "audio")):
    print(out)

视觉的pipeline

在视觉上用pipeline和文本时一致的。

确定任务和分类器,图像可以被检索,是一个本地的路径或者base64-encoded图片,

from transformers import pipeline

>>> vision_classifier = pipeline(model="google/vit-base-patch16-224")
>>> preds = vision_classifier(
...     images="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
... )
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
>>> preds
[{'score': 0.4335, 'label': 'lynx, catamount'}, {'score': 0.0348, 'label': 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor'}, {'score': 0.0324, 'label': 'snow leopard, ounce, Panthera uncia'}, {'score': 0.0239, 'label': 'Egyptian cat'}, {'score': 0.0229, 'label': 'tiger cat'}]

文本的pipeline

from transformers import pipeline

>>> # This model is a `zero-shot-classification` model.
>>> # It will classify text, except you are free to choose any label you might imagine
>>> classifier = pipeline(model="facebook/bart-large-mnli")
>>> classifier(
...     "I have a problem with my iphone that needs to be resolved asap!!",
...     candidate_labels=["urgent", "not urgent", "phone", "tablet", "computer"],
... )
{'sequence': 'I have a problem with my iphone that needs to be resolved asap!!', 'labels': ['urgent', 'phone', 'computer', 'not urgent', 'tablet'], 'scores': [0.504, 0.479, 0.013, 0.003, 0.002]}

多模态pipeline

VQA包含了文本和图像,可以随意的给图像或者url

from transformers import pipeline

>>> vqa = pipeline(model="impira/layoutlm-document-qa")
>>> vqa(
...     image="https://huggingface.co/spaces/impira/docquery/resolve/2359223c1837a7587402bda0f2643382a6eefeab/invoice.png",
...     question="What is the invoice number?",
... )
[{'score': 0.42515, 'answer': 'us-001', 'start': 16, 'end': 16}]
要运行上面的示例,除了安装Transformers之外,还需要安装pytesseract:
sudo apt install -y tesseract-ocr
pip install pytesseract

在pipeline上运行大型的模型使用accelerate

你可以运行pipeline在大型的模型使用accelerate。请安装accelerate:pip install accelerate.

使用device_map="auto"去加载模型。加载opt-1.3b

# pip install accelerate
import torch
from transformers import pipeline

pipe = pipeline(model="facebook/opt-1.3b", torch_dtype=torch.bfloat16, device_map="auto")
output = pipe("This is a cool example!", do_sample=True, top_p=0.95)

也可以使用8bit去加载模型,得安装bitsandbytes,并且添加参数load_in_8bit=True

import torch
from transformers import pipeline

pipe = pipeline(model="facebook/opt-1.3b", device_map="auto", model_kwargs={"load_in_8bit": True})
output = pipe("This is a cool example!", do_sample=True, top_p=0.95)

请注意,您可以用任何支持大型模型加载的hug Face模型替换检查点,例如BLOOM!

使用AutoClass加载预训练实例

如何去加载模型是很有挑战的,因为模型那么多,AutoClass自动加载和推理出正确的模型从给定的checkpoint.from_pretrained()方法可以快速的加载预训练模型,那你就不需要投入资源和时间重新训练模型。

需要注意的是,体系结构指的是模型的骨架,检查点是给定体系结构的权重。Bert是一个体系结构,bert-base-uncased是一个checkpoint,模型是一个通用术语,可以表示体系结构或检查点。

在本教程中,学习:
加载一个预训练的tokenizer。

​ 加载一个预训练的图像处理器

​ 加载一个预训练的特征提取器。

​ 加载一个预训练的processor。

​ 加载一个预训练的模型。

AutoTokenizer

几乎所有的NLP任务都要从tokenizer开始做,tokenizer是将你的输入变成模型可接受的样子。

使用AutoTokenizer.from_pretrained()加载tokenizer

from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

通过分词器,你的输入变成了:一个三元组

sequence = "In a hole in the ground there lived a hobbit."
>>> print(tokenizer(sequence))
{'input_ids': [101, 1999, 1037, 4920, 1999, 1996, 2598, 2045, 2973, 1037, 7570, 10322, 4183, 1012, 102], 
 'token_type_ids': [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]}

音频AutoFeatureExtractor

对于音频任务,你需要加载pretrain的特征提取器AutoFeatureExtractor.from_pretrained():

from transformers import AutoFeatureExtractor

>>> feature_extractor = AutoFeatureExtractor.from_pretrained(
...     "ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition"
... )

多模态AutoProcessor

多模态的任务需要一个 processor处理器,包括两种类型的前处理工具,例如:LayoutLMV2模型需要一个图像处理器处理图片,tokenizer处理文本,如何使用呢

from transformers import AutoProcessor

>>> processor = AutoProcessor.from_pretrained("microsoft/layoutlmv2-base-uncased")

自动导入模型AutoModel

AutoModelForxxx可以让你导入pretrained模型,here 可以找到所有的可使用的任务,比如使用文本序列分类

AutoModelForSequenceClassification.from_pretrained():

from transformers import AutoModelForSequenceClassification

>>> model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased")

这个模型也可以用去其他的任务

from transformers import AutoModelForTokenClassification

>>> model = AutoModelForTokenClassification.from_pretrained("distilbert-base-uncased")

通常,我们建议使用AutoTokenizer类和AutoModelFor类来加载模型的预训练实例。这将确保每次都加载正确的体系结构。在下一个教程中,学习如何使用新加载的标记器、图像处理器、特征提取器和处理器对数据集进行预处理以进行微调。

Tensorflow就是在上面的模型前面加一个TF

数据处理Preprocess

在您可以在数据集上训练模型之前,需要将其预处理为预期的模型输入格式。无论您的数据是文本、图像还是音频,都需要将它们转换并组装成一批张量。Transformers提供了一组预处理类,帮助您为模型准备数据。在本教程中,您将学习以下内容:

  • 文本:你需要Tokenizer去转换序列文本到tokens,转成tensor。
  • 语言:使用Feature extractor去提取特征,转成tensor
  • 图像:使用一个ImageProcessor把图像转换成tensor。
  • 多模态:使用Processor去合并tokenizer和feature extractor/image processor

开始之前先安装

pip install datasets

预处理文本数据的主要工具是tokenizer。tokenizer根据一组规则将文本分割成token。token被转换成数字,然后是张量,成为模型输入。模型所需的任何其他输入都由tokenizer变换后。

如果您计划使用预训练模型,那么使用相关的预训练标记器是很重要的。这确保了文本以与预训练语料库相同的方式分割,并在预训练期间使用相同的相应标记到索引(通常称为词汇表)

使用AutoTokenizer.from_pretrained()方法,去下载词表模型

from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")


#然后将数据放进去
encoded_input = tokenizer("Do not meddle in the affairs of wizards, for they are subtle and quick to anger.")
print(encoded_input)
{'input_ids': [101, 2079, 2025, 19960, 10362, 1999, 1996, 3821, 1997, 16657, 1010, 2005, 2027, 2024, 11259, 1998, 4248, 2000, 4963, 1012, 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],
 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

会放回三个很重要的数据,字典格式:

  • inputs_id:文本中单词对应的词表的位置。
  • attention_mask:代表是否要被注意,为0就代表忽略
  • token_type_id:当超过一个文本序列时,表示这些token属于哪个序列。

返回你的输入,通过input_ids解码后:

tokenizer.decode(encoded_input["input_ids"])
'[CLS] Do not meddle in the affairs of wizards, for they are subtle and quick to anger. [SEP]'

可以看到,在序列上添加了-CLS和SEP(classifier和separator)-在序列上,不是所有的模型都需要这样的特定的tokens,但是如果需要,tokenizer会自动的加上他们。

如果有多个序列需要处理,将他们放到列表。

batch_sentences = [
...     "But what about second breakfast?",
...     "Don't think he knows about second breakfast, Pip.",
...     "What about elevensies?",
... ]
>>> encoded_inputs = tokenizer(batch_sentences)
>>> print(encoded_inputs)
{'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102],
               [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102],
               [101, 1327, 1164, 5450, 23434, 136, 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, 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, 1],
                    [1, 1, 1, 1, 1, 1, 1]]}

pad填充

句子并不总是相同的长度,这可能是一个问题,因为张量,模型输入,需要有一个统一的形状。填充是一种策略,通过在较短的句子中添加特殊的填充标记来确保张量是矩形的。

batch_sentences = [
...     "But what about second breakfast?",
...     "Don't think he knows about second breakfast, Pip.",
...     "What about elevensies?",
... ]
>>> encoded_input = tokenizer(batch_sentences, padding=True)
>>> print(encoded_input)
{'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0],
               [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102],
               [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]],
 '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, 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': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]]}

Truncation截断

有时候序列太长,需要对序列文本进行截断

设置truncation=True就可以限制最大的长度。

encoded_input = tokenizer(batch_sentences, padding=True, truncation=True)

将数据转成tensor

原始的输出是字典配合矩阵,使用return_tensor='pt’即可,pt改成tf即为tensorflow

encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="pt")

音频(不考虑)

视觉

对于计算机视觉任务,您需要一个图像处理器来准备模型的数据集。图像预处理包括将图像转换为模型所期望的输入的几个步骤。这些步骤包括但不限于调整大小、规范化、颜色通道校正和将图像转换为张量。

图像预处理通常遵循某种形式的图像增强。图像预处理和图像增强都对图像数据进行变换,但它们的目的不同:
图像增强以一种有助于防止过拟合和增加模型鲁棒性的方式改变图像。你可以在如何增加你的数据有创意-调整亮度和颜色,裁剪,旋转,调整大小,缩放等。但是,要注意不要通过增强来改变图像的含义。
图像预处理保证图像匹配模型的预期输入格式。当对计算机视觉模型进行微调时,图像必须与模型最初训练时完全一样进行预处理。
您可以使用任何您喜欢的库进行图像增强。对于图像预处理,使用与模型相关联的ImageProcessor
from datasets import load_dataset

>>> dataset = load_dataset("food101", split="train[:100]")

from transformers import AutoImageProcessor

image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")

#图像预处理
from torchvision.transforms import RandomResizedCrop, ColorJitter, Compose

size = (
    image_processor.size["shortest_edge"]
    if "shortest_edge" in image_processor.size
    else (image_processor.size["height"], image_processor.size["width"])
)

_transforms = Compose([RandomResizedCrop(size), ColorJitter(brightness=0.5, hue=0.5)])

该模型接受pixel_values作为输入。ImageProcessor可以处理图像的归一化,并生成适当的张量。创建一个函数,结合图像增强和图像预处理对一批图像进行处理,并生成pixel_values:

def transforms(examples):
    images = [_transforms(img.convert("RGB")) for img in examples["image"]]
    examples["pixel_values"] = image_processor(images, do_resize=False, return_tensors="pt")["pixel_values"]
    return examples

dataset.set_transform(transforms)

#填充
def collate_fn(batch):
    pixel_values = [item["pixel_values"] for item in batch]
    encoding = image_processor.pad(pixel_values, return_tensors="pt")
    labels = [item["labels"] for item in batch]
    batch = {}
    batch["pixel_values"] = encoding["pixel_values"]
    batch["pixel_mask"] = encoding["pixel_mask"]
    batch["labels"] = labels
    return batch

多模态

需要tokenizer和feature extractor

from datasets import load_dataset

>>> lj_speech = load_dataset("lj_speech", split="train")

对于ASR,你可能需要关注audio和text,你可以删掉其他的列

lj_speech = lj_speech.map(remove_columns=["file", "id", "normalized_text"])

记住,你应该总是重新采样你的音频数据集的采样率,以匹配用于预训练模型的数据集的采样率!

lj_speech = lj_speech.cast_column("audio", Audio(sampling_rate=16_000))

Load a processor with AutoProcessor.from_pretrained():

from transformers import AutoProcessor

>>> processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base-960h")

创建一个函数,将数组中包含的音频数据处理为input_values,并将文本标记为标签。这些是模型的输入:

def prepare_dataset(example):
...     audio = example["audio"]

...     example.update(processor(audio=audio["array"], text=example["text"], sampling_rate=16000))

...     return example

将prepare_dataset函数应用于示例:

prepare_dataset(lj_speech[0])

处理器现在已经添加了input_values和标签,采样率也被正确地降采样到16kHz。现在可以将处理过的数据集传递给模型了!

Fine Tune预训练模型

使用预训练模型有很大的好处。它降低了计算成本和碳足迹,并允许您使用最先进的模型,而无需从头开始训练。transformer为广泛的任务提供了成千上万的预训练模型。当你使用预训练模型时,你是在特定于你的任务的数据集上训练它。这就是所谓的微调,一种非常强大的训练技巧。在本教程中,您将使用您选择的深度学习框架微调预训练模型:

  • Fine-tune使用Trainer.
  • Fine-tune使用TensorFlow和Keras
  • Fine-tune使用pytorch

准备数据prepare a dataset

在开始预训练模型时,你需要下载数据然后训练,

from datasets import load_dataset

dataset = load_dataset("yelp_review_full")

正如您现在所知道的,您需要一个tokenizer来处理文本,并包含填充和截断策略来处理任何可变的序列长度。为了一步处理你的数据集,使用Datasets map方法在整个数据集上应用预处理函数:

def tokenize_function(examples):
     return tokenizer(examples["text"], padding="max_length", truncation=True)
tokenized_datasets = dataset.map(tokenize_function, batched=True)
#可以选择更小的数据,如果需要的话
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))

Train训练

pytorch的trainer

transformers提供了一个训练器类优化transformer模型,使其更容易开始训练,而无需手动编写自己的训练循环。Trainer API支持广泛的训练选项和功能,如日志记录、梯度积累和混合精度。

你应该知道你的label的数量,并且指定

from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)

你会看到一个警告,关于一些预训练的权重没有被使用,一些权重被随机初始化。别担心,这很正常!丢弃BERT模型的预训练分类头,代之以随机初始化的分类头。您将在序列分类任务上对这个新模型进行微调,将预训练模型的知识传递给它。

训练的超参数

接下来,创建一个TrainingArguments类,其中包含您可以调优的所有超参数以及用于激活不同训练选项的标志。对于本教程,您可以从默认的训练超参数开始,但请随意尝试这些参数以找到最佳设置。

from transformers import TrainingArguments
training_args = TrainingArguments(output_dir="test_trainer")
Evaluate评估

在训练时trainer没有自动评估模型,你需要给Trainer一个function去计算和评估,evaluate库提供一个简单的评估方法,可以使用evaluate.load()。

import numpy as np
>>> import evaluate

>>> metric = evaluate.load("accuracy")

调用compute on metric来计算预测的准确性。在将预测传递给计算之前,需要将预测转换为logits(记住所有transformer模型都返回logits):

def compute_metrics(eval_pred):
...     logits, labels = eval_pred 
...     predictions = np.argmax(logits, axis=-1) #找到最大的概率
...     return metric.compute(predictions=predictions, references=labels)#label和pred算metric
Trainer

创建一个trainer,包括了训练的超参数,训练和测试数据,评估方法。

trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=small_train_dataset,
...     eval_dataset=small_eval_dataset,
...     compute_metrics=compute_metrics,
... )

就可以开始预训练我们的模型了

trainer.train()
Tensorflow暂时省略

使用原生的pytorch训练

Trainer负责训练循环,并允许您在一行代码中微调模型。对于喜欢编写自己的训练循环的用户,您还可以在原生PyTorch中微调Transformers模型。
此时,您可能需要重新启动笔记本或执行以下代码来释放一些内存

接下来,手动后处理tokenized_dataset,为训练做准备

手动删除text列,因为模型不需要

tokenized_datasets = tokenized_datasets.remove_columns(["text"])

将label列重命名为labels,因为模型期望参数被命名为labels:

tokenized_datasets = tokenized_datasets.rename_column("label", "labels")

设置数据集的格式以返回PyTorch张量而不是列表:

tokenized_datasets.set_format("torch")
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))
DataLoader

为数据集创建dataloader

模型还是使用Auto。。。

from torch.utils.data import DataLoader

train_dataloader = DataLoader(small_train_dataset, shuffle=True, batch_size=8)
eval_dataloader = DataLoader(small_eval_dataset, batch_size=8)
Optimizer and learning rate scheduler

创建一个优化器和学习率调度器来微调模型。让我们使用PyTorch中的AdamW优化器:

from torch.optim import AdamW

>>> optimizer = AdamW(model.parameters(), lr=5e-5)

从Trainer中创建默认学习率调度器:

from transformers import get_scheduler

>>> num_epochs = 3
>>> num_training_steps = num_epochs * len(train_dataloader)
>>> lr_scheduler = get_scheduler(
...     name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps
... )

最后,指定设备使用GPU,如果你有一个访问权限。否则,在CPU上训练可能需要几个小时而不是几分钟。

import torch

>>> device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
>>> model.to(device)
训练loop

要跟踪您的培训进度,请使用tqdm库在培训步骤数上添加进度条:

from tqdm.auto import tqdm

>>> progress_bar = tqdm(range(num_training_steps))

>>> model.train()
>>> for epoch in range(num_epochs):
...     for batch in train_dataloader:
...         batch = {k: v.to(device) for k, v in batch.items()}
...         outputs = model(**batch)
...         loss = outputs.loss
...         loss.backward()

...         optimizer.step()
...         lr_scheduler.step()
...         optimizer.zero_grad()
...         progress_bar.update(1)
评估evaluate

就像在Trainer中添加评估函数一样,在编写自己的训练循环时也需要这样做。但不是在每个epoch结束时计算和报告度量,这次您将使用add_batch累积所有批次并在最后计算度量

import evaluate

>>> metric = evaluate.load("accuracy")
>>> model.eval()
>>> for batch in eval_dataloader:
...     batch = {k: v.to(device) for k, v in batch.items()}
...     with torch.no_grad():
...         outputs = model(**batch)

...     logits = outputs.logits
...     predictions = torch.argmax(logits, dim=-1)
...     metric.add_batch(predictions=predictions, references=batch["labels"])

>>> metric.compute()

使用一个脚本训练

python examples/pytorch/summarization/run_summarization.py \
    --model_name_or_path t5-small \
    --do_train \
    --do_eval \
    --dataset_name cnn_dailymail \
    --dataset_config "3.0.0" \
    --source_prefix "summarize: " \
    --output_dir /tmp/tst-summarization \
    --per_device_train_batch_size=4 \
    --per_device_eval_batch_size=4 \
    --overwrite_output_dir \
    --predict_with_generate
class ModelArguments:
    """
    Arguments pertaining to which model/config/tokenizer we are going to fine-tune from.
    """

    model_name_or_path: str = field(
        metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}
    )
    config_name: Optional[str] = field(
        default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"}
    )
    tokenizer_name: Optional[str] = field(
        default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"}
    )
    cache_dir: Optional[str] = field(
        default=None,
        metadata={"help": "Where to store the pretrained models downloaded from huggingface.co"},
    )
    use_fast_tokenizer: bool = field(
        default=True,
        metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."},
    )
    model_revision: str = field(
        default="main",
        metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."},
    )
    token: str = field(
        default=None,
        metadata={
            "help": (
                "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token "
                "generated when running `huggingface-cli login` (stored in `~/.huggingface`)."
            )
        },
    )
    use_auth_token: bool = field(
        default=None,
        metadata={
            "help": "The `use_auth_token` argument is deprecated and will be removed in v4.34. Please use `token`."
        },
    )
    trust_remote_code: bool = field(
        default=False,
        metadata={
            "help": (
                "Whether or not to allow for custom models defined on the Hub in their own modeling files. This option"
                "should only be set to `True` for repositories you trust and in which you have read the code, as it will"
                "execute code present on the Hub on your local machine."
            )
        },
    )
    resize_position_embeddings: Optional[bool] = field(
        default=None,
        metadata={
            "help": (
                "Whether to automatically resize the position embeddings if `max_source_length` exceeds "
                "the model's position embeddings."
            )
        },
    )


@dataclass
class DataTrainingArguments:
    """
    Arguments pertaining to what data we are going to input our model for training and eval.
    """

    lang: Optional[str] = field(default=None, metadata={"help": "Language id for summarization."})

    dataset_name: Optional[str] = field(
        default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."}
    )
    dataset_config_name: Optional[str] = field(
        default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."}
    )
    text_column: Optional[str] = field(
        default=None,
        metadata={"help": "The name of the column in the datasets containing the full texts (for summarization)."},
    )
    summary_column: Optional[str] = field(
        default=None,
        metadata={"help": "The name of the column in the datasets containing the summaries (for summarization)."},
    )
    train_file: Optional[str] = field(
        default=None, metadata={"help": "The input training data file (a jsonlines or csv file)."}
    )
    validation_file: Optional[str] = field(
        default=None,
        metadata={
            "help": (
                "An optional input evaluation data file to evaluate the metrics (rouge) on (a jsonlines or csv file)."
            )
        },
    )
    test_file: Optional[str] = field(
        default=None,
        metadata={
            "help": "An optional input test data file to evaluate the metrics (rouge) on (a jsonlines or csv file)."
        },
    )
    overwrite_cache: bool = field(
        default=False, metadata={"help": "Overwrite the cached training and evaluation sets"}
    )
    preprocessing_num_workers: Optional[int] = field(
        default=None,
        metadata={"help": "The number of processes to use for the preprocessing."},
    )
    max_source_length: Optional[int] = field(
        default=1024,
        metadata={
            "help": (
                "The maximum total input sequence length after tokenization. Sequences longer "
                "than this will be truncated, sequences shorter will be padded."
            )
        },
    )
    max_target_length: Optional[int] = field(
        default=128,
        metadata={
            "help": (
                "The maximum total sequence length for target text after tokenization. Sequences longer "
                "than this will be truncated, sequences shorter will be padded."
            )
        },
    )
    val_max_target_length: Optional[int] = field(
        default=None,
        metadata={
            "help": (
                "The maximum total sequence length for validation target text after tokenization. Sequences longer "
                "than this will be truncated, sequences shorter will be padded. Will default to `max_target_length`."
                "This argument is also used to override the ``max_length`` param of ``model.generate``, which is used "
                "during ``evaluate`` and ``predict``."
            )
        },
    )
    pad_to_max_length: bool = field(
        default=False,
        metadata={
            "help": (
                "Whether to pad all samples to model maximum sentence length. "
                "If False, will pad the samples dynamically when batching to the maximum length in the batch. More "
                "efficient on GPU but very bad for TPU."
            )
        },
    )
    max_train_samples: Optional[int] = field(
        default=None,
        metadata={
            "help": (
                "For debugging purposes or quicker training, truncate the number of training examples to this "
                "value if set."
            )
        },
    )
    max_eval_samples: Optional[int] = field(
        default=None,
        metadata={
            "help": (
                "For debugging purposes or quicker training, truncate the number of evaluation examples to this "
                "value if set."
            )
        },
    )
    max_predict_samples: Optional[int] = field(
        default=None,
        metadata={
            "help": (
                "For debugging purposes or quicker training, truncate the number of prediction examples to this "
                "value if set."
            )
        },
    )
    num_beams: Optional[int] = field(
        default=None,
        metadata={
            "help": (
                "Number of beams to use for evaluation. This argument will be passed to ``model.generate``, "
                "which is used during ``evaluate`` and ``predict``."
            )
        },
    )
    ignore_pad_token_for_loss: bool = field(
        default=True,
        metadata={
            "help": "Whether to ignore the tokens corresponding to padded labels in the loss computation or not."
        },
    )
    source_prefix: Optional[str] = field(
        default="", metadata={"help": "A prefix to add before every source text (useful for T5 models)."}
    )

    forced_bos_token: Optional[str] = field(
        default=None,
        metadata={
            "help": (
                "The token to force as the first generated token after the decoder_start_token_id."
                "Useful for multilingual models like mBART where the first generated token"
                "needs to be the target language token (Usually it is the target language token)"
            )
        },
    )

分布式混合精度训练

python -m torch.distributed.launch \
    --nproc_per_node 8 pytorch/summarization/run_summarization.py \
    --fp16 \
    --model_name_or_path t5-small \
    --do_train \
    --do_eval \
    --dataset_name cnn_dailymail \
    --dataset_config "3.0.0" \
    --source_prefix "summarize: " \
    --output_dir /tmp/tst-summarization \
    --per_device_train_batch_size=4 \
    --per_device_eval_batch_size=4 \
    --overwrite_output_dir \
    --predict_with_generate

在TPU训练

python xla_spawn.py --num_cores 8 \
    summarization/run_summarization.py \
    --model_name_or_path t5-small \
    --do_train \
    --do_eval \
    --dataset_name cnn_dailymail \
    --dataset_config "3.0.0" \
    --source_prefix "summarize: " \
    --output_dir /tmp/tst-summarization \
    --per_device_train_batch_size=4 \
    --per_device_eval_batch_size=4 \
    --overwrite_output_dir \
    --predict_with_generate

PyTorch支持TPUs with the XLA 深度学习 compiler

tf:

python run_summarization.py  \
    --tpu name_of_tpu_resource \
    --model_name_or_path t5-small \
    --dataset_name cnn_dailymail \
    --dataset_config "3.0.0" \
    --output_dir /tmp/tst-summarization  \
    --per_device_train_batch_size 8 \
    --per_device_eval_batch_size 16 \
    --num_train_epochs 3 \
    --do_train \
    --do_eval

使用accelerate加速

Accelerate是一个仅支持PyTorch的库,它提供了一种统一的方法,用于在几种类型的设置(仅支持cpu,多个gpu, tpu)上训练模型,同时保持PyTorch训练循环的完全可见性。确保你已经安装了加速,如果你还没有它:

pip install git+https://github.com/huggingface/accelerate

您需要使用run_summarization_no_trainer.py脚本,而不是run_summarization_no_trainer.py脚本。加速支持的脚本将在文件夹中有一个task_no_trainer.py文件。运行如下命令创建并保存配置文件:

accelerate config

测试你的设置以确保它被正确配置:

accelerate test

现在您可以开始训练了:

accelerate launch run_summarization_no_trainer.py \
    --model_name_or_path t5-small \
    --dataset_name cnn_dailymail \
    --dataset_config "3.0.0" \
    --source_prefix "summarize: " \
    --output_dir ~/tmp/tst-summarization

使用自定义数据集

摘要脚本支持自定义数据集,只要它们是CSV或JSON行文件。当你使用自己的数据集时,你需要指定几个额外的参数:

Train_file和validation_file指定训练和验证文件的路径。
Text_column是要汇总的输入文本。
Summary_column是要输出的目标文本。

python examples/pytorch/summarization/run_summarization.py \
    --model_name_or_path t5-small \
    --do_train \
    --do_eval \
    --train_file path_to_csv_or_jsonlines_file \
    --validation_file path_to_csv_or_jsonlines_file \
    --text_column text_column_name \
    --summary_column summary_column_name \
    --source_prefix "summarize: " \
    --output_dir /tmp/tst-summarization \
    --overwrite_output_dir \
    --per_device_train_batch_size=4 \
    --per_device_eval_batch_size=4 \
    --predict_with_generate

使用Accelerate分布式训练

随着模型变得越来越大,并行性已经成为在有限硬件上训练更大模型并将训练速度提高几个数量级的一种策略。在hug Face,我们创建了Accelerate库,以帮助用户轻松地在任何类型的分布式设置上训练Transformers模型,无论是一台机器上的多个GPU还是跨几台机器的多个GPU。在本教程中,学习如何自定义本地PyTorch训练循环以启用分布式环境中的训练。

pip install accelerate

导入Accelerator,Accelerator将自动检测您的分布式设置类型,并初始化培训所需的所有组件。您不需要显式地将模型放置在设备上。

from accelerate import Accelerator

>>> accelerator = Accelerator()

准备 accelerate

下一步是将所有相关的训练对象传递给prepare方法。这包括您的训练和评估的dataloader,一个模型和一个优化器

train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(
     train_dataloader, eval_dataloader, model, optimizer
 )

反向传播

最后添加的是将训练循环中的典型loss.backward()替换为Accelerate的backwardmethod:

for epoch in range(num_epochs):
...     for batch in train_dataloader:
...         outputs = model(**batch)
...         loss = outputs.loss
...         accelerator.backward(loss)

...         optimizer.step()
...         lr_scheduler.step()
...         optimizer.zero_grad()
...         progress_bar.update(1)

正如您在下面的代码中看到的那样,您只需要在训练循环中添加四行代码就可以启用分布式训练!

from accelerate import Accelerator
1
    
accelerator = Accelerator()
2  
    
- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
- model.to(device)
+ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(
+     train_dataloader, eval_dataloader, model, optimizer
+ )
3

-         loss.backward()
+         accelerator.backward(loss)
4

训练脚本

如果您是从脚本运行训练,请运行以下命令创建并保存配置文件:

accelerate config

训练:

accelerate launch train.py

使用notebook训练

如果你打算使用collaboration的tpu, Accelerate也可以在笔记本电脑上运行。将所有负责训练的代码封装在一个函数中,并将其传递给notebook_launcher:

from accelerate import notebook_launcher

>>> notebook_launcher(training_function)

微调PEFT

参数有效微调(PEFT)方法在微调过程中冻结预训练的模型参数,并在其上添加少量可训练参数(适配器)。适配器经过训练以学习特定于任务的信息。这种方法已被证明具有非常高的内存效率和较低的计算使用量,同时产生与完全微调的模型相当的结果。
使用PEFT训练的适配器通常也比完整的模型小一个数量级,这使得共享、存储和加载它们更加方便

比如:存储在Hub上的OPTForCausalLM模型的适配器权重仅为6MB,而模型权重的完整大小可达700MB。

get start

pip install peft

如果你想尝试全新的功能,你可能会对从源代码安装库感兴趣:

pip install git+https://github.com/huggingface/peft.git

transformer原生支持一些PEFT方法,这意味着您可以加载存储在本地或Hub上的适配器权重,并通过几行代码轻松运行或训练它们。支持以下几种方法:

  • AdaLoRA
  • IA3
  • Low Rank Adapters

如果您想使用其他PEFT方法,例如快速学习或快速调优,或者关于PEFT库的一般信息,请参考文档。 documentation.

加载PEFT adapter

要从Transformers加载和使用PEFT适配器模型,请确保Hub存储库或本地目录包含adapter_config.Json文件和adaper的权重,。然后可以使用AutoModelFor Model 类型 类加载PEFT适配器模型。例如,要加载用于causal language的PEFT adapter模型:

  1. 确定PEFT 模型id
  2. 传它到AutoModelForCausalLM 类里面
from transformers import AutoModelForCausalLM, AutoTokenizer

peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(peft_model_id)

您可以使用AutoModelFor class或基本模型类(如OPTForCausalLM或LlamaForCausalLM)加载PEFT适配器。

你也可以通过调用load_adapter方法来加载PEFT适配器

from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "facebook/opt-350m"
peft_model_id = "ybelkada/opt-350m-lora"
#加载模型
model = AutoModelForCausalLM.from_pretrained(model_id)
#加载lora模型
model.load_adapter(peft_model_id)

使用8bit或者4bit

bitsandbytes集成支持8位和4位精度数据类型,这对于加载大型模型很有用,因为它可以节省内存(请参阅bitsandbytes集成指南以了解更多信息)。将load_in_8bit或load_in_4bit参数添加到from_pretrained()中,并设置device_map="auto"以有效地将模型分发到硬件:

from transformers import AutoModelForCausalLM, AutoTokenizer

peft_model_id = "ybelkada/opt-350m-lora"
model = AutoModelForCausalLM.from_pretrained(peft_model_id, device_map="auto", load_in_8bit=True)

添加新的adapter

您可以使用~peft.PeftModel。Add_adapter将新适配器添加到具有现有适配器的模型中,只要新适配器与当前适配器的类型相同。例如,如果您将现有的LoRA适配器附加到模型上:

from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import PeftConfig

model_id = "facebook/opt-350m"
model = AutoModelForCausalLM.from_pretrained(model_id)

lora_config = LoraConfig(
    target_modules=["q_proj", "k_proj"],
    init_lora_weights=False
)

model.add_adapter(lora_config, adapter_name="adapter_1")

添加一个新的adapter:

model.add_adapter(lora_config, adapter_name="adapter_2")

现在您可以使用~peft.PeftModel。Set_adapter设置使用哪个适配器:

# use adapter_1
model.set_adapter("adapter_1")
output = model.generate(**inputs)
print(tokenizer.decode(output_disabled[0], skip_special_tokens=True))

# use adapter_2
model.set_adapter("adapter_2")
output_enabled = model.generate(**inputs)
print(tokenizer.decode(output_enabled[0], skip_special_tokens=True))

启用或者禁用adapters

一旦将适配器添加到模型中,就可以启用或禁用适配器模块。启用适配器模块。

from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer
from peft import PeftConfig

model_id = "facebook/opt-350m"
adapter_model_id = "ybelkada/opt-350m-lora"
tokenizer = AutoTokenizer.from_pretrained(model_id)
text = "Hello"
inputs = tokenizer(text, return_tensors="pt")

model = AutoModelForCausalLM.from_pretrained(model_id)
peft_config = PeftConfig.from_pretrained(adapter_model_id)

# to initiate with random weights
peft_config.init_lora_weights = False

model.add_adapter(peft_config)
model.enable_adapters()
output = model.generate(**inputs)

禁用 adapter module:

model.disable_adapters()
output = model.generate(**inputs)

训练PEFT adapter

Trainer类支持PEFT适配器,因此您可以为您的特定用例训练适配器。它只需要再添加几行代码。例如,要训练LoRA适配器:

使用任务类型和超参数定义适配器配置(参见~peft)。有关超参数的更多详细信息)。

from peft import LoraConfig

peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.1,
    r=64,
    bias="none",
    task_type="CAUSAL_LM",
)

给模型添加adapter

model.add_adapter(peft_config)

将模型给到Trainer

trainer = Trainer(model=model, ...)
trainer.train()

保存模型

model.save_pretrained(save_dir)
model = AutoModelForCausalLM.from_pretrained(save_dir)

分享模型

使用transformer代理运行模型

使用 Large Language Models生成

llm或大型语言模型是文本生成背后的关键组件。简而言之,它们由大型预训练的转换器模型组成,这些模型被训练用来预测给定输入文本的下一个单词(或者更准确地说,是令牌)。由于它们一次预测一个标记,所以除了调用模型之外,您需要做一些更复杂的事情来生成新句子—您需要进行自回归生成。

自回归生成是在给定几个初始输入的情况下,用自己生成的输出迭代调用模型的推理时间过程。在Transformers中,这是由generate()方法处理的,该方法可用于所有具有生成功能的模型。

这个导航是教你如何

  • 使用LLM生成文本
  • 避免常见的陷阱
  • 接下来的步骤是帮助你充分利用你的LLM
pip install transformers bitsandbytes>=0.39.0 -q

文本生成

一个语言模型接受一系列文本token作为输入,并返回下一个token的概率分布。

使用llm进行自回归生成的一个关键方面是如何从这个概率分布中选择下一个token。只要您最终得到用于下一次迭代的token,这一步中就可以进行任何操作。这意味着它可以像从概率分布中选择最可能的token一样简单,也可以像在从结果分布中抽样之前应用十几个转换一样复杂。

上面描述的过程迭代重复,直到达到某个停止条件。理想情况下,停止条件由模型决定,模型应该学习何时输出序列结束(EOS)token。如果不是这种情况,则在达到某个预定义的最大长度时停止生成。

正确设置token选择步骤和停止条件对于使您的模型按照您的任务所期望的方式运行至关重要。这就是为什么我们有一个与每个模型相关联的GenerationConfig文件,它包含一个很好的默认生成参数化,并与您的模型一起加载。

如果您对基本的LLM用法感兴趣,我们的高级Pipeline接口是一个很好的起点。然而,llm通常需要高级功能,如量化和对令牌选择步骤的精细控制,这最好通过generate()来完成。使用llm的自回归生成也是资源密集型的,应该在GPU上执行以获得足够的吞吐量。

首先需要导入模型

from transformers import AutoModelForCausalLM

>>> model = AutoModelForCausalLM.from_pretrained(
...     "openlm-research/open_llama_7b", device_map="auto", load_in_4bit=True
... )

你会注意到from_pretrained调用中的两个标志:

  • device_map确保模型被移动到你的GPU(s)
  • load_in_4bit应用4位动态量化来大规模减少资源需求

还有其他方法可以初始化模型,但这是一个从LLM开始的良好基线。

下一步加载tokenizer:

from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("openlm-research/open_llama_7b")
>>> model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to("cuda")

model_inputs变量保存tokenized的文本输入,以及attention mask。虽然generate()在未传递attention mask时尽最大努力推断注意掩码,但我们建议尽可能传递它以获得最佳结果。
最后,调用generate()方法返回生成的token,这些token应该在打印之前转换为文本

generated_ids = model.generate(**model_inputs)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

就是这样!只需几行代码,您就可以利用LLM的强大功能。.

常见陷阱

有许多生成策略,有时默认值可能不适合您的用例。如果你的输出与你期望的不一致,我们已经列出了最常见的陷阱以及如何避免它们

from transformers import AutoModelForCausalLM, AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("openlm-research/open_llama_7b")
>>> tokenizer.pad_token = tokenizer.eos_token  # Llama has no pad token by default
>>> model = AutoModelForCausalLM.from_pretrained(
...     "openlm-research/open_llama_7b", device_map="auto", load_in_4bit=True
... )
生成的输出太长或者太短

如果没有在GenerationConfig文件中指定,则默认情况下generate最多返回20个令牌。我们强烈建议在生成调用中手动设置max_new_tokens,以控制它可以返回的新令牌的最大数量。请记住llm(更准确地说,只有解码器的模型)也将输入提示作为输出的一部分返回。

model_inputs = tokenizer(["A sequence of numbers: 1, 2"], return_tensors="pt").to("cuda")

>>> # By default, the output will contain up to 20 tokens
>>> generated_ids = model.generate(**model_inputs)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5'

>>> # Setting `max_new_tokens` allows you to control the maximum length
>>> generated_ids = model.generate(**model_inputs, max_new_tokens=50)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'
生成模式不正确,使用采样sample

默认情况下,除非在GenerationConfig文件中指定,否则generate会在每次迭代时选择最可能的令牌(贪婪解码)。根据你的任务,这可能是不可取的;像聊天机器人或写论文这样的创造性任务可以从抽样中受益。另一方面,音频转录或翻译等基于输入的任务则受益于贪婪解码。使用do_sample=True启用采样,您可以在这篇博客文章中了解更多有关此主题的信息。

# Set seed or reproducibility -- you don't need this unless you want full reproducibility
设置种子或可再现性——你不需要这个,除非你想要完全的可再现性
>>> from transformers import set_seed
>>> set_seed(0)

>>> model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to("cuda")
#LLM+贪婪解码 = 重复、枯燥的输出
>>> # LLM + greedy decoding = repetitive, boring output
>>> generated_ids = model.generate(**model_inputs)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'I am a cat. I am a cat. I am a cat. I am a cat'

#使用采样,输出变得更加有效
>>> # With sampling, the output becomes more creative!
>>> generated_ids = model.generate(**model_inputs, do_sample=True)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'I am a cat.\nI just need to be. I am always.\nEvery time'
填充错误

llm是只有解码器的架构,这意味着它们会继续迭代您的输入提示符。如果输入的长度不相同,则需要填充。由于llm没有被填充token训练,因此您的输入需要左填充。确保你也不要忘记传递注意力掩码来生成!

# 上面初始化的分词器默认具有激活的右padding:
The tokenizer initialized above has right-padding active by default: the 1st sequence,
它更短,右侧有填充。生成失败
>>> # which is shorter, has padding on the right side. Generation fails.
>>> model_inputs = tokenizer(
...     ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
... ).to("cuda")
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids[0], skip_special_tokens=True)[0]
''

# 使用左填充, it works as expected!
tokenizer = AutoTokenizer.from_pretrained("openlm-research/open_llama_7b", padding_side="left")
tokenizer.pad_token = tokenizer.eos_token  # Llama has no pad token by default
model_inputs = tokenizer(
    ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to("cuda")
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 3, 4, 5, 6,'

其他资源

虽然自回归生成过程相对简单,但充分利用LLM可能是一项具有挑战性的努力,因为有许多活动部分。

下面帮你更近一步了解LLM的使用和理解。

高级生成用法
  • 指导如何控制不同的生成方法,如何设置生成配置文件,以及如何流式输出;Guide
  • 关于GenerationConfig、generate()和generate相关类的API引用。GenerationConfig, generate(), generate-related classes
LLM排行榜

开源的的LLM排行榜(Open LLM Leaderboard),关注开源模型的质量;Open LLM Leaderboard

开源的LLM- perf排行榜,专注于LLM吞吐量Open LLM-Perf Leaderboard

延迟和吞吐量

动态量化指南,向您展示了如何大幅降低内存需求Guide

相关库

文本生成-推理,用于LLM的生产就绪服务器;text-generation-inference

优化,transformers的扩展,优化特定的硬件设备。optimum

任务指南

分为自然语言、语音、视觉、多模态、生成式。

自然语言处理

文本分类

文本分类是一种常见的NLP任务,它为文本分配标签或类。最流行的文本分类形式之一是情感分析,它为文本序列分配一个标签,如积极、消极或中立。

本指南告诉你

  • 在IMDb数据集上,Finetune DistilBERT 来确定电影评论是正面还是负面。

  • 使用你的finetune模型进行推理

本教程中演示的任务由以下模型体系结构支持:
    ALBERT, BART, BERT, BigBird, BigBird-Pegasus, BioGpt, BLOOM, CamemBERT, CANINE, CodeLlama, ConvBERT, CTRL, Data2VecText, DeBERTa, DeBERTa-v2, DistilBERT, ELECTRA, ERNIE, ErnieM, ESM, Falcon, FlauBERT, FNet, Funnel Transformer, GPT-Sw3, OpenAI GPT-2, GPTBigCode, GPT Neo, GPT NeoX, GPT-J, I-BERT, LayoutLM, LayoutLMv2, LayoutLMv3, LED, LiLT, LLaMA, Longformer, LUKE, MarkupLM, mBART, MEGA, Megatron-BERT, MobileBERT, MPNet, MPT, MRA, MT5, MVP, Nezha, Nyströmformer, OpenLlama, OpenAI GPT, OPT, Perceiver, PLBart, QDQBert, Reformer, RemBERT, RoBERTa, RoBERTa-PreLayerNorm, RoCBert, RoFormer, SqueezeBERT, T5, TAPAS, Transformer-XL, UMT5, XLM, XLM-RoBERTa, XLM-RoBERTa-XL, XLNet, X-MOD, YOSO

在开始之前,保证装了以下的库:

pip install transformers datasets evaluate

我们鼓励你登录你的“hugging face”账户,这样你就可以在社区上传和分享你的模型。当出现提示时,输入您的令牌登录:

from huggingface_hub import notebook_login

>>> notebook_login()
Load IMDb dataset

下载IMDB数据集,通过DATASETS库:

from datasets import load_dataset

>>> imdb = load_dataset("imdb")

第一个例子:

imdb["test"][0]
{
    "label": 0,
    "text": "I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded, under-appreciated and misunderstood. I tried to like this, I really did, but it is to good TV sci-fi as Babylon 5 is to Star Trek (the original). Silly prosthetics, cheap cardboard sets, stilted dialogues, CG that doesn't match the background, and painfully one-dimensional characters cannot be overcome with a 'sci-fi' setting. (I'm sure there are those of you out there who think Babylon 5 is good sci-fi TV. It's not. It's clichéd and uninspiring.) While US viewers might like emotion and character development, sci-fi is a genre that does not take itself seriously (cf. Star Trek). It may treat important issues, yet not as a serious philosophy. It's really difficult to care about the characters here as they are not simply foolish, just missing a spark of life. Their actions and reactions are wooden and predictable, often painful to watch. The makers of Earth KNOW it's rubbish as they have to always say \"Gene Roddenberry's Earth...\" otherwise people would not continue watching. Roddenberry's ashes must be turning in their orbit as this dull, cheap, poorly edited (watching it without advert breaks really brings this home) trudging Trabant of a show lumbers into space. Spoiler. So, kill off a main character. And then bring him back as another actor. Jeeez! Dallas all over again.",
}
  • text:文本
  • label:0负面1证明
处理数据和训练数据

下一步是加载DistilBERT的tokenizer去预处理text字段:

from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

写一个前处理的函数,tokenize 文本,截取序列的长度,不能超过最大的input长度:

def preprocess_function(examples):
...     return tokenizer(examples["text"], truncation=True)

使用datasets中的map函数,将数据集转换为token,使用batched=True来一次处理多个数据来进行加速。

tokenized_imdb = imdb.map(preprocess_function, batched=True)

现在使用DataCollatorWithPadding创建一批示例。在Collator过程中,动态地将句子填充到批处理中最长的长度,而不是将整个数据集填充到最大长度,这更有效。

from transformers import DataCollatorWithPadding

#torch
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

#tensorflow
data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")

在训练期间包含一个度量通常有助于评估模型的性能。您可以使用Evaluate库快速加载求值方法。对于此任务,加载精度度量(请参阅Evaluate 快速指南,了解有关如何加载和计算度量的更多信息):

import evaluate

>>> accuracy = evaluate.load("accuracy")

然后创建一个函数,传递你的预测和标签来计算精度:

import numpy as np


>>> def compute_metrics(eval_pred):
...     predictions, labels = eval_pred
...     predictions = np.argmax(predictions, axis=1)
...     return accuracy.compute(predictions=predictions, references=labels)

您的compute_metrics函数现在已经准备好了,当您设置训练时,您将返回到它。

在你开始训练你的模型之前,用id2label和label2id创建一个预期id到它们标签的映射:

id2label = {0: "NEGATIVE", 1: "POSITIVE"}
>>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}

现在您可以开始训练您的模型了!使用automodelforsequencecclassification加载DistilBERT,同时加载期望的标签数量和标签映射:

from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer

>>> model = AutoModelForSequenceClassification.from_pretrained(
...     "distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
... )

到目前为止,目前只剩下三个步骤:

第一步:定义训练的超参数TrainingArguments,指定output_dir指定哪里可以保存我们的模型,也可以上传到huggingface的hub,使用push_to_hub=True,在每个epoch结束,都会验证精度和保存模型。

第二步:将训练的参数传递给Trainer,包括model,dataset,tokenizer,data collator和compute_metrics函数。

第三步:调用trian()去微调模型。

traing_args = TrainingArguments(
output_dir = "my_awesome_model",
    learning_rate= 2e-5,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    num_train_epoch=2,
    weight_decay=0.01,
    evaluation_strategy='epoch',
    save_strategy="epoch",
    load_best_model_at_end=True,
    push_to_hub=True,
)

trainer = Trainer(
	model=model,
    args = training_args,
    train_dataset=tokenized_imdb["train"],
    eval_dataset=tokenized_imdb["test"],
    tokenizer=tokenizer,
    data_collator=data_collator,
    compute_metrics=compute_metrics,
)
trainer.train()
#默认情况下,当您向训练器传递tokenizer时,训练器将应用动态填充。在这种情况下,不需要显式data collator。

一旦训练完成,使用push_to_hub()方法将你的模型分享给Hub,这样每个人都可以使用你的模型:

trainer.push_to_hub()
tensorflow处理和训练

pass

推理

微调结束后,可以使用它进行推理:

text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."

在pipeline()中使用您调优的模型来进行推理,最简单的方法是使用它。用你的模型实例化一个情感分析的管道,并将你的文本传递给它:

classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model")
classifier(text)
[{'label': 'POSITIVE', 'score': 0.9994940757751465}]

也可以不使用pipeline,

from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
>>> inputs = tokenizer(text, return_tensors="pt")
model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
with torch.no_grad():
    logits = model(**inputs).logits
    predicted_class_id = logits.argmax().item()
model.config.id2label[predicted_class_id]
'POSITIVE'
tensorflow 推理

pass

词语分类

标记分类为句子中的单个token分配一个标签。最常见的token分类任务之一是命名实体识别(NER)。NER试图为句子中的每个实体(如人、位置或组织)找到一个标签。

本指南会教你:

  1. 使用DistilBERT微调WNUT17数据集,检测entites;
  2. 推理

可以使用以下的模型:

ALBERT, BERT, BigBird, BioGpt, BLOOM, CamemBERT, CANINE, ConvBERT, Data2VecText, DeBERTa, DeBERTa-v2, DistilBERT, ELECTRA, ERNIE, ErnieM, ESM, Falcon, FlauBERT, FNet, Funnel Transformer, GPT-Sw3, OpenAI GPT-2, GPTBigCode, GPT Neo, GPT NeoX, I-BERT, LayoutLM, LayoutLMv2, LayoutLMv3, LiLT, Longformer, LUKE, MarkupLM, MEGA, Megatron-BERT, MobileBERT, MPNet, MPT, MRA, Nezha, Nyströmformer, QDQBert, RemBERT, RoBERTa, RoBERTa-PreLayerNorm, RoCBert, RoFormer, SqueezeBERT, XLM, XLM-RoBERTa, XLM-RoBERTa-XL, XLNet, X-MOD, YOSO

首先安装库:

pip install transformers datasets evaluate seqeval
加载WNUT 17 数据集
from datasets import load_dataset

>>> wnut = load_dataset("wnut_17")

wnut["train"][0]
{'id': '0',
 'ner_tags': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0],
 'tokens': ['@paulwalk', 'It', "'s", 'the', 'view', 'from', 'where', 'I', "'m", 'living', 'for', 'two', 'weeks', '.', 'Empire', 'State', 'Building', '=', 'ESB', '.', 'Pretty', 'bad', 'storm', 'here', 'last', 'evening', '.']
}

ner_tags中的每个数字代表一个实体。将数字转换为它们的标签名称以找出entity是什么:

label_list = wnut["train"].features[f"ner_tags"].feature.names
>>> label_list
[
    "O",
    "B-corporation",
    "I-corporation",
    "B-creative-work",
    "I-creative-work",
    "B-group",
    "I-group",
    "B-location",
    "I-location",
    "B-person",
    "I-person",
    "B-product",
    "I-product",
]

每个ner_tag前缀的字母表示实体的标记位置:

  • B-表示entity的开始。
  • I-表示token包含在同一entity中(例如,State的token是Empire State Building等实体的一部分)。
  • 0表示该token不对应任何entity。

下一步是加载一个DistilBERT tokenizer来预处理token字段:

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

正如您在上面的示例标记字段中看到的那样,看起来输入已经被标记化了。但是输入实际上还没有被标记,您需要设置is_split_into_words=True来将单词标记为子单词。例如:

文本生成

文本生成策略

文本生成对于许多NLP任务至关重要,例如开放式文本生成、摘要、翻译等。它还在各种混合模态应用程序中发挥作用,这些应用程序将文本作为输出,如语音到文本和视觉到文本。一些可以生成文本的模型包括GPT2、XLNet、OpenAI GPT、CTRL、TransformerXL、XLM、Bart、T5、GIT、Whisper。

下面是一些使用generate()方法为不同任务生成文本输出的例子:

  • Text summarization文本摘要
  • Image captioning图片说明文字
  • Audio transcription听写记录

注意,generate方法的输入依赖于模型的modality。它们由模型的前处理类返回,例如AutoTokenizer或AutoProcessor。如果模型的前处理器创建了不止一种输入,则将所有输入传递给generate()。您可以在相应的模型文档中了解有关单个模型前处理类的更多信息。

选择输出标记以生成文本的过程称为解码,您可以定制generate()方法将使用的解码策略。修改解码策略(参数)不会改变任何可训练参数的值。但是,它会对生成的输出的质量产生明显的影响。它可以帮助减少文本中的重复,使其更加连贯。(参数包括,是否采样sample,文本的最大长度的输出)

本教程包括:

  • 默认的文本生成 的config
  • 常用的解码策略和他们的超参数
  • 在Hub上保存和共享自定义生成配置与您的微调模型
默认的文本生成配置

在模型的生成的config中定义模型的解码策略。在pipline()中使用预训练模型进行推理时,模型调用PreTrainedModel.generate()方法,该方法在底层应用默认的生成配置。当模型中没有保存任何自定义配置时,也会使用默认配置。

当你显式加载一个模型时,你可以通过model.generation_config检查它附带的生成配置:

from transformers import AutoModelForCausalLM

>>> model = AutoModelForCausalLM.from_pretrained("distilgpt2")
>>> model.generation_config
GenerationConfig {
    "_from_model_config": true,
    "bos_token_id": 50256,
    "eos_token_id": 50256,
    "transformers_version": "4.26.0.dev0"
}

打印出模型的Generation_config,config只显示与默认生成配置不同的值,而不列出任何默认值。

  • 默认的生成配置将输出与输入提示符的组合大小限制为最多20个令牌,以避免遇到资源限制。
  • 默认的解码策略是贪婪搜索,这是最简单的解码策略,它选择一个概率最高的令牌作为下一个令牌。对于许多任务和较小的输出大小,这很有效。然而,当用于生成更长的输出时,贪婪搜索可能开始产生高度重复的结果。
自定义文本生成

你可以通过将参数和它们的值直接传递给generate方法来覆盖任何generation_config:

my_model.generate(**inputs, num_beams=4, do_sample=True)

即使默认的解码策略主要适用于您的任务,您仍然可以调整一些东西。一些常用的调整参数包括:

  • Max_new_tokens:要生成的最大token数。换句话说,输出序列的大小,不包括提示中的标记。

  • Num_beams:通过指定高于1的beam数量,可以有效地从贪婪搜索切换到波束搜索。该策略在每个时间步评估几个假设,并最终选择对整个序列具有总体最高概率的假设。这具有识别高概率序列的优势,这些序列以较低概率的初始标记开始,会被贪婪搜索忽略。如果是1则是贪婪搜索

  • do_sample:如果设置为True,则启用多项采样、图搜索多项采样、Top-K采样和Top-p采样等解码策略。所有这些策略都通过各种特定的策略调整,从整个词汇表的概率分布中选择下一个token。

  • Num_return_sequences:每个输入返回的候选序列的数量。此选项仅适用于支持多个候选序列的解码策略,例如波束搜索(通过扩展有限集中最有前途的节点来探索图形,类似于图算法的bfs)和采样的变化。或者像贪婪搜索和对比搜索这样的解码策略返回单个输出序列。

关于beams搜索(波束搜索)的解答https://zhuanlan.zhihu.com/p/82829880

用你的模型保存一个自定义的解码器策略

如果您想分享您的微调模型的配置文件,您可以:

  • 创建一个GenerationConfig类实例
  • 指定解码策略参数
  • 使用GenerationConfig.save_pretrained()保存生成配置,确保其config_file_name参数为空
  • 将push_to_hub设置为True,将配置上传到模型的repo
from transformers import AutoModelForCausalLM, GenerationConfig

>>> model = AutoModelForCausalLM.from_pretrained("my_account/my_model")
>>> generation_config = GenerationConfig(
...     max_new_tokens=50, do_sample=True, top_k=50, eos_token_id=model.config.eos_token_id
... )
>>> generation_config.save_pretrained("my_account/my_model", push_to_hub=True)

您还可以使用GenerationConfig.save_pretrained()中的config_file_name参数在单个目录中存储多个生成配置。稍后可以使用GenerationConfig.from_pretrained()实例化它们。如果你想为单个模型存储多个生成配置(例如,一个用于带有采样的创造性文本生成,一个用于带有光束搜索的摘要),这是很有用的。您必须具有向模型添加配置文件的Hub权限。

from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, GenerationConfig

>>> tokenizer = AutoTokenizer.from_pretrained("t5-small")
>>> model = AutoModelForSeq2SeqLM.from_pretrained("t5-small")

>>> translation_generation_config = GenerationConfig(
...     num_beams=4,
...     early_stopping=True,
...     decoder_start_token_id=0,
...     eos_token_id=model.config.eos_token_id,
...     pad_token=model.config.pad_token_id,
... )

>>> # Tip: add `push_to_hub=True` to push to the Hub
>>> translation_generation_config.save_pretrained("/tmp", "translation_generation_config.json")

然后,您可以使用命名的生成配置文件来参数化生成
>>> # You could then use the named generation config file to parameterize generation
>>> generation_config = GenerationConfig.from_pretrained("/tmp", "translation_generation_config.json")
>>> inputs = tokenizer("translate English to French: Configuration files are easy to use!", return_tensors="pt")
>>> outputs = model.generate(**inputs, generation_config=generation_config)
>>> print(tokenizer.batch_decode(outputs, skip_special_tokens=True))
['Les fichiers de configuration sont faciles à utiliser!']
流式

generate()支持流式,通过streamer流式输入,streamer的输入和特定的实例类兼容,只要这个类包含put()和end()方法,put()用来上传新的tokens,end()方法是生成文本的结束标志。

streamer类还在开发中,可能会更改。

在实际中,你可以设计自己的流类用于各种目的,我们也有基础的流类给你使用,比如TextStreamer类,流式输出generate()的返回数据在屏幕上,一个时间一个单词。

from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer

>>> tok = AutoTokenizer.from_pretrained("gpt2")
>>> model = AutoModelForCausalLM.from_pretrained("gpt2")
>>> inputs = tok(["An increasing sequence: one,"], return_tensors="pt")
>>> streamer = TextStreamer(tok)

>>> # Despite returning the usual output, the streamer will also print the generated text to stdout.
>>> _ = model.generate(**inputs, streamer=streamer, max_new_tokens=20)
An increasing sequence: one, two, three, four, five, six, seven, eight, nine, ten, eleven,
解码器的策略

可以使用generate()参数和generation_config的某些组合来启用特定的解码策略。如果你是这个概念的新手,我们建议你阅读这篇博客文章,它说明了常见的解码策略是如何工作的。this blog post that illustrates how common decoding strategies work.

在这里,我们将展示控制解码策略的一些参数,并说明如何使用它们。

贪婪搜索

默认情况下,Generate使用贪婪搜索解码,因此您不必传递任何参数来启用它。这意味着参数num_beams被设置为1,do_sample=False。

from transformers import AutoModelForCausalLM, AutoTokenizer

>>> prompt = "I look forward to"
>>> checkpoint = "distilgpt2"

>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
>>> outputs = model.generate(**inputs)
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
['I look forward to seeing you all again!\n\n\n\n\n\n\n\n\n\n\n']
对比搜索Contrastive search

对比搜索解码策略在2022年的论文A contrast Framework for Neural Text Generation中提出。它证明了产生非重复但连贯的长输出的优越结果。要了解对比搜索是如何工作的,请查看这篇博文。启用和控制对比搜索行为的两个主要参数是penalty_alpha和top_k:

from transformers import AutoTokenizer, AutoModelForCausalLM

>>> checkpoint = "gpt2-large"
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)

>>> prompt = "Hugging Face Company is"
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> outputs = model.generate(**inputs, penalty_alpha=0.6, top_k=4, max_new_tokens=100)
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
['Hugging Face Company is a family owned and operated business. We pride ourselves on being the best
in the business and our customer service is second to none.\n\nIf you have any questions about our
products or services, feel free to contact us at any time. We look forward to hearing from you!']
多项式采样Multinomial sampling

与贪婪搜索总是选择概率最高的标记作为下一个标记相反,多项抽样(也称为祖先抽样)根据模型给出的整个词汇表的概率分布随机选择下一个标记。每个非零概率的令牌都有被选中的机会,从而减少了重复的风险。

To enable multinomial sampling set do_sample=True and num_beams=1.

from transformers import AutoTokenizer, AutoModelForCausalLM, set_seed
>>> set_seed(0)  # For reproducibility

>>> checkpoint = "gpt2-large"
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)

>>> prompt = "Today was an amazing day because"
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> outputs = model.generate(**inputs, do_sample=True, num_beams=1, max_new_tokens=100)
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
['Today was an amazing day because when you go to the World Cup and you don\'t, or when you don\'t get invited,
that\'s a terrible feeling."']
定向搜索解码Beam-search decoding

与贪婪搜索不同,波束搜索解码在每个时间步保留多个假设,并最终选择整个序列总体概率最高的假设。这样做的好处是可以识别高概率序列,这些序列以较低概率的初始标记开始,可能会被贪婪搜索忽略。要启用这种解码策略,请指定大于1的num_beams(也就是要跟踪的假设数)

from transformers import AutoModelForCausalLM, AutoTokenizer

>>> prompt = "It is astonishing how one can"
>>> checkpoint = "gpt2-medium"

>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)

>>> outputs = model.generate(**inputs, num_beams=5, max_new_tokens=50)
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
['It is astonishing how one can have such a profound impact on the lives of so many people in such a short period of
time."\n\nHe added: "I am very proud of the work I have been able to do in the last few years.\n\n"I have']
波束搜索多项采样Beam-search multinomial sampling

顾名思义,这种解码策略结合了波束搜索和多项采样。您需要指定num_beams大于1,并设置do_sample=True以使用这种解码策略

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, set_seed
>>> set_seed(0)  # For reproducibility

>>> prompt = "translate English to German: The house is wonderful."
>>> checkpoint = "t5-small"

>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint)

>>> outputs = model.generate(**inputs, num_beams=5, do_sample=True)
>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
'Das Haus ist wunderbar.'
多波束搜索解码Diverse beam search decoding

多样化波束搜索解码策略是波束搜索策略的扩展,它允许生成更多样化的波束序列集供选择。要了解它是如何工作的,请参阅异波束搜索:从神经序列模型解码不同的解决方案。这种方法有三个主要参数:num_beams、num_beam_groups和diversity_penalty。分集损失确保了不同组的输出是不同的,并且在每个组内使用波束搜索。

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

>>> checkpoint = "google/pegasus-xsum"
>>> prompt = (
...     "The Permaculture Design Principles are a set of universal design principles "
...     "that can be applied to any location, climate and culture, and they allow us to design "
...     "the most efficient and sustainable human habitation and food production systems. "
...     "Permaculture is a design system that encompasses a wide variety of disciplines, such "
...     "as ecology, landscape design, environmental science and energy conservation, and the "
...     "Permaculture design principles are drawn from these various disciplines. Each individual "
...     "design principle itself embodies a complete conceptual framework based on sound "
...     "scientific principles. When we bring all these separate  principles together, we can "
...     "create a design system that both looks at whole systems, the parts that these systems "
...     "consist of, and how those parts interact with each other to create a complex, dynamic, "
...     "living system. Each design principle serves as a tool that allows us to integrate all "
...     "the separate parts of a design, referred to as elements, into a functional, synergistic, "
...     "whole system, where the elements harmoniously interact and work together in the most "
...     "efficient way possible."
... )

>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint)

>>> outputs = model.generate(**inputs, num_beams=5, num_beam_groups=5, max_new_tokens=30, diversity_penalty=1.0)
>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
'The Design Principles are a set of universal design principles that can be applied to any location, climate and
culture, and they allow us to design the'

本指南说明了启用各种解码策略的主要参数。为生成方法提供了更高级的参数,这使您可以进一步控制生成方法的行为。有关可用参数的完整列表,请参阅API文档。

API documentation.

协助解码Assisted Decoding

辅助解码是对上述解码策略的修改,它使用具有相同标记器(理想情况下是一个小得多的模型)的辅助模型来贪婪地生成一些候选标记。然后,主模型在单个向前传递中验证候选令牌,这加快了解码过程。目前,辅助解码只支持贪婪搜索和采样,不支持批量输入。要了解更多关于辅助解码的知识,请查看这篇博客文章。

要启用辅助解码,请使用模型设置assistant_model参数。

from transformers import AutoModelForCausalLM, AutoTokenizer

>>> prompt = "Alice and Bob"
>>> checkpoint = "EleutherAI/pythia-1.4b-deduped"
>>> assistant_checkpoint = "EleutherAI/pythia-160m-deduped"

>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
>>> outputs = model.generate(**inputs, assistant_model=assistant_model)
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
['Alice and Bob are sitting in a bar. Alice is drinking a beer and Bob is drinking a']

当使用辅助解码与采样方法时,您可以使用温度参数来控制随机性,就像在多项采样中一样。然而,在辅助解码中,降低温度将有助于改善延迟。

from transformers import AutoModelForCausalLM, AutoTokenizer, set_seed
>>> set_seed(42)  # For reproducibility

>>> prompt = "Alice and Bob"
>>> checkpoint = "EleutherAI/pythia-1.4b-deduped"
>>> assistant_checkpoint = "EleutherAI/pythia-160m-deduped"

>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
>>> inputs = tokenizer(prompt, return_tensors="pt")

>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
>>> outputs = model.generate(**inputs, assistant_model=assistant_model, do_sample=True, temperature=0.5)
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
['Alice and Bob are going to the same party. It is a small party, in a small']

开发指南

从Tokenizers引用tokenizers

PreTrainedTokenizerFast依赖于Tokenizers库。从tokenizers库获得的token可以非常简单地加载到Transformers中。

在进入细节之前,让我们先用几行创建一个虚拟的tokenizer:

from tokenizers import Tokenizer
>>> from tokenizers.models import BPE
>>> from tokenizers.trainers import BpeTrainer
>>> from tokenizers.pre_tokenizers import Whitespace

>>> tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
>>> trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])

>>> tokenizer.pre_tokenizer = Whitespace()
>>> files = [...]
>>> tokenizer.train(files, trainer)

现在我们有了一个对我们定义的文件进行训练的Tokenizer。我们可以在该运行时中继续使用它,也可以将其保存到JSON文件中以备将来重用。

直接从tokenizer对象中加载

让我们看看如何在Transformers库中利用这个tokenizer对象。PreTrainedTokenizerFast类允许简单的实例化,通过接受实例化的标记器对象作为参数:

from transformers import PreTrainedTokenizerFast

>>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer)

这个对象现在可以与Transformers标记器共享的所有方法一起使用!

Loading from a JSON file

为了从JSON文件加载标记器,让我们首先保存我们的标记器:

tokenizer.save("tokenizer.json")

我们保存该文件的路径可以通过tokenizer_file参数传递给PreTrainedTokenizerFast初始化方法:

from transformers import PreTrainedTokenizerFast

>>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_file="tokenizer.json")

这个对象现在可以与Transformers标记器共享的所有方法一起使用!转到标记器页面以获取更多信息。 the tokenizer page

你可能感兴趣的:(语言模型,深度学习,人工智能,pytorch)