Transformers 4.37 中文文档(二)(3)

简介: Transformers 4.37 中文文档(二)

Transformers 4.37 中文文档(二)(2)https://developer.aliyun.com/article/1563282


基于聊天的执行(chat)

代理还采用了基于聊天的方法,使用 chat()方法:

agent.chat("Generate a picture of rivers and lakes")

agent.chat("Transform the picture so that there is a rock in there")

当您想要跨指令保持状态时,这是一种有趣的方法。这对于实验很有帮助,但往往更擅长单个指令,而不是复杂指令(run()方法更擅长处理)。

如果您想传递非文本类型或特定提示,这种方法也可以接受参数。

⚠️ 远程执行

出于演示目的,以便可以与所有设置一起使用,我们已经为代理可以访问的默认工具的几个远程执行器创建了。这些是使用inference endpoints创建的。

我们现在已经关闭了这些,但为了看到如何设置远程执行工具,我们建议阅读自定义工具指南。

这里发生了什么?什么是工具,什么是代理?

代理

这里的“代理”是一个大型语言模型,我们正在提示它,以便它可以访问特定的一组工具。

LLMs 在生成小样本代码方面表现得相当不错,因此这个 API 利用 LLM 的这一特点,通过提示 LLM  给出执行任务的一组工具的小样本代码。然后,您给代理的任务和您给它的工具描述完成这个提示。这样它就可以访问您正在使用的工具的文档,特别是它们的预期输入和输出,并生成相关的代码。

工具

工具非常简单:它们是一个函数,带有名称和描述。然后我们使用这些工具的描述来提示代理。通过提示,我们向代理展示如何利用工具执行查询中请求的任务。

这里使用全新的工具而不是流水线,因为代理使用非常原子化的工具编写更好的代码。流水线更加重构,通常将多个任务合并为一个。工具旨在专注于一个非常简单的任务。

代码执行?!

然后,这段代码将在我们的小型 Python 解释器上执行,同时传递您的工具和输入集。我们听到您在后面尖叫“任意代码执行!”,但让我们解释为什么情况并非如此。

只能调用您提供的工具和打印函数,因此可以执行的内容已经受到限制。如果限制在 Hugging Face 工具上,那么您应该是安全的。

然后,我们不允许任何属性查找或导入(对于传递输入/输出到一小组函数来说,这些都不应该是必要的),因此所有最明显的攻击(无论如何,您需要提示  LLM 输出它们)都不应该是问题。如果您想更加安全,可以执行带有额外参数 return_code=True 的  run()方法,这样代理将只返回要执行的代码,您可以决定是否执行。

如果尝试执行非法操作或代码生成的 Python 错误时,执行将停止。

精心挑选的工具

我们确定了一组可以增强这些代理的工具。以下是我们在transformers中集成的工具的更新列表:

  • 文档问答:给定一个文档(如 PDF)的图像格式,回答关于该文档的问题(Donut)
  • 文本问答:给定一段长文本和一个问题,在文本中回答问题(Flan-T5)
  • 无条件图像字幕:给图像加上字幕!(BLIP)
  • 图像问答:给定一幅图像,在这幅图像上回答一个问题(VILT)
  • 图像分割:给定一幅图像和一个提示,输出该提示的分割蒙版(CLIPSeg)
  • 语音转文本:给定一个人说话的音频录音,将语音转录为文本(Whisper)
  • 文本转语音:将文本转换为语音(SpeechT5)
  • 零样本文本分类:给定一个文本和一个标签列表,确定文本对应于哪个标签最多(BART)
  • 文本摘要:将长文本总结为一句或几句话(BART)
  • 翻译:将文本翻译成指定语言(NLLB)

这些工具已经在 transformers 中集成,也可以手动使用,例如:

from transformers import load_tool
tool = load_tool("text-to-speech")
audio = tool("This is a text to speech tool")

自定义工具

虽然我们确定了一组精心挑选的工具,但我们坚信这个实现提供的主要价值是快速创建和共享自定义工具的能力。

