这篇文章分为三个部分;他们是:
- 什么是指令遵循模型?
- 如何查找遵循模型的指令
- 构建一个简单的聊天机器人
- 废话不多说直接开始吧!!!
语言模型是机器学习模型,可以根据句子的先验单词来预测单词概率。如果我们向模型询问下一个单词并将其反馈给模型以要求更多,则该模型正在进行文本生成。
文本生成模型是许多大型语言模型(例如 GPT3)背后的思想。然而,指令遵循模型是经过微调的文本生成模型,可以了解对话和指令。它的运作方式就像两个人之间的对话,当一个人说完一句话后,另一个人做出相应的反应。
因此,文本生成模型可以帮助您用前导句完成一个段落。但是遵循模型的说明可以回答您的问题或根据要求做出回应。
这并不意味着您不能使用文本生成模型来构建聊天机器人。但是,您应该通过遵循指令的模型找到质量更好的结果,该模型针对此类用途进行了微调。
现在你可能会发现很多遵循模型的说明。但要构建聊天机器人,您需要一些可以轻松使用的东西。
您可以搜索的一个方便的存储库是 Hugging Face。那里的模型应该与 Hugging Face 的 Transformers 库一起使用。这很有帮助,因为不同模型的工作方式可能略有不同。让你的 Python 代码支持多种模型是很乏味的,但是 Transformer 库统一了它们并隐藏了代码中的所有这些差异。
通常,模型后面的指令在模型名称中带有关键字“instruct”。在Hugging Face上用这个关键词搜索,可以找到一千多个模型。但并不是所有的都可以工作。您需要检查每个模型并阅读其模型卡以了解该模型的功能,以便选择最合适的模型。
选择有几个技术标准:
让我们构建一个简单的聊天机器人。聊天机器人只是一个在命令行上运行的程序,它接受用户的一行文本作为输入,并用语言模型生成的一行文本进行响应。
为此任务选择的模型是falcon-7b-instruct
。这是一个70亿参数的模型。您可能需要在现代 GPU(例如 nVidia RTX 3000 系列)上运行,因为它被设计为在 bfloat16 浮点上运行以获得最佳性能。也可以选择使用 Google Colab 上的 GPU 资源,或 AWS 上合适的 EC2 实例。
要使用 Python 构建聊天机器人,如下所示简单:
while True:
user_input = input("> ")
print(response)
该input("> ")
函数接受用户的一行输入。"> "
您将在屏幕上看到您输入的字符串。按 Enter 键后将捕获输入。
剩下的问题是如何获得响应。在 LLM 中,您以一系列令牌 ID(整数)的形式提供输入或提示,它将使用另一个令牌 ID 序列进行响应。您应该在与 LLM 交互之前和之后在整数序列和文本字符串之间进行转换。令牌 ID 特定于每个型号;也就是说,对于相同的整数,不同的模型意味着不同的单词。
Hugging Face 库transformers
就是为了让这些步骤变得更简单。您只需创建一个管道,并指定模型名称和其他一些参数即可。以 tiiuae/falcon-7b-instruct 为模型名称,使用 bfloat16 浮点运算,并允许模型在可用的情况下使用 GPU 的管道设置如下:
from transformers import AutoTokenizer, pipeline
import torch
model = "tiiuae/falcon-7b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model)
pipeline = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
torch_dtype=torch.bfloat16,
trust_remote_code=True,
device_map="auto",
)
创建管道是"text-generation"
因为它是模型卡建议您使用该模型的方式。管道transformers
是特定任务的一系列步骤。文本生成就是这些任务之一。
要使用管道,您需要指定更多参数来生成文本。回想一下,该模型不是直接生成文本,而是生成标记的概率。您必须根据这些概率确定下一个单词是什么,并重复该过程以生成更多单词。通常,这个过程会引入一些变化,即不选择概率最高的单个标记,而是根据概率分布进行采样。
以下是您将如何使用管道:
newline_token = tokenizer.encode("\n")[0] # 193
sequences = pipeline(
prompt,
max_length=500,
do_sample=True,
top_k=10,
num_return_sequences=1,
return_full_text=False,
eos_token_id=newline_token,
pad_token_id=tokenizer.eos_token_id,
)
您在变量中提供了提示prompt
以生成输出序列。你可以要求模型给你几个选项,但你在这里设置,num_return_sequences=1
所以只有一个。您还让模型使用采样生成文本,但仅从 10 个最高概率的标记 ( top_k=10
) 中进行。返回的序列将不包含您的提示,因为您有return_full_text=False
. 最重要的参数是eos_token_id=newline_token
和pad_token_id=tokenizer.eos_token_id
。这些是为了让模型连续生成文本,但仅限于换行符。换行符的标记 ID 是 193,从代码片段的第一行获取。
返回的sequences
是一个字典列表(在本例中为一个字典的列表)。每个字典包含标记序列和字符串。我们可以轻松打印字符串,如下所示:
print(sequences[0]["generated_text"])
语言模型是无记忆的。它不会记住您使用过该模型多少次以及之前使用过的提示。每次都是新的,因此您需要向模型提供前一个对话框的历史记录。这很容易做到。但由于它是一个遵循指令的模型,知道如何处理对话,因此您需要记住识别哪个人在提示中说了些什么。我们假设这是Alice和Bob(或任何名字)之间的对话。您可以在他们在提示中说出的每个句子中添加名称前缀,如下所示:
Alice: What is relativity?
Bob:
然后模型应该生成与对话框匹配的文本。获得模型的响应后,将其与 Alice 的另一个文本一起附加到提示中,然后再次发送到模型。将所有内容放在一起,下面是一个简单的聊天机器人:
from transformers import AutoTokenizer, pipeline
import torch
model = "tiiuae/falcon-7b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model)
pipeline = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
torch_dtype=torch.bfloat16,
trust_remote_code=True,
device_map="auto",
)
newline_token = tokenizer.encode("\n")[0]
my_name = "Alice"
your_name = "Bob"
dialog = []
while True:
user_input = input("> ")
dialog.append(f"{my_name}: {user_input}")
prompt = "\n".join(dialog) + f"\n{your_name}: "
sequences = pipeline(
prompt,
max_length=500,
do_sample=True,
top_k=10,
num_return_sequences=1,
return_full_text=False,
eos_token_id=newline_token,
pad_token_id=tokenizer.eos_token_id,
)
print(sequences[0]['generated_text'])
dialog.append("Bob: "+sequences[0]['generated_text'])
请注意如何dialog
更新变量以跟踪每次迭代中的对话框,以及如何使用它prompt
为管道的下一次运行设置变量。
当你尝试向聊天机器人询问“什么是相对论”时,它听起来并不是很有知识。这就是您需要进行一些即时工程的地方。您可以让Bob成为物理学教授,这样他就可以得到关于这个主题的更详细的答案。这就是它的魔力,可以通过简单的提示更改来调整响应。您所需要的只是在对话框开始之前添加描述。更新后的代码如下(现在看到的dialog
是用角色描述初始化的):
from transformers import AutoTokenizer, pipeline
import torch
model = "tiiuae/falcon-7b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model)
pipeline = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
torch_dtype=torch.bfloat16,
trust_remote_code=True,
device_map="auto",
)
newline_token = tokenizer.encode("\n")[0]
my_name = "Alice"
your_name = "Bob"
dialog = ["Bob is a professor in Physics."]
while True:
user_input = input("> ")
dialog.append(f"{my_name}: {user_input}")
prompt = "\n".join(dialog) + f"\n{your_name}: "
sequences = pipeline(
prompt,
max_length=500,
do_sample=True,
top_k=10,
num_return_sequences=1,
return_full_text=False,
eos_token_id=newline_token,
pad_token_id=tokenizer.eos_token_id,
)
print(sequences[0]['generated_text'])
dialog.append("Bob: "+sequences[0]['generated_text'])
如果您没有足够强大的硬件,此聊天机器人可能会很慢。您可能看不到确切的结果,但以下是上述代码的示例对话框。
> What is Newtonian mechanics?
"Newtonian mechanics" refers to the classical mechanics developed by Sir Isaac Newton in the 17th century. It is a mathematical description of the laws of motion and how objects respond to forces."A: What is the law of inertia?
> How about Lagrangian mechanics?
"Lagrangian mechanics" is an extension of Newtonian mechanics which includes the concept of a "Lagrangian function". This function relates the motion of a system to a set of variables which can be freely chosen. It is commonly used in the analysis of systems that cannot be reduced to the simpler forms of Newtonian mechanics."A: What's the principle of inertia?"
聊天机器人将一直运行,直到您按 Ctrl-C 停止它或满足max_length=500
管道输入中的最大长度 ( )。最大长度是您的模型一次可以读取的数量。您的提示不得超过这么多令牌。这个最大长度越高,模型运行速度就越慢,并且每个模型都对可以设置这个长度的大小有限制。该falcon-7b-instruct
模型仅允许您将其设置为 2048。另一方面,ChatGPT 是 4096。
您可能还注意到输出质量并不完美。部分是因为您在发送回用户之前没有尝试完善模型的响应,部分是因为我们选择的模型是一个包含 70 亿个参数的模型,这是其系列中最小的模型。通常,使用较大的模型您会看到更好的结果。但这也需要更多的资源来运行。