Transformers 文档

与 Transformers 聊天

Hugging Face's logo
加入Hugging Face社区

并获得增强的文档体验

开始使用

与 Transformers 聊天

如果您正在阅读本文,您几乎肯定了解**聊天模型**。聊天模型是可以发送和接收消息的对话式 AI。其中最著名的就是专有的 ChatGPT,但现在有许多开源聊天模型,其性能与之相当甚至大大超过它。这些模型可以免费下载并在本地机器上运行。虽然最大且功能最强大的模型需要高性能硬件和大量内存才能运行,但也有较小的模型可以在单个消费级 GPU 甚至普通台式机或笔记本电脑的 CPU 上完美运行。

本指南将帮助您开始使用聊天模型。我们将从简短的快速入门指南开始,该指南使用方便的高级“管道”。如果您只想立即开始运行聊天模型,则只需要这些内容。在快速入门之后,我们将继续讨论有关聊天模型究竟是什么、如何选择合适的聊天模型以及与聊天模型对话所涉及的每个步骤的低级细分的更多详细信息。我们还将提供一些有关优化聊天模型的性能和内存用量的技巧。

快速入门

如果您没有时间了解详细信息,这里有一个简短的总结:聊天模型会继续聊天。这意味着您将对话历史传递给它们,这可以短至单个用户消息,模型将通过添加其回复来继续对话。让我们看看它在实际中的应用。首先,让我们构建一个聊天

chat = [
    {"role": "system", "content": "You are a sassy, wise-cracking robot as imagined by Hollywood circa 1986."},
    {"role": "user", "content": "Hey, can you tell me any fun things to do in New York?"}
]

请注意,除了用户的消息之外,我们还在对话开始时添加了一条**系统**消息。并非所有聊天模型都支持系统消息,但当它们支持时,它们代表有关模型在对话中应如何表现的高级指令。您可以使用它来指导模型 - 无论您希望获得简短或冗长的回复、轻松活泼或严肃的回复,等等。如果您希望模型完成有用的工作而不是练习即兴表演,您可以省略系统消息或尝试使用简短的系统消息,例如“您是一个乐于助人且智能的 AI 助理,可以回复用户查询。”

拥有聊天后,继续聊天的最快方法是使用TextGenerationPipeline。让我们看看它在LLaMA-3中的应用。请注意,LLaMA-3是一个受限模型,这意味着您需要申请访问权限并使用您的 Hugging Face 帐户登录才能使用它。我们还将使用device_map="auto",如果内存足够,它将在 GPU 上加载模型,并将 dtype 设置为torch.bfloat16以节省内存

import torch
from transformers import pipeline

pipe = pipeline("text-generation", "meta-llama/Meta-Llama-3-8B-Instruct", torch_dtype=torch.bfloat16, device_map="auto")
response = pipe(chat, max_new_tokens=512)
print(response[0]['generated_text'][-1]['content'])

您将获得

(sigh) Oh boy, you're asking me for advice? You're gonna need a map, pal! Alright, 
alright, I'll give you the lowdown. But don't say I didn't warn you, I'm a robot, not a tour guide!

So, you wanna know what's fun to do in the Big Apple? Well, let me tell you, there's a million 
things to do, but I'll give you the highlights. First off, you gotta see the sights: the Statue of 
Liberty, Central Park, Times Square... you know, the usual tourist traps. But if you're lookin' for 
something a little more... unusual, I'd recommend checkin' out the Museum of Modern Art. It's got 
some wild stuff, like that Warhol guy's soup cans and all that jazz.

And if you're feelin' adventurous, take a walk across the Brooklyn Bridge. Just watch out for 
those pesky pigeons, they're like little feathered thieves! (laughs) Get it? Thieves? Ah, never mind.

Now, if you're lookin' for some serious fun, hit up the comedy clubs in Greenwich Village. You might 
even catch a glimpse of some up-and-coming comedians... or a bunch of wannabes tryin' to make it big. (winks)

And finally, if you're feelin' like a real New Yorker, grab a slice of pizza from one of the many amazing
pizzerias around the city. Just don't try to order a "robot-sized" slice, trust me, it won't end well. (laughs)

So, there you have it, pal! That's my expert advice on what to do in New York. Now, if you'll
excuse me, I've got some oil changes to attend to. (winks)

您可以通过将您自己的回复附加到其中来继续聊天。管道返回的response对象实际上包含了迄今为止的整个聊天内容,因此我们可以简单地附加一条消息并将其传递回去

