此存储库中的食谱从那以后移至Prodigy,并在那里维持。他们甚至很快就会随着Spacy-LLM支持的出现而进行升级,该支持具有更好的提示和多个LLM提供商。这就是为什么我们选择归档此存储库的原因,以便我们可以直接将这些食谱直接保留为Spacy和Prodigy的一部分。
您可以通过查看文档中的大型语言模型部分来了解更多信息。
该存储库包含有关如何将零和几次学习与小注释工作相结合的示例代码,以获得具有最大效率的高质量数据集。具体来说,我们使用OpenAI可用的大型语言模型为我们提供了一组初始的预测,然后在本地机器上旋转一个天体实例来浏览这些预测并策划它们。这使我们能够很快获得一个金标准数据集,并训练适合我们确切需求和用例的较小监督模型。

确保安装Prodigy以及其他一些Python依赖性:
python -m pip install prodigy -f https://[email protected]
python -m pip install -r requirements.txt用XXXX-XXXX-XXXX-XXXX是您的个人神秘许可证密钥。
然后,从OpenAi.com创建一个新的API密钥或获取现有的API密钥。记录秘密密钥以及组织密钥,并确保将其作为环境变量可用。例如,将它们设置在根目录中的.env文件中:
OPENAI_ORG = "org-..."
OPENAI_KEY = "sk-..."
ner.openai.correct :零或几次学习的NER注释此食谱标记了从大语言模型获得的实体预测,并允许您将其标记为正确,或者手动策划它们。这使您可以通过零拍或几次学习快速收集金标准数据集。这很像在prodi.gy中使用标准的ner.correct ,但是我们使用GPT-3作为后端模型来做出预测。
python -m prodigy ner.openai.correct dataset filepath labels [--options] -F ./recipes/openai_ner.py| 争论 | 类型 | 描述 | 默认 |
|---|---|---|---|
dataset | str | prodigy数据集将注释保存到。 | |
filepath | 小路 | 通往.jsonl数据的路径。数据至少应包含一个"text"字段。 | |
labels | str | 定义模型应该预测的NER标签的逗号分隔列表。 | |
--lang , -l | str | 输入数据的语言 - 将用于获得相关的令牌。 | "en" |
--segment , -S | 布尔 | 当应将示例分为句子时,要设置的标志。默认情况下,显示了完整的输入文章。 | False |
--model , -m | str | GPT-3模型用于初始预测。 | "text-davinci-003" |
--prompt_path , -p | 小路 | 通往.jinja2提示模板的路径。 | ./templates/ner_prompt.jinja2 |
--examples-path , -e | 小路 | 示例的途径以帮助定义任务。该文件可以是.yml,.yaml或.json。如果设置为None ,则应用零射击学习。 | None |
--max-examples , -n | int | 最大示例数量要包括在OpenAi提示中。如果设置为0,即使有示例可用,也始终应用零射击学习。 | 2 |
--batch-size , -b | int | 查询的批次大小发送到OpenAI API。 | 10 |
--verbose , -v | 布尔 | 标志以将额外信息打印到终端。 | False |
假设我们想从我们从烹饪子雷迪特获得的一些文本中识别出菜肴,成分和烹饪设备。我们将将文本发送到由OpenAI托管的GPT-3,并提供注释提示,向语言模型解释我们想要的预测类型。像:
From the text below, extract the following entities in the following format:
dish: <comma delimited list of strings>
ingredient: <comma delimited list of strings>
equipment: <comma delimited list of strings>
Text:
...
我们在.jinja2文件中定义了此提示的定义,该文件还描述了如何附加几次学习的示例。您可以创建自己的模板,并使用--prompt-path或-p选项将其提供给食谱。此外,使用--examples-path或-e ,您可以设置包含其他示例的.y(a)ml或.json文件的文件路径:
python -m prodigy ner.openai.correct my_ner_data ./data/reddit_r_cooking_sample.jsonl " dish,ingredient,equipment " -p ./templates/ner_prompt.jinja2 -e ./examples/ner.yaml -n 2 -F ./recipes/openai_ner.py从OpenAI API接收结果后,Prodigy配方将预测转换为可以用Prodigy渲染的注释任务。该任务甚至显示了我们从语言模型中获得的原始提示以及原始答案。