通过将工具的代码推送到 Hugging Face Space 或模型存储库,您就能直接利用代理。我们已经向huggingface-tools组织添加了一些transformers-agnostic工具:

  • 文本下载器:从网址下载文本
  • 文本转图像:根据提示生成一幅图像,利用稳定的扩散
  • 图像转换:根据初始图像和提示修改图像,利用指导 pix2pix 稳定扩散
  • 文本到视频:根据提示生成一个小视频,利用 damo-vilab

我们从一开始就在使用的文本到图像工具是一个远程工具,位于huggingface-tools/text-to-image!我们将继续在这个和其他组织上发布这样的工具,以进一步增强这个实现。

默认情况下,代理可以访问位于huggingface-tools上的工具。我们将解释如何编写和共享您的工具,以及如何利用存储在 Hub 上的任何自定义工具的以下指南。

代码生成

到目前为止,我们已经展示了如何使用代理来为您执行操作。然而,代理只是生成代码,然后我们使用一个非常受限的 Python 解释器来执行。如果您想在不同的环境中使用生成的代码,可以提示代理返回代码,以及工具定义和准确的导入。

例如,以下指令

agent.run("Draw me a picture of rivers and lakes", return_code=True)

返回以下代码

from transformers import load_tool
image_generator = load_tool("huggingface-tools/text-to-image")
image = image_generator(prompt="rivers and lakes")

然后您可以修改并自行执行。

LLMs 的生成

原始文本:huggingface.co/docs/transformers/v4.37.2/en/llm_tutorial

LLMs,或大型语言模型,是文本生成背后的关键组件。简而言之,它们由大型预训练的变压器模型组成,训练用于预测给定一些输入文本的下一个单词(或更准确地说,令牌)。由于它们一次预测一个令牌,因此您需要做一些更复杂的事情来生成新的句子,而不仅仅是调用模型  - 您需要进行自回归生成。

自回归生成是在推理时迭代调用模型以生成输出的过程,给定一些初始输入。在🤗 Transformers 中,这由 generate()方法处理,适用于所有具有生成能力的模型。

本教程将向您展示如何:

  • 使用 LLM 生成文本
  • 避免常见陷阱
  • 帮助您充分利用 LLM 的下一步

在开始之前,请确保您已安装所有必要的库:

pip install transformers bitsandbytes>=0.39.0 -q

生成文本

进行因果语言建模训练的语言模型将文本令牌序列作为输入,并返回下一个令牌的概率分布。

https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/assisted-generation/gif_1_1080p.mov

“LLM 的前向传递”

LLMs 进行自回归生成的一个关键方面是如何从这个概率分布中选择下一个令牌。在这一步中可以采取任何方法,只要最终得到下一次迭代的令牌即可。这意味着它可以简单地从概率分布中选择最可能的令牌,也可以在从结果分布中抽样之前应用十几种转换。

https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/assisted-generation/gif_2_1080p.mov

“自回归生成通过从概率分布中迭代选择下一个令牌来生成文本”

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

正确设置令牌选择步骤和停止条件对于使您的模型在任务上表现如您期望的方式至关重要。这就是为什么我们为每个模型关联一个 GenerationConfig 文件,其中包含一个良好的默认生成参数设置,并且与您的模型一起加载。

让我们谈谈代码!

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

首先,您需要加载模型。

>>> from transformers import AutoModelForCausalLM
>>> model = AutoModelForCausalLM.from_pretrained(
...     "mistralai/Mistral-7B-v0.1", device_map="auto", load_in_4bit=True
... )

您会注意到from_pretrained调用中有两个标志:

  • device_map确保模型被移动到您的 GPU 上
  • load_in_4bit应用 4 位动态量化以大幅减少资源需求

还有其他初始化模型的方法,但这是一个很好的基准,可以开始使用 LLM。

接下来,您需要使用 tokenizer 对文本输入进行预处理。

>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
>>> model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to("cuda")

model_inputs变量保存了标记化的文本输入,以及注意力掩码。虽然 generate()会尽力推断注意力掩码,但我们建议尽可能在生成时传递它以获得最佳结果。

在对输入进行标记化后,您可以调用 generate()方法返回生成的标记。然后应将生成的标记转换为文本后打印。

>>> generated_ids = model.generate(**model_inputs)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A list of colors: red, blue, green, yellow, orange, purple, pink,'