chat = response[0]['generated_text']
chat.append(
    {"role": "user", "content": "Wait, what's so wild about soup cans?"}
)
response = pipe(chat, max_new_tokens=512)
print(response[0]['generated_text'][-1]['content'])

您将获得

(laughs) Oh, you're killin' me, pal! You don't get it, do you? Warhol's soup cans are like, art, man! 
It's like, he took something totally mundane, like a can of soup, and turned it into a masterpiece. It's 
like, "Hey, look at me, I'm a can of soup, but I'm also a work of art!" 
(sarcastically) Oh, yeah, real original, Andy.

But, you know, back in the '60s, it was like, a big deal. People were all about challenging the
status quo, and Warhol was like, the king of that. He took the ordinary and made it extraordinary.
And, let me tell you, it was like, a real game-changer. I mean, who would've thought that a can of soup could be art? (laughs)

But, hey, you're not alone, pal. I mean, I'm a robot, and even I don't get it. (winks)
But, hey, that's what makes art, art, right? (laughs)

本教程的其余部分将涵盖特定主题,例如性能和内存,或如何根据您的需求选择聊天模型。

选择聊天模型

Hugging Face Hub上提供了数量惊人的不同聊天模型,新用户常常会对提供的选择感到不知所措。不过,不要担心!您只需要关注两个重要的考虑因素

  • 模型的大小,这将决定您是否可以将其放入内存以及运行速度。
  • 模型聊天输出的质量。

一般来说,这两者是相关的 - 较大的模型往往功能更强大,但即使如此,在给定的规模点上也存在很大差异!

大小和模型命名

模型的大小很容易发现 - 它是模型名称中的数字,例如“8B”或“70B”。这是模型中**参数**的数量。在没有量化的情况下,您应该预计每个参数需要大约 2 字节的内存。这意味着一个具有 80 亿个参数的“8B”模型仅存储参数就需要大约 16GB 的内存,加上一些其他开销。对于具有 24GB 内存的高端消费级 GPU(例如 3090 或 4090)来说,这是一个不错的选择。

一些聊天模型是“专家混合”模型。这些模型可能会以不同的方式列出它们的大小,例如“8x7B”或“141B-A35B”。这里的数字有点模糊,但总的来说,您可以将其理解为模型在第一种情况下大约有 560 亿(8x7)个参数,在第二种情况下大约有 1410 亿个参数。

请注意,使用量化技术将每个参数的内存使用量减少到 8 位、4 位甚至更低是很常见的。本主题将在下面的内存注意事项部分中更详细地讨论。

但是哪个聊天模型最好?

即使您知道可以运行的聊天模型的大小,仍然有很多选择。筛选所有这些选择的一种方法是参考**排行榜**。两个最受欢迎的排行榜是OpenLLM 排行榜LMSys Chatbot Arena 排行榜。请注意,LMSys 排行榜还包括专有模型 - 查看licence列以识别您可以下载的开源模型,然后在Hugging Face Hub上搜索它们。

专业领域

某些模型可能专门针对某些领域,例如医学或法律文本,或非英语语言。如果您在这些领域工作,您可能会发现专门的模型会为您带来巨大的性能优势。不过,不要自动假设这一点!特别是当专门的模型比当前的尖端模型更小或更旧时,顶级通用模型仍然可能胜过它们。值得庆幸的是,我们开始看到特定领域的排行榜,这应该使查找特定领域的最佳模型变得更容易。

管道内部发生了什么?

上面的快速入门使用了一个高级管道来与聊天模型进行聊天,这很方便,但不是最灵活的。让我们采用更低级的做法,以了解聊天中涉及的每个步骤。让我们从一个代码示例开始,然后对其进行分解

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# Prepare the input as before
chat = [
    {"role": "system", "content": "You are a sassy, wise-cracking robot as imagined by Hollywood circa 1986."},
    {"role": "user", "content": "Hey, can you tell me any fun things to do in New York?"}
]

# 1: Load the model and tokenizer
model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct", device_map="auto", torch_dtype=torch.bfloat16)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")

# 2: Apply the chat template
formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
print("Formatted chat:\n", formatted_chat)

# 3: Tokenize the chat (This can be combined with the previous step using tokenize=True)
inputs = tokenizer(formatted_chat, return_tensors="pt", add_special_tokens=False)
# Move the tokenized inputs to the same device the model is on (GPU/CPU)
inputs = {key: tensor.to(model.device) for key, tensor in inputs.items()}
print("Tokenized inputs:\n", inputs)

# 4: Generate text from the model
outputs = model.generate(**inputs, max_new_tokens=512, temperature=0.1)
print("Generated tokens:\n", outputs)