在这里,我们看到该模型从一开始就可以正确识别菜肴,成分和烹饪设备!
该食谱还提供--verbose或-v选项,其中包括收到流量时终端上的确切提示和响应。请注意,由于对API的请求进行了批处理,因此您可能需要稍微滚动一点才能找到当前的提示。
在某个时候,您可能会在OpenAI语言模型的预测中注意到一个错误。例如,我们注意到在此示例中识别烹饪设备的错误:

如果您看到这些系统错误,则可以通过纠正示例,然后在Prodigy UI右上方选择小的“标志”图标来将预测引导到正确的方向:

一旦您在Prodigy接口上击中Accept ,标记的示例将自动拾取,并将作为提示的一部分发送到OpenAI API的示例。
笔记
由于Prodigy批次批量这些请求,因此在将下一批提示发送到OpenAI之后,提示将稍有延迟更新。您可以尝试使批处理大小(--batch-size或-b)较小以使更改更早生效,但这可能会对注释工作流的速度产生负面影响。
ner.openai.fetch :提取示例ner.openai.correct食谱在注释时从OpenAI中获取了示例,但我们还提供了一个可以预先获取大量示例的食谱。
python -m prodigy ner.openai.fetch input_data.jsonl predictions.jsonl " dish,ingredient,equipment " -F ./recipes/ner.py这将创建一个可以加载的ner.manual配方的predictions.jsonl 。
请注意,OpenAI API一次要求过多数据时可能会返回“ 429请求太多”错误 - 在这种情况下,最好一次确保您一次仅请求100个左右的示例。
策划了一组预测后,您可以以db-out导出结果:
python -m prodigy db-out my_ner_data > ner_data.jsonl导出的注释的格式包含您在下游训练较小模型所需的所有数据。数据集中的每个示例都包含原始文本,令牌,跨度注释表示实体等。
您还可以使用数据data-to-spacy导出到Spacy的二进制格式。这种格式使您可以作为Spacy Doc对象加载注释,这对于进一步转换可以方便。 data-to-spacy命令还使使用Spacy训练NER模型变得容易。首先,您导出数据,将火车数据指定为总计的20%:
python -m prodigy data-to-spacy ./data/annotations/ --ner my_ner_data -es 0.2然后,您可以用Spacy或Prodigy训练模型:
python -m spacy train ./data/annotations/config.cfg --paths.train ./data/annotations/train.spacy --paths.dev ./data/annotations/dev.spacy -o ner-model这将将模型保存到ner-model/目录。
我们还提供了一个实验脚本,以加载.spacy二进制格式,并使用HuggingFace transformers库来训练模型。您可以使用刚导出的相同数据并像这样运行脚本:
# First you need to install the HuggingFace library and requirements
pip install -r requirements_train.txt
python ./scripts/train_hf_ner.py ./data/annotations/train.spacy ./data/annotations/dev.spacy -o hf-ner-model所得模型将保存到hf-ner-model/目录。
textcat.openai.correct :零或几次学习的TextCat注释此食谱使我们能够在大型语言模型的帮助下更快地对文本进行分类。它还提供了解释为什么选择特定标签的“原因”。
python -m prodigy textcat.openai.correct dataset filepath labels [--options] -F ./recipes/openai_textcat.py| 争论 | 类型 | 描述 | 默认 |
|---|---|---|---|
dataset | str | prodigy数据集将注释保存到。 | |
filepath | 小路 | 通往.jsonl数据的路径。数据至少应包含一个"text"字段。 | |
labels | str | 定义文本分类标签的逗号分隔列表该模型应该预测。 | |
--lang , -l | str | 输入数据的语言 - 将用于获得相关的令牌。 | "en" |
--segment , -S | 布尔 | 当应将示例分为句子时,要设置的标志。默认情况下,显示了完整的输入文章。 | False |
--model , -m | str | GPT-3模型用于初始预测。 | "text-davinci-003" |
--prompt-path , -p | 小路 | 通往.jinja2提示模板的路径。 | ./templates/textcat_prompt.jinja2 |
--examples-path , -e | 小路 | 示例的途径以帮助定义任务。该文件可以是.yml,.yaml或.json。如果设置为None ,则应用零射击学习。 | None |
--max-examples , -n | int | 最大示例数量要包括在OpenAi提示中。如果设置为0,即使有示例可用,也始终应用零射击学习。 | 2 |
--batch-size , -b | int | 查询的批次大小发送到OpenAI API。 | 10 |
--exclusive-classes , -E | 布尔 | 标志以使分类任务排他性。 | False |
--verbose , -v | 布尔 | 标志以将额外信息打印到终端。 | False |
textcat配方可用于二进制,多类和多标签文本分类。您可以通过在--labels参数中传递适当数量的标签来设置此设置;例如,通过单个标签将其变成二进制分类,依此类推。我们将在程序中讨论每个部分。
假设我们想知道是否有一个特定的Reddit评论在谈论食物食谱。我们将将文本发送到GPT-3,并提供指示我们想要的预测的提示。
From the text below, determine wheter or not it contains a recipe. If it is a
recipe, answer "accept." If it is not a recipe, answer "reject."
Your answer should only be in the following format:
answer: <string>
reason: <string>
Text:
对于二进制分类,我们希望GPT-3如果给定文本是食物配方,否则拒绝“接受”。然后在UI中突出显示GPT-3的建议。我们可以按Accept (Check Mark)按钮将文本作为正面示例包括在内,或者按拒绝(Cross Mark)按钮,如果是一个负示例。
python -m prodigy textcat.openai.correct my_binary_textcat_data data/reddit_r_cooking_sample.jsonl --labels recipe -F recipes/openai_textcat.py
现在,假设我们要将Reddit注释分类为食谱,反馈或问题。我们可以编写以下提示:
Classify the text below to any of the following labels: recipe, feedback, question.
The task is exclusive, so only choose one label from what I provided.
Your answer should only be in the following format:
answer: <string>
reason: <string>
Text:
然后,我们可以使用此食谱来通过将三个标签传递给--labels参数来处理多标签和多类案例。我们还应该设置--exclusive-classes标志以渲染单选ui:
python -m prodigy textcat.openai.correct my_multi_textcat_data data/reddit_r_cooking_sample.jsonl
--labels recipe,feedback,question
--exclusive-classes
-F recipes/openai_textcat.py
我们将这些提示写为.jinja2模板,也可以以几次学习的示例进行示例。您可以创建自己的模板,并使用--prompt-path或-p选项将其提供给食谱。此外,使用--examples-path或-e ,您可以设置包含其他示例的.y(a)ml或.json文件的文件路径。您还可以在这些示例中添加上下文,因为我们观察到它可以改善输出:
python -m prodigy textcat.openai.correct my_binary_textcat_data
./data/reddit_r_cooking_sample.jsonl
--labels recipe
--prompt-path ./templates/textcat_prompt.jinja2
--examples-path ./examples/textcat_binary.yaml -n 2
-F ./recipes/openai_textcat.py与NER食谱类似,此食谱还将预测转换为可以用Prodigy渲染的注释任务。对于二进制分类,我们将classification接口与自定义HTML元素一起使用,而对于多类或多类文本分类,我们使用了choice注释接口。请注意,我们在UI中包括原始提示和OpenAI响应。
最后,您可以使用--verbose或-v标志在终端上显示确切的提示和响应。请注意,由于对API的请求进行了批处理,因此您可能需要稍微滚动一点才能找到当前的提示。
与NER配方类似,您还可以通过纠正示例,然后在Prodigy UI右上角选择小“标志”图标来将预测引导到正确的方向:

点击Prodigy界面上的“接受”按钮后,将在提示的一部分中拾取标记的示例并将其添加到发送到OpenAI API的几个示例中。
笔记
由于Prodigy批次批量这些请求,因此在将下一批提示发送到OpenAI之后,提示将稍有延迟更新。您可以尝试使批处理大小(--batch-size或-b)较小以使更改更早生效,但这可能会对注释工作流的速度产生负面影响。
textcat.openai.fetch :获取文本分类示例textcat.openai.fetch食谱使我们能够预先获取大量示例。当您使用高度影响的数据并且仅对罕见示例感兴趣时,这很有帮助。
python -m prodigy textcat.openai.fetch input_data.jsonl predictions.jsonl --labels Recipe -F ./recipes/openai_textcat.py这将创建一个可以使用textcat.manual配方加载的predictions.jsonl文件。
请注意,OpenAI API一次要求时可能会返回“ 429请求”错误 - 在这种情况下,最好确保您一次仅请求100个左右的示例,并查看API的速率限制。
textcat.openai.fetch食谱适合与存在严重类失衡的数据集。通常,您需要找到稀有类的示例,而不是注释随机样本。从那里,您想将它们置于训练一个体面的模型等。
这是像OpenAI这样的大型语言模型可能会有所帮助的地方。
使用REDDIT R/烹饪数据集,我们提示Openai寻找类似于食物食谱的评论。我们没有注释10,000个示例,而是运行了textcat.openai.fetch并获得了145个积极的类。在这145个示例中,有114个是真正的阳性(精度为79%)。然后,我们检查了1,000个负面示例,并发现了12例假阴性病例(98%的召回)。
理想情况下,一旦我们完全注释了数据集,我们就可以训练一种监督模型,该模型比依靠零射击预测生产要好。运行成本很低,更容易管理。
策划了一组预测后,您可以以db-out导出结果:
python -m prodigy db-out my_textcat_data > textcat_data.jsonl导出的注释的格式包含您在下游训练较小模型所需的所有数据。数据集中的每个示例都包含原始文本,令牌,跨度注释表示实体等。
您还可以使用数据data-to-spacy导出到Spacy的二进制格式。这种格式使您可以作为Spacy Doc对象加载注释,这对于进一步转换可以方便。 data-to-spacy命令还使用Spacy训练文本分类模型变得容易。首先,您导出数据,将火车数据指定为总计的20%:
# For binary textcat
python -m prodigy data-to-spacy ./data/annotations/ --textcat my_textcat_data -es 0.2
# For multilabel textcat
python -m prodigy data-to-spacy ./data/annotations/ --textcat-multilabel my_textcat_data -es 0.2然后,您可以用Spacy或Prodigy训练模型:
python -m spacy train ./data/annotations/config.cfg --paths.train ./data/annotations/train.spacy --paths.dev ./data/annotations/dev.spacy -o textcat-model这将将模型保存到textcat-model/ Directory中。
terms.openai.fetch :根据查询获取短语和术语该食谱生成了从大语言模型获得的术语和短语。这些术语可以策划并将其变成模式文件,这可以帮助下游注释任务。
python -m prodigy terms.openai.fetch query filepath [--options] -F ./recipes/openai_terms.py| 争论 | 类型 | 描述 | 默认 |
|---|---|---|---|
query | str | 查询发送到Openai | |
output_path | 小路 | 保存输出的路径 | |
--seeds , -s | str | 一个或多个分离的种子短语。 | "" |
--n , -n | int | 生成的最少项目数量 | 100 |
--model , -m | str | GPT-3用于完成的型号 | "text-davinci-003" |
--prompt-path , -p | 小路 | 通往jinja2提示模板的路径 | templates/terms_prompt.jinja2 |
--verbose , -v | 布尔 | 将额外信息打印到终端 | False |
--resume , -r | 布尔 | 通过从输出文件中加载文本示例中的恢复 | False |
--progress , -pb | 布尔 | 打印食谱的进度。 | False |
--temperature , -t | 漂浮 | OpenAI温度参数 | 1.0 |
--top-p , --tp | 漂浮 | OpenAI TOP_P参数 | 1.0 |
--best-of , -bo | int | openai best_of param” | 10 |
--n-batch , -nb | int | Openai批处理大小参数 | 10 |
--max-tokens , -mt | int | 最大令牌要生成每个通话 | 100 |
假设您有兴趣检测文本中的滑板技巧,那么您可能想从已知技巧的术语列表开始。您可能需要从以下查询开始:
# Base behavior, fetch at least 100 terms/phrases
python -m prodigy terms.openai.fetch " skateboard tricks " tricks.jsonl --n 100 --prompt-path templates/terms_prompt.jinja2 -F recipes/openai_terms.py这将产生一个提示,该提示要求尝试生成至少100个“滑板技巧”的示例。 OpenAI可以生成的代币数量有一个上限,但是此食谱将尝试继续收集条款,直到达到指定的金额为止。
如果您想更精确,则可以选择使查询更加精心详细,但也可以选择通过--seeds添加一些种子术语。这些将作为开始示例,以帮助将Openai转向正确的方向。
# Base behavior but with seeds
python -m prodigy terms.openai.fetch " skateboard tricks " tricks.jsonl --n 100 --seeds " kickflip,ollie " --prompt-path templates/terms_prompt.jinja2 -F recipes/openai_terms.py收集许多示例可能需要一段时间,因此随着请求的发送,通过--progress展示进度可能会有所帮助。
# Adding progress output as we wait for 500 examples
python -m prodigy terms.openai.fetch " skateboard tricks " tricks.jsonl --n 500 --progress --seeds " kickflip,ollie " --prompt-path templates/terms_prompt.jinja2 -F recipes/openai_terms.py收集了一些示例后,您可能需要生成更多。您可以选择从以前的输出文件中继续。这将有效地将这些例子重新使用作为提示的种子。
# Use the `--resume` flag to re-use previous examples
python -m prodigy terms.openai.fetch " skateboard tricks " tricks.jsonl --n 50 --resume --prompt-path templates/terms_prompt.jinja2 -F recipes/openai_terms.py食谱完成后,您将有一个tricks.jsonl文件,其中具有如下的内容:
{ "text" : " pop shove it " , "meta" :{ "openai_query" : " skateboard tricks " }}
{ "text" : " switch flip " , "meta" :{ "openai_query" : " skateboard tricks " }}
{ "text" : " nose slides " , "meta" :{ "openai_query" : " skateboard tricks " }}
{ "text" : " lazerflip " , "meta" :{ "openai_query" : " skateboard tricks " }}
{ "text" : " lipslide " , "meta" :{ "openai_query" : " skateboard tricks " }}
...现在,您在磁盘上有一个tricks.jsonl文件,其中包含滑板技巧,但是您不能假设所有这些都是准确的。下一步将是查看术语,您可以使用textcat.manual 。
# The tricks.jsonl was fetched from OpenAI beforehand
python -m prodigy textcat.manual skateboard-tricks-list tricks.jsonl --label skateboard-tricks这会生成一个看起来像这样的接口:

