在我们为面向客户的聊天应用制作大语言模型 (LLM)时,预训练模型往往是很好的起点,但随着时间的推移,您可能希望去控制该模型聊天的整体行为和给客户带去的“感觉”,而不仅仅由基本模型所能提供。对此,我们虽然可以通过提示工程(prompt engineering)来实现,但是它会严重限制聊天输入的长度,而且每次推理调用的成本都会增加。目前,另一种更有效的方法是在数据集上对模型进行微调,并在模型中灌输新的行为模式。
微调Mistral 7B模型
下面,我们将引导您微调Mistral7B的开源LLM。为此,我们会调用MindsDB与模型进行交互,并使用Anyscale Endpoints对其进行托管。如果您需要微调其他模型的话,其过程将十分类似。
什么是MindsDB?
作为一个面向开发人员的开源人工智能(AI)平台,MindsDB可以将AI/ML模型与实时数据相连接。由其提供的工具和自动化功能,可轻松地构建和维护个性化AI方案。MindsDB提供了数百种与各种数据源、API和ML框架的集成。借助该平台,您可以将最先进的AI模型(如OpenAI、LLama2、Cohere、Mistral等)与数百种数据源(包括企业级数据库,以及PostgreSQL、MongoDB、Snowflake、Slack、Shopify等第三方应用)整合在一起。
什么是Anyscale?
Anyscale是支持ChatGPT等世界顶尖AI产品的Ray框架的创建者。由其提供的Anyscale Endpoints可以轻松地以快度、低成本的方式,优化访问Mistral 7B等开源LLM。
微调模型
下面,我们会把微调后的模型与其原始版本进行比较,检查其输出行为上的差异,并解释其背后原因。
步骤 1:准备好先决条件
- 请在您的机器上本地部署MindsDB。
- 请确保安装了Anyscale Endpoints集成。
- 此外,您还需要注册Anyscale Endpoints。
步骤 2:加载数据
我们将使用由链接--https://huggingface.co/datasets/b-mc2/sql-create-context?ref=hackernoon.com提供的数据集。其中包含了“上下文-问题-答案”三元组。它们将针对SQL表的原始查询,与用户提出的自然语言问题,以及返回该用户所需信息的基本答案联系起来。
尽管该数据集包含了7万多个示例,但是我们在此只考虑前300个。我们会将数据重新排列成“长”格式,并将“对话/聊天”垂直堆叠成行。也就是说,每一行都有一条“内容”信息和一个“角色”。此处的角色可以是“系统”、“助手”(我们的模型)或“用户”。
那么在每个“系统”行的内容中,我们都定义了如下内容:
- 其任务是将问题转化为SQL查询
- 相关的SQL表会创建参考语句
据此,输入以下内容即可轻松地检查到相关数据:
SELECT * FROM example_db.demo_data.anyscale_endpoints_ft_sample_data LIMIT 10;
下图展示的是从Postgres数据库示例中检索到的一个样本:
请注意,助手的回答就是询问,没有任何附带解释。这就是我们希望观察到的原始基础模型的主要效果。下面,让我们来设置一下。
步骤 3:设置基本模型
1.在MindsDB项目中创建一个Anyscale集成的实例:
CREATE ML_ENGINE anyscale_endpoints FROM anyscale_endpoints;
2.用它创建一个初始的Mistral 7B模型(这里使用的具体模型名称是mistralai/Mistral-7B-Instruct-v0.1):
CREATE MODEL ft_sql
PREDICT answer
USING
engine = 'anyscale_endpoints',
model_name = 'mistralai/Mistral-7B-Instruct-v0.1',
prompt_template = '{{content}}',
api_key = 'your-api-key-here';
3.您可以通过如下语句,查询模型并从中得到答案:
SELECT answer FROM ft_sql WHERE content = 'hi!';
4.让我们以如下方式提问,从原始数据集的诸多示例中获取一个:
SELECT answer FROM ft_sql WHERE content = 'Hi! I have created a SQL table with this command: “CREATE TABLE employees (country VARCHAR)”. How should I query my database to know how many employees are living in Canada?';
您应该得到如下回复:
虽然上述答案是正确的,但是有些冗长。如果要在更广泛的软件应用(如代码协同引导程序)中部署该模型,则需要有更简洁的输出。
在此,我们需要强调的是,虽然取决于多种变量,但是在预先训练好的大语言模型上执行微调的主要效果,就是要影响模型的整体行为和排列,而不是完美地记忆新示例中包含的所有事实信息。相反,如果您需要提取存储在其他地方的特定真实数据,那么您最好使用RAG设置。这两种技术并不互斥,您完全可以同时使用两者。
步骤 4:微调模型
5.有了现成的数据集,再加上MindsDB和Anyscale Endpoint的简易性,我们只需如下一条SQL命令就能对Mistral 7B模型进行微调了:
FINETUNE ft_sql FROM example_db (
SELECT * FROM demo_data.anyscale_endpoints_ft_sample_data LIMIT 300
);
6.该命令将触发Anyscale Endpoints平台上的微调运行。由于模型有70亿个参数,而数据集较小,因此该过程可能需要15分钟左右的时间。
如下图所示,您将会在注册Anyscale Endpoints时使用过的电子邮箱中收到通知。之后MindsDB模型也会显示为已准备就绪的状态。
下图展示了由其建立的可视化管道:
由于Mistral 7B是一个基于“transformer”架构的大型神经网络,因此对其进行“监督微调”可以被理解为:对预先训练好的基础模型的某些权重稍作修改。具体做法是:在部分新的数据上最小化误差指标,同时兼顾较低的学习率等因素。
而且,与基础预训练阶段相比,其根本的区别就在于数据是有标签的,而不是无标签的(标签提供了“监督”)。从上述步骤可知,我们提供了一个理想“助手”的预期回答,这将为训练过程提供参考信息,以获得一个比原始模型更善于生成答案的模型。
接着,我们来试着对模型提出如下问题:
SELECT answer FROM ft_sql WHERE content = 'Hi! I have created a SQL table with this command: “CREATE TABLE employees (country VARCHAR)”. How should I query my database to know how many employees are living in Canada?';
与之相对应的答案(answer)列输出会显示为:SELECT COUNT(*) FROM employees WHERE country = "Canada"。显然,这要简洁得多。
由于MindsDB具有自动模型版本控制功能,因此您可以通过MODEL_NAME.VERSION访问以前的模型版本。下面是我们针对.1版本通过重新输入来触发。它将给出与第3.d节类似的答案。
SELECT answer FROM ft_sql.1 WHERE content = 'Hi! I have created a SQL table with this command: “CREATE TABLE employees (country VARCHAR)”. How should I query my database to know how many employees are living in Canada?' USING max_tokens=1000;
需要进一步说明的是,虽然微调后的模型确实表现出了较大的不同,但是我们仍有必要根据经验来检查准确度指标,毕竟众所周知,LLM需要通过“空间(space)”来产生更好的答案。此处的空间是以词块来衡量的,它直接会导致更长的回答。这就意味着,根据任务的不同,冗长的答案可能会更难解析。不过,这实际上可能是提高下游任务准确性的一种理想特性。
步骤 5:提示工程
此处还有一个有趣的现象。正如OpenAI在发布GPT-2时所展示的那样,大语言模型可以有效地在“上下文”中学习,也就是所谓的“提示”。这正是为什么提示工程在建立LLM管道时,被描述为绝对关键的原因。事实表明,一个精心挑选的上下文实例所产生的影响,可能不亚于数十或数百个对模型进行微调的特定实例。
下面,让我们再次使用基本模型,并修改为“提示”方式,使得读取方式略有不同:
CREATE MODEL ft_sql_succinct
PREDICT answer
USING
engine = 'anyscale_endpoints',
model_name = 'mistralai/Mistral-7B-Instruct-v0.1',
prompt_template = 'Answer with the correct SQL query only, no explanations whatsoever. Here is the question: {{content}}';
显然,如果使用相同的内容输入去查询该模型,就会得到“SELECT COUNT(*) FROM employees WHERE country = 'Canada';”这正是我们想要的效果,也说明了:对于简单的情况,良好的提示模板可以起到显著的作用。
什么时候使用提示工程?
大多数LLM提供者都会建议我们在进行任何微调之前,先进行提示工程的设计。而真正在进行微调时,您可以在某处生成一组新的模型。上文演示的MindsDB+Anyscale 技术栈虽然能够处理基础架构的开销,但与推理时可用于基础模型的单个灵活提示相比,则会引入额外的训练和服务问题等更高的运行成本。
反过来说,如果您有大量的数据需要微调,或者由于某种行为限制,使得提示工程无法满足您的要求的话,那么微调就会成为一种更有吸引力的选择。例如,您的基本模型可能有一个特别短的token限制(如:总共只有2K的token)。
当然,如前所述,如果您需要模型能够回忆各种事实情况,那么RAG则是必要的补充。它将能极大地帮助模型避免编造信息。
小结
在上文中,我们讨论了MindsDB和Anyscale Endpoints是如何以一种经济高效且简单的方式,将开源大模型与数据进行微调。同时,我们也探讨了微调对模型行为的影响,以及微调与提示工程的关系。希望上述内容对您有所帮助,祝您的项目取得成功。
【原标题】Fine-Tuning Mistral 7B: Enhance Open-Source Language Models with MindsDB and Anyscale Endpoints,作者: Jorge Torres