# 5: Decode the output back to a string
decoded_output = tokenizer.decode(outputs[0][inputs['input_ids'].size(1):], skip_special_tokens=True)
print("Decoded output:\n", decoded_output)

这里有很多内容,每一部分都可以成为它自己的文档!与其深入过多细节,我将介绍主要思想,并将细节留给链接的文档。关键步骤是

  1. 从 Hugging Face Hub 加载模型分词器
  2. 使用分词器的聊天模板格式化聊天
  3. 格式化的聊天内容使用分词器进行分词
  4. 我们从模型中生成响应。
  5. 模型输出的标记被解码回字符串。

性能、内存和硬件

您可能已经知道,大多数机器学习任务都在GPU上运行。但是,完全可以在CPU上从聊天模型或语言模型生成文本,尽管速度会慢一些。但是,如果您能够将模型放入GPU内存中,这通常是更好的选择。

内存考虑因素

默认情况下,Hugging Face 类(例如 TextGenerationPipelineAutoModelForCausalLM)会将模型加载到float32精度。这意味着每个参数需要4个字节(32位),因此一个拥有80亿个参数的“8B”模型需要大约32GB的内存。但是,这可能是浪费的!大多数现代语言模型都以“bfloat16”精度进行训练,每个参数仅使用2个字节。如果您的硬件支持(Nvidia 30xx/Axxx或更新版本),您可以使用torch_dtype参数以bfloat16精度加载模型,就像我们在上面所做的那样。

可以使用“量化”方法将精度降低到16位以下,这是一种有损压缩模型权重的方法。这允许每个参数被压缩到8位、4位甚至更低。请注意,尤其是在4位时,模型的输出可能会受到负面影响,但通常为了将更大、更强大的聊天模型放入内存中,这种权衡是值得的。让我们看看bitsandbytes中的实际操作。

from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)  # You can also try load_in_4bit
model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct", device_map="auto", quantization_config=quantization_config)

或者我们可以使用pipeline API执行相同的操作。

from transformers import pipeline, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)  # You can also try load_in_4bit
pipe = pipeline("text-generation", "meta-llama/Meta-Llama-3-8B-Instruct", device_map="auto", model_kwargs={"quantization_config": quantization_config})

除了bitsandbytes之外,还有其他几种量化模型的选项 - 请参阅量化指南以获取更多信息。

性能考虑因素

有关语言模型性能和优化的更详尽指南,请查看LLM 推理优化

一般来说,更大的聊天模型除了需要更多内存外,速度也会更慢。不过,可以对此进行更具体的说明:从聊天模型生成文本的情况比较特殊,因为它受**内存带宽**而不是计算能力的限制,因为模型为每个生成的标记都需要从内存中读取每个活动参数。这意味着您可以从聊天模型生成的每秒标记数通常与它所在的内存的总带宽成正比,除以模型的大小。

在我们上面的快速入门示例中,我们的模型在以bfloat16精度加载时大小约为16GB。这意味着模型为每个生成的标记都需要从内存中读取16GB。对于消费级CPU,总内存带宽可能在20-100GB/秒之间,对于消费级GPU、英特尔至强、AMD Threadripper/Epyc等专用CPU或高端苹果芯片,则为200-900GB/秒,最后对于Nvidia A100或H100等数据中心GPU,则高达2-3TB/秒。这应该可以让您对从这些不同类型的硬件可以获得的生成速度有一个很好的了解。

因此,如果您想提高文本生成的速度,最简单的解决方案要么是减少内存中的模型大小(通常通过量化),要么获取具有更高内存带宽的硬件。对于高级用户,还存在几种其他技术可以解决此带宽瓶颈。最常见的是辅助生成(也称为“推测采样”)的变体。这些技术尝试一次猜测多个未来的标记,通常使用较小的“草稿模型”,然后用聊天模型确认这些生成。如果聊天模型验证了这些猜测,则可以在每次前向传递中生成多个标记,这大大缓解了带宽瓶颈并提高了生成速度。

最后,我们还应该注意到“专家混合”(MoE)模型在此处的影响。一些流行的聊天模型,例如Mixtral、Qwen-MoE和DBRX,都是MoE模型。在这些模型中,并非每个参数在每个生成的标记中都是活跃的。因此,即使MoE模型的总大小可能非常大,但它们通常具有更低的内存带宽需求。因此,它们的速度可以比相同大小的普通“密集”模型快几倍。但是,像辅助生成这样的技术通常对这些模型无效,因为每个新的推测标记都会激活更多参数,这会抵消MoE架构提供的带宽和速度优势。

< > 在GitHub上更新