您可以手动接受或拒绝每个示例,当您完成注释后,可以通过terms.to-patterns带注释的文本导出到模式文件中。
# Generate a `patterns.jsonl` file.
python -m prodigy terms.to-patterns skateboard-tricks-list patterns.jsonl --label skateboard-tricks --spacy-model blank:en完成食谱后,您将有一个patterns.jsonl文件,其中具有类似的内容:
{ "label" : " skateboard-tricks " , "pattern" :[{ "lower" : " pop " },{ "lower" : " shove " },{ "lower" : " it " }]}
{ "label" : " skateboard-tricks " , "pattern" :[{ "lower" : " switch " },{ "lower" : " flip " }]}
{ "label" : " skateboard-tricks " , "pattern" :[{ "lower" : " nose " },{ "lower" : " slides " }]}
{ "label" : " skateboard-tricks " , "pattern" :[{ "lower" : " lazerflip " }]}
{ "label" : " skateboard-tricks " , "pattern" :[{ "lower" : " lipslide " }]}
...Openai对及时尺寸有严格的限制。您的及时要及时大于4079代币。不幸的是,这意味着您可以生成的术语列表的大小有限制。当发生这种情况时,食谱将报告一个错误,但是很高兴意识到此限制。
ab.openai.prompts :提示的A/B评估该食谱的目的是快速允许某人以可量化和盲目的方式比较两个提示的输出质量。
python -m prodigy ab.openai.prompts dataset inputs_path display_template_path prompt1_template_path prompt2_template_path [--options] -F ./recipes/openai_ab.py| 争论 | 类型 | 描述 | 默认 |
|---|---|---|---|
dataset | str | Prodigy数据集可将答案保存到 | |
inputs_path | 小路 | 通往JSONL输入的路径 | |
display_template_path | 小路 | 总结参数的模板 | |
prompt1_template_path | 小路 | 通往第一个Jinja2提示模板的路径 | |
prompt2_template_path | 小路 | 通往第二个Jinja2提示模板的路径 | |
--model , -m | str | GPT-3用于完成的型号 | "text-davinci-003" |
--batch-size , -b | int | 批次大小发送到OpenAI API | 10 |
--verbose , -v | 布尔 | 将额外信息打印到终端 | False |
--no-random , -NR | 布尔 | 不要随机化哪种注释显示为正确 | False |
--repeat , -r | int | 多久向Openai发送相同提示的多久一次 | 1 |
例如,让我们尝试产生幽默的狂热。为此,我们首先需要构造两个表示发送到OpenAI的提示的Jinja文件。
templates/ab/prompt1.jinja2 Write a haiku about {{topic}}.
templates/ab/prompt2.jinja2 Write an incredibly hilarious haiku about {{topic}}. So funny!
您可以通过构造带有所需参数的.jsonl文件来为这些提示提供变量。在这种情况下,我们需要确保考虑{{topic}} 。
这是一个可以工作的示例.jsonl文件。
data/ab_example.jsonl{ "id" : 0 , "prompt_args" : { "topic" : " star wars " }}
{ "id" : 0 , "prompt_args" : { "topic" : " kittens " }}
{ "id" : 0 , "prompt_args" : { "topic" : " the python programming language " }}
{ "id" : 0 , "prompt_args" : { "topic" : " maths " }}笔记
prompt_args下的所有参数将通过以渲染Jinja模板。id是强制性的,可用于以后分析中识别组。
我们几乎可以评估了,但是此食谱需要一个最终的Jinja2模板。这个不会用于生成提示,但它将生成一个有用的标题,以提醒当前任务的注释者。这是这样的模板的示例。
templates/ab/input.jinja2 A haiku about {{topic}}.
当您将所有这些模板放在一起时,您可以开始注释。下面的命令启动注释接口,还使用--repeat 4选项。这将确保每个主题至少将其提示至少4次。
python -m prodigy ab.openai.prompts haiku data/ab_example.jsonl templates/ab/input.jinja2 templates/ab/prompt1.jinja2 templates/ab/prompt2.jinja2 --repeat 5 -F recipes/openai_ab.py
这就是注释接口的样子:

当您查看此界面时,您会注意到标题模板是渲染的,并且可以从两个选项中选择。这两个选项都是由两个提示模板生成的OpenAI的响应。您还可以在选择菜单的右下角看到prompt_args 。
从这里,您可以注释您喜欢的示例并收集可能帮助您确定哪个提示最好的数据。
注释后,您将概述结果概述。
=========================== Evaluation results ===========================
✔ You preferred prompt1.jinja2
prompt1.jinja2 11
prompt2.jinja2 5
但是您也可以从数据库中获取原始注释以进行进一步分析。
python -m prodigy db-out haiku
有很多有趣的后续实验,以及许多将基本思想调整到不同任务或数据集的方法。我们也有兴趣尝试不同的提示。目前尚不清楚要求注释的格式可能会改变模型的预测,或者是否有较短的提示也可能会执行。我们还想运行一些端到端的实验。