最后,您不需要一次处理一个序列!您可以对输入进行批处理,这将大大提高吞吐量,同时延迟和内存成本很小。您只需要确保正确填充输入即可(下文有更多信息)。

>>> tokenizer.pad_token = tokenizer.eos_token  # Most LLMs don't have a pad token by default
>>> model_inputs = tokenizer(
...     ["A list of colors: red, blue", "Portugal is"], return_tensors="pt", padding=True
... ).to("cuda")
>>> generated_ids = model.generate(**model_inputs)
>>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)
['A list of colors: red, blue, green, yellow, orange, purple, pink,',
'Portugal is a country in southwestern Europe, on the Iber']

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

常见陷阱

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

>>> from transformers import AutoModelForCausalLM, AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
>>> tokenizer.pad_token = tokenizer.eos_token  # Most LLMs don't have a pad token by default
>>> model = AutoModelForCausalLM.from_pretrained(
...     "mistralai/Mistral-7B-v0.1", device_map="auto", load_in_4bit=True
... )

生成的输出过短/过长

如果在 GenerationConfig 文件中未指定,generate默认返回最多 20 个标记。我们强烈建议在generate调用中手动设置max_new_tokens以控制它可以返回的最大新标记数量。请记住,LLMs(更准确地说,仅解码器模型)还会将输入提示作为输出的一部分返回。

>>> 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,'

生成模式不正确

默认情况下,除非在 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(42)
>>> model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to("cuda")
>>> # 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.  Specifically, I am an indoor-only cat.  I'

填充方向错误

LLMs 是仅解码器架构,意味着它们会继续迭代您的输入提示。如果您的输入长度不同,就需要进行填充。由于 LLMs 没有经过训练以从填充标记继续,因此您的输入需要进行左填充。确保不要忘记传递注意力掩码以生成!

>>> # The tokenizer initialized above has right-padding active by default: the 1st sequence,
>>> # which is shorter, has padding on the right side. Generation fails to capture the logic.
>>> 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, 33333333333'
>>> # With left-padding, it works as expected!
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
>>> tokenizer.pad_token = tokenizer.eos_token  # Most LLMs don't have a 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 的示例,它使用聊天模板:

>>> tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
>>> model = AutoModelForCausalLM.from_pretrained(
...     "HuggingFaceH4/zephyr-7b-alpha", device_map="auto", load_in_4bit=True
... )
>>> set_seed(0)
>>> prompt = """How many helicopters can a human eat in one sitting? Reply as a thug."""
>>> model_inputs = tokenizer([prompt], return_tensors="pt").to("cuda")
>>> input_length = model_inputs.input_ids.shape[1]
>>> generated_ids = model.generate(**model_inputs, max_new_tokens=20)
>>> print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"I'm not a thug, but i can tell you that a human cannot eat"
>>> # Oh no, it did not follow our instruction to reply as a thug! Let's see what happens when we write
>>> # a better prompt and use the right template for this model (through `tokenizer.apply_chat_template`)
>>> set_seed(0)
>>> messages = [
...     {
...         "role": "system",
...         "content": "You are a friendly chatbot who always responds in the style of a thug",
...     },
...     {"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
... ]
>>> model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to("cuda")
>>> input_length = model_inputs.shape[1]
>>> generated_ids = model.generate(model_inputs, do_sample=True, max_new_tokens=20)
>>> print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
'None, you thug. How bout you try to focus on more useful questions?'
>>> # As we can see, it followed a proper thug style 😎

更多资源

虽然自回归生成过程相对简单,但充分利用您的 LLM 可能是一项具有挑战性的努力,因为其中有许多要素。为了帮助您深入了解 LLM 的使用和理解,请继续以下步骤:

高级生成用法

  1. 指南关于如何控制不同的生成方法,如何设置生成配置文件,以及如何流式传输输出;
  2. 指南关于聊天 LLM 的提示模板;
  3. 指南如何充分利用提示设计;
  4. GenerationConfig 上的 API 参考,generate(),以及 generate-related classes。大多数类,包括 logits 处理器,都有使用示例!

LLM 排行榜

  1. Open LLM Leaderboard,专注于开源模型的质量;
  2. Open LLM-Perf Leaderboard,专注于 LLM 吞吐量。

延迟、吞吐量和内存利用率

  1. Guide 如何优化 LLMs 的速度和内存;
  2. Guide 关于量化,如 bitsandbytes 和 autogptq,展示了如何大幅减少内存需求。

相关库

  1. text-generation-inference,一个为 LLMs 准备的生产就绪服务器;
  2. optimum,一个 🤗 Transformers 的扩展,针对特定硬件设备进行优化。

任务指南

自然语言处理

文本分类

原始文本:huggingface.co/docs/transformers/v4.37.2/en/tasks/sequence_classification

www.youtube-nocookie.com/embed/leNG9fN9FQU

文本分类是一项常见的 NLP 任务,它为文本分配标签或类别。一些最大的公司在生产中运行文本分类,用于各种实际应用。文本分类中最流行的形式之一是情感分析,它为一系列文本分配标签如🙂积极,🙁消极或😐中性。

本指南将向您展示如何:

  1. IMDb数据集上对DistilBERT进行微调,以确定电影评论是积极的还是消极的。
  2. 使用您的微调模型进行推理。

本教程中演示的任务由以下模型架构支持:

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, Mistral,  Mixtral, MobileBERT, MPNet, MPT, MRA, MT5, MVP, Nezha, Nyströmformer,  OpenLlama, OpenAI GPT, OPT, Perceiver, Persimmon, Phi, PLBart, QDQBert,  Qwen2, 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 accelerate

我们鼓励您登录您的 Hugging Face 账户,这样您就可以上传和与社区分享您的模型。在提示时,输入您的令牌以登录:

>>> from huggingface_hub import notebook_login
>>> notebook_login()

加载 IMDb 数据集

首先从🤗数据集库中加载 IMDb 数据集:

>>> 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 标记器来预处理 text 字段:

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

创建一个预处理函数来对 text 进行标记化,并截断序列,使其不超过 DistilBERT 的最大输入长度:

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

应用预处理函数到整个数据集,使用🤗 Datasets map 函数。您可以通过设置 batched=True 来加速 map,以一次处理数据集的多个元素:

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

现在使用 DataCollatorWithPadding 创建一个示例批次。在整理过程中,动态填充句子到批次中的最长长度比整个数据集填充到最大长度更有效。

Pytorch 隐藏 Pytorch 内容

>>> from transformers import DataCollatorWithPadding
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

TensorFlow 隐藏 TensorFlow 内容

>>> from transformers import DataCollatorWithPadding
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")


Transformers 4.37 中文文档(二)(4)https://developer.aliyun.com/article/1563285

相关文章
|
3月前
|
存储 缓存 Shell
Transformers 4.37 中文文档(一)(3)
Transformers 4.37 中文文档(一)
212 1
Transformers 4.37 中文文档(一)(3)
|
3月前
|
存储 编解码 JSON
Transformers 4.37 中文文档(四)(5)
Transformers 4.37 中文文档(四)
43 1
Transformers 4.37 中文文档(四)(5)
|
3月前
|
自然语言处理 PyTorch 语音技术
Transformers 4.37 中文文档(四)(1)
Transformers 4.37 中文文档(四)
34 3
|
3月前
|
编解码 缓存 算法
Transformers 4.37 中文文档(一百)(2)
Transformers 4.37 中文文档(一百)
33 1
|
3月前
|
自然语言处理 PyTorch TensorFlow
Transformers 4.37 中文文档(一)(1)
Transformers 4.37 中文文档(一)
60 1
|
3月前
|
自然语言处理 PyTorch TensorFlow
Transformers 4.37 中文文档(一百)(3)
Transformers 4.37 中文文档(一百)
26 1
|
3月前
|
自然语言处理 PyTorch TensorFlow
Transformers 4.37 中文文档(一百)(4)
Transformers 4.37 中文文档(一百)
37 1
|
3月前
|
自然语言处理 PyTorch TensorFlow
Transformers 4.37 中文文档(一百)(5)
Transformers 4.37 中文文档(一百)
28 1
|
3月前
|
存储 JSON 缓存
Transformers 4.37 中文文档(一百)(1)
Transformers 4.37 中文文档(一百)
41 1
|
3月前
|
PyTorch TensorFlow 调度
Transformers 4.37 中文文档(四)(2)
Transformers 4.37 中文文档(四)
47 1