随着 ChatGPT 等 LLM 模型的发展,公司纷纷将基于语言的深度学习应用程序商业化。 Duolingo 和 Blinkist 等公司正在构建教育聊天应用程序,Cocounsel 等公司正在构建文档分析模型,而 MedGPT 等公司甚至正在构建可以执行医疗诊断等任务的专业模型。在上一篇文章中,我写了如何使用 ChatGPT 和提示工程来构建强大的文档分析器。
为了支持更强大和特定领域的LLM应用程序,技术提供商提供了许多云解决方案。例如,ChatGPT 背后的公司 OpenAI 为用户提供了一个简单但功能强大的微调 API,允许用户基于 GPT3 技术构建自己的语言模型。谷歌也不甘示弱,他们的野牛文本模型被广泛认为是 GPT 3 和 GPT 3.5 的有力竞争对手,可通过谷歌云平台进行微调。在上一篇文章中,我写了如何使用微调 API 创建领域专家 LLM。
尽管这些服务非常强大,但考虑对法学硕士技术进行大量投资的公司将希望学习利用开源技术训练自己的模型。与使用这些供应商提供的端点相比,训练您自己的模型具有以下优点:
在本文中,我们将采用一个流行且功能强大的开源 LLM 模型,使用我们自己的数据对其进行训练,类似于我们在上一篇文章中所做的那样,并验证结果。虽然我们正在处理的示例是非商业性的并且基于公共信息,但这些技术可以轻松地交叉应用于商业活动。我们将在“专家 LLM 模型”部分深入探讨使用此技术构建哪些商业应用程序的具体建议,其中我们定义了本文将要解决的问题。
对于今天的实验,我们将依赖Flan-T5 Large,这是 Google 发布的大型语言模型。虽然这不是 Bard 的基础技术,但该模型被广泛认为与基于 GPT 的技术具有竞争力。然而,Flan T5 模型令人印象深刻的是,它们使用比基于 GPT 的模型少得多的参数获得了令人满意的结果。例如,即使是 XL 版本的模型也只有 30 亿个参数,而 GPT3 则有 1750 亿个参数。
由于这种紧凑性,在云计算资产上训练和存储这些模型的成本相对较低。此外,Flan-T5 系列模型是随 Apache 许可证一起发布的,该许可证允许商业用途,从而减少了与其他一些开源 LLM 相关的潜在许可证问题。例如,Facebook 的 LLaMa 仍然仅可用于研究和非商业目的。
为了写这篇文章,我尝试了几种不同类别的任务来测试该技术的有效性。一般来说,Flan-T5,尤其是 XL 变体,似乎具有与市场上某些 GPT 模型类似的出色自然语言理解能力。然而,该模型在绘制抽象连接时有些不足,并且在生成长输出时遇到一些困难。因此,人们应该注意为正确的任务选择正确的模型。
Replicate 是一家平台即服务公司,允许人们以实惠的价格租用 GPU 来训练和运行大型人工智能模型。他们的人工智能模型管理工具套件允许用户专注于数据处理而不是管理服务器资源。
为了撰写本文,我尝试了多种 AI 训练 PaaS 产品,包括 AWS SageMaker、Google Colab 和 PaperSpace Gradient。 Replicate 是迄今为止最容易上手的平台,并且相对于提到的其他服务提供了非常有竞争力的价格。
Python 是数据工程的通用语言。广泛的生态系统使程序员能够快速摄取、分析和处理数据。大多数主要的人工智能培训平台都对Python提供一流的支持,这使我们的工作变得更加轻松。由于 Replicate 的出色集成,我们今天将使用 Python 编写所有代码。
由于 Flan-T5 系列模型在理解文本方面比生成文本要好得多,因此我们希望选择一个输入较多但输出较少的任务。自然语言分类器是此类场景的完美用例,因此今天我们将构建一个剧作家标识符。具体来说,我们将给出威廉·莎士比亚或安东·契诃夫的模型段落,看看我们是否可以教模型根据写作风格和词语选择来识别剧作家。
当然,因为这是一个公共教程,所以我们有意选择具有公共且易于访问的数据的模型。然而,这可以很容易地适应商业环境。以下是自然语言分类器可能有用的一些示例:
为了创建训练数据,我们可以从古腾堡计划下载一些安东·契诃夫和威廉·莎士比亚的戏剧。要设置数据摄取,我们可以运行以下 Python 脚本。
import requests import openai import replicate import os import pandas as pd import random texts = { 'chekhov': 'https://www.gutenberg.org/files/7986/7986-0.txt', 'chekhov_2': 'https://www.gutenberg.org/cache/epub/1755/pg1755.txt', 'shakespeare_midsummer': 'https://www.gutenberg.org/cache/epub/1514/pg1514.txt', 'shakespeare_romeo_juliet': 'https://www.gutenberg.org/cache/epub/1112/pg1112.txt', 'shakespeare_macbeth': 'https://www.gutenberg.org/cache/epub/2264/pg2264.txt', 'shakespeare_hamlet': 'https://www.gutenberg.org/cache/epub/2265/pg2265.txt', }
现在我们创建训练数据文件夹并下载文本:
if not os.path.exists('training_text'): os.mkdir('training_text') for name, url in texts.items(): print(name) res = requests.get(url) with open(os.path.join('training_text', '%s.txt' % name), 'w') as fp_write: fp_write.write(res.text)
您应该看到类似这样的一些输出,表明它已成功:
chekhov chekhov_2 shakespeare_midsummer shakespeare_romeo_juliet shakespeare_macbeth Shakespeare_hamlet
您还可以检查 Training_text 文件夹以查看文件是否已正确下载。
现在我们要将这些文件读回内存并将它们分成行列表。当我们这样做时,我们将计算每个文件中的行数。
lines_by_file = {} for fn in os.listdir('training_text'): if not fn.endswith('.txt'): continue with open(os.path.join('training_text', fn)) as fp_file: lines_by_file[fn.split('.')[0]] = '\n'.join(fp_file.readlines()) print(fn, len(lines_by_file[fn.split('.')[0]]))
您应该看到如下所示的输出:
shakespeare_midsummer.txt 120198 shakespeare_romeo_juliet.txt 179726 shakespeare_macbeth.txt 140022 shakespeare_hamlet.txt 204169 chekhov.txt 419063 chekhov_2.txt 148324
有趣的来了。我们希望将这些线分割成真实的训练数据。为此,我们首先删除前 1000 行,其中包含介绍、页眉和页脚内容。然后,我们一次抓取剩余的 50 行文本。然后我们将这 50 行变成提示和完成对。
train_data = [] for k in lines_by_file: is_chekhov = 'chekhov' in k useful_lines = lines_by_file[k].split('\n')[1000:-1000] prompt_fmt = "Which playwright wrote the following passage? \n ==== \n %s \n ====" for i in range(0, len(useful_lines), 50): training_set = useful_lines[i: i+50] train_data.append({ 'prompt': prompt_fmt % '\n'.join(training_set), 'completion': 'Anton Chekhov' if is_chekhov else 'William Shakespeare' })
现在我们已经清楚地定义了问题 - 给定戏剧中的 50 行文本,确定剧作家是安东·契诃夫还是威廉·莎士比亚。我们还没有完成。我们需要将数据写入jsonl(JSON Lines)格式用于训练,并且我们还想保留一些样本用于测试目的。像这样运行以下代码:
df = pd.DataFrame(train_data) df_chekhov = df[df['completion'] == 'Anton Chekhov'] df_shakespeare = df[df['completion'] == 'William Shakespeare'] chekhov_test_indices = random.sample(df_chekhov.index.tolist(), 15) shakespeare_test_indices = random.sample(df_shakespeare.index.tolist(), 15) df_chekhov_test = df_chekhov.loc[chekhov_test_indices] df_shakespeare_test = df_shakespeare.loc[shakespeare_test_indices] df_chekhov_train = df_chekhov.loc[[i for i in df_chekhov.index if i not in chekhov_test_indices]] df_shakespeare_train = df_shakespeare.loc[[i for i in df_shakespeare.index if i not in shakespeare_test_indices]] pd.concat([df_chekhov_train, df_shakespeare_train]).to_json('chekhov_shakespeare_train.jsonl', orient='records', lines=True) pd.concat([df_chekhov_test, df_shakespeare_test]).to_json('chekhov_shakespeare_test.jsonl', orient='records', lines=True)
当然,如果你想使用整个语料库进行训练,你可以简单地运行
pd.DataFrame(train_data).to_json('output.jsonl', orient='records', lines=True)
。
在调用训练之前,我们需要做两件事 - 首先,我们需要将训练数据上传到可复制访问的地方。一种非常简单的方法是将文件上传到 google 云存储桶,将存储桶和文件公开,并以https://storage.googleapis.com/<bucket_name>/<file_name>
格式提供 url https://storage.googleapis.com/<bucket_name>/<file_name>
.
接下来,我们需要创建一个目的地。为此,只需登录 Replicate(您可以通过 Github OAuth 来完成),然后创建一个新模型。创建并命名模型后,您将能够将模型推送到此空间。
一切设置完毕后,您可以像这样开始训练:
training = replicate.trainings.create( version="[flant5-large location]", input={ "train_data": "[Data Location]", }, destination="[Destination]" ) print(training)
您应该看到一些输出,告诉您训练正在开始。等待几分钟,然后运行以下代码来检查训练情况:
training.reload() print(training)
您还可以在 Replicate 网站上监控训练进度。训练完成后,您可以重新加载训练对象以获取输出名称并继续下一步。
请注意,有时 GPU 资源稀缺,您可能会收到“训练失败”错误。如果您遇到这种情况,请等待几个小时,然后重试。 GPU 短缺,PaaS 提供商也不能幸免!
好的!现在我们已经有了微调后的模型,我们需要对其进行测试。请记住,我们保留了 15 个契诃夫和莎士比亚的段落用于测试。我们可以在这里使用它们,如下所示:
for _, row in df_chekhov_test.iterrows(): output = replicate.run( training.output["version"], input={"prompt": row['prompt']} ) for s in output: print(s, end="", flush=True) print('')
经过短暂的启动后,您应该看到输出打印到控制台。该模型应该非常准确,并且每次都会返回“Anton Chekhov”。让我们用莎士比亚来试试这个:
for _, row in df_shakespeare_test.iterrows(): output = replicate.run( training.output["version"], input={"prompt": row['prompt']} ) for s in output: print(s, end="", flush=True) print('')
与契诃夫的例子类似,您应该看到该模型每次都能识别莎士比亚。
为了更好地衡量,让我们看看基本模型是否能够识别莎士比亚或契诃夫:
for _, row in df_shakespeare_test.iterrows(): output = replicate.run( "[base flant5-large location]", input={"prompt": row['prompt']} ) for s in output: print(s, end="", flush=True) print('') for _, row in df_chekhov_test.iterrows(): output = replicate.run( "[base flant5-large location]", input={"prompt": row['prompt']} ) for s in output: print(s, end="", flush=True) print('')
您应该看到基本模型无法可靠地识别相同段落的剧作家。这表明我们的微调可靠地为模型提供了新信息,并且我们已经为自己构建了一个自然语言剧作家分类器!
在今天的文章中,我们基于 Google 提供的大型语言模型 Flan-T5 训练了一个简单的自然语言分类器。由于其紧凑的尺寸和宽松的许可证,Flan-T5 可以在私有基础设施上进行训练和部署,这使其与市场上许多其他流行模型(例如 ChatGPT)区分开来。
虽然今天的示例基于公共数据并且绝对是非商业性的,但这种概念证明可以轻松地适应如上所述的许多其他商业应用。如果您对法学硕士有一个想法并希望将其变为现实,请随时访问我的GitHub或LinkedIn页面来开始对话。另外,请随意阅读我之前的 LLM 文章,包括一篇关于使用 ChatGPT 构建文档分析器和使用 OpenAI 的 Fine Tuning API 创建领域专家 LLM 的文章。
快乐黑客!