如何确保答案来自自定义(微调)数据集?

Mos*_*she 8 customization nlp openai-api gpt-3

我使用带有“提示”和“完成”的自定义文本来训练新模型。

这是我用来根据数据创建自定义模型的教程:

beta.openai.com/docs/guides/fine-tuning/advanced-usage

然而,即使在训练模型并向模型发送提示文本之后,我仍然得到并不总是适合我的通用结果。

如何确保提示的完成结果仅来自我用于模型的文本,而不是来自通用 OpenAI 模型?

我可以使用一些标志来消除通用模型的结果吗?

Rok*_*nko 28

语义搜索示例

以下是使用 OpenAI API 基于嵌入的语义搜索的示例。


错误的目标:如果提示与微调数据集中的提示类似,OpenAI API 应该从微调数据集中回答

这是完全错误的逻辑。忘记微调。正如OpenAI官方文档中所述:

微调可让您通过 API 提供以下功能,从而更充分地利用可用模型:

  1. 比即时设计更高质量的结果
  2. 能够训练超出提示范围的示例
  3. 由于提示较短而节省了代币
  4. 更低的延迟请求

微调通过训练超出提示范围的更多示例来改进小样本学习,让您在大量任务上取得更好的结果

微调并不是用微调数据集中的特定答案来回答特定问题。换句话说,经过微调的模型不知道对于给定的问题应该给出什么答案。它无法读懂你的想法。您将根据微调模型拥有的所有知识得到答案,其中: knowledge of a fine-tuned model= default knowledge(即模型在微调之前拥有的知识)+ fine-tuning knowledge(即您通过微调添加到模型中的知识)调)。

尽管GPT-3模型有很多常识,但有时我们希望模型能够针对给定的具体问题给出具体的答案(即“事实”)。如果微调不是正确的方法,那么什么才是正确的方法呢?


正确的目标:当被问到“事实”时用“事实”回答,否则用 OpenAI API 回答

正确的方法是基于嵌入向量的语义搜索,我们使用余弦相似度相互比较,以找到给定特定问题的“事实”。请参阅下面的示例及其详细说明。

注意:为了更好(视觉)理解,以下代码在Jupyter中运行和测试。

第 1 步:创建一个.csv包含“事实”的文件

为了简单起见,我们添加两家公司(即 ABC 和 XYZ)的内容。我们案例中的内容将是对公司的一句话描述。

公司.csv

CSV

运行print_dataframe.ipynb以打印数据帧。

print_dataframe.ipynb

import pandas as pd

df = pd.read_csv('companies.csv')
df
Run Code Online (Sandbox Code Playgroud)

我们应该得到以下输出:

木星1


第 2 步:计算每个“事实”的嵌入向量

嵌入是一个数字向量,可以帮助我们理解文本在语义上的相似或不同。两个嵌入彼此越接近,它们的内容就越相似(来源)。

我们首先测试Embeddings 端点get_embedding.ipynb使用输入运行This is a test

注意:对于 Embeddings 端点,该参数prompt称为input

get_embedding.ipynb

import openai
import os

openai.api_key = os.getenv('OPENAI_API_KEY')

def get_embedding(model: str, text: str) -> list[float]:
    result = openai.Embedding.create(
      model = model,
      input = text
    )
    return result['data'][0]['embedding']

print(get_embedding('text-embedding-ada-002', 'This is a test'))
Run Code Online (Sandbox Code Playgroud)

我们应该得到以下输出:

木星2

我们在上面的屏幕截图中看到的是This is a test一个嵌入向量。更准确地说,我们得到一个1536维的嵌入向量(即里面有1536个数字)。您可能熟悉 3 维空间(即 X、Y、Z)。嗯,这是一个1536维的空间,这是非常难以想象的。

此时我们需要了解两件事:

  • 为什么我们需要将文本转换为嵌入向量(即数字)?随后,我们可以比较嵌入向量并找出两个文本的相似程度。我们无法比较文本本身。
  • 为什么嵌入向量中有 1536 个数字?因为该text-embedding-ada-002模型的输出维度为1536。它是预先定义的。

现在我们可以为每个“事实”创建一个嵌入向量。跑步get_all_embeddings.ipynb

get_all_embeddings.ipynb

import openai
from openai.embeddings_utils import get_embedding
import pandas as pd
import os

openai.api_key = os.getenv('OPENAI_API_KEY')

df = pd.read_csv('companies.csv')

df['embedding'] = df['content'].apply(lambda x: get_embedding(x, engine = 'text-embedding-ada-002'))
df.to_csv('companies_embeddings.csv')
Run Code Online (Sandbox Code Playgroud)

上面的代码将获取第一家公司(即x),获取其'content'(即“事实”)并get_embedding使用text-embedding-ada-002模型应用该函数。它将把第一家公司的嵌入向量保存在名为 的新列中'embedding'。然后会取第二家公司、第三家公司、第四家公司等等。最后,代码会自动生成一个.csv名为companies_embeddings.csv.

将嵌入向量保存在本地(即在文件中.csv)意味着我们不必每次需要它们时都调用 OpenAI API。我们为给定的“事实”计算一次嵌入向量,仅此而已。

运行print_dataframe_embeddings.ipynb以打印包含名为 的新列的数据框'embedding'

print_dataframe_embeddings.ipynb

import pandas as pd
import numpy as np

df = pd.read_csv('companies_embeddings.csv')
df['embedding'] = df['embedding'].apply(eval).apply(np.array)
df
Run Code Online (Sandbox Code Playgroud)

我们应该得到以下输出:

木星3

第 3 步:计算输入的嵌入向量,并将其与companies_embeddings.csv使用余弦相似度得到的嵌入向量进行比较

我们需要计算输入的嵌入向量,以便我们可以将输入与给定的“事实”进行比较,并查看这两个文本的相似程度。实际上,我们将输入的嵌入向量与“事实”的嵌入向量进行比较。然后我们将输入与第二个“事实”、第三个“事实”、第四个“事实”等进行比较。运行get_cosine_similarity.ipynb

get_cosine_similarity.ipynb

import openai
from openai.embeddings_utils import cosine_similarity
import pandas as pd
import os

openai.api_key = os.getenv('OPENAI_API_KEY')

my_model = 'text-embedding-ada-002'
my_input = '<INSERT_INPUT_HERE>'

def get_embedding(model: str, text: str) -> list[float]:
    result = openai.Embedding.create(
      model = my_model,
      input = my_input
    )
    return result['data'][0]['embedding']

input_embedding_vector = get_embedding(my_model, my_input)

df = pd.read_csv('companies_embeddings.csv')
df['embedding'] = df['embedding'].apply(eval).apply(np.array)
df['similarity'] = df['embedding'].apply(lambda x: cosine_similarity(x, input_embedding_vector))
df
Run Code Online (Sandbox Code Playgroud)

上面的代码将获取输入并将其与第一个事实进行比较。它将把计算出的两者相似度保存在名为 的新列中'similarity'。然后它将采取第二个事实、第三个事实、第四个事实等。

如果my_input = 'Tell me something about company ABC'

ABC

如果my_input = 'Tell me something about company XYZ'

XYZ

如果my_input = 'Tell me something about company Apple'

苹果

我们可以看到,当我们Tell me something about company ABC作为输入给出时,它与第一个“事实”最相似。当我们Tell me something about company XYZ作为输入给出时,它与第二个“事实”最相似。然而,如果我们Tell me something about company Apple作为输入给出,它与这两个“事实”中的任何一个最不相似。

第 4 步:如果相似度高于我们的阈值,则使用最相似的“事实”进行回答,否则使用 OpenAI API 进行回答

让我们将相似度阈值设置为>= 0.9。如果相似度为 ,下面的代码应使用最相似的“事实”进行回答>= 0.9,否则使用 OpenAI API 进行回答。跑步get_answer.ipynb

获取答案.ipynb

# Imports
import openai
from openai.embeddings_utils import cosine_similarity
import pandas as pd
import numpy as np
import os

# Use your API key
openai.api_key = os.getenv('OPENAI_API_KEY')

# Insert OpenAI text embedding model and input
my_model = 'text-embedding-ada-002'
my_input = '<INSERT_INPUT_HERE>'

# Calculate embedding vector for the input using OpenAI Embeddings endpoint
def get_embedding(model: str, text: str) -> list[float]:
    result = openai.Embedding.create(
      model = my_model,
      input = my_input
    )
    return result['data'][0]['embedding']

# Save embedding vector of the input
input_embedding_vector = get_embedding(my_model, my_input)

# Calculate similarity between the input and "facts" from companies_embeddings.csv file which we created before
df = pd.read_csv('companies_embeddings.csv')
df['embedding'] = df['embedding'].apply(eval).apply(np.array)
df['similarity'] = df['embedding'].apply(lambda x: cosine_similarity(x, input_embedding_vector))

# Find the highest similarity value in the dataframe column 'similarity'
highest_similarity = df['similarity'].max()

# If the highest similarity value is equal or higher than 0.9 then print the 'content' with the highest similarity
if highest_similarity >= 0.9:
    fact_with_highest_similarity = df.loc[df['similarity'] == highest_similarity, 'content']
    print(fact_with_highest_similarity)
# Else pass input to the OpenAI Completions endpoint
else:
    response = openai.Completion.create(
      model = 'text-davinci-003',
      prompt = my_input,
      max_tokens = 30,
      temperature = 0
    )
    content = response['choices'][0]['text'].replace('\n', '')
    print(content)
Run Code Online (Sandbox Code Playgroud)

如果my_input = 'Tell me something about company ABC'且阈值为>= 0.9,我们应该从 中得到以下答案companies_embeddings.csv

答案1

如果my_input = 'Tell me something about company XYZ'且阈值为>= 0.9,我们应该从 中得到以下答案companies_embeddings.csv

答案2

如果my_input = 'Tell me something about company Apple'阈值为,我们应该从 OpenAI API>= 0.9得到以下答案:

答案3


其他提示和技巧

您可以使用Pinecone来存储嵌入向量,如官方Pinecone 文章中所述:

嵌入由人工智能模型(例如大型语言模型)生成,并具有大量属性或特征,这使得它们的表示难以管理。在人工智能和机器学习的背景下,这些特征代表了数据的不同维度,这对于理解模式、关系和底层结构至关重要。

这就是为什么我们需要专门为处理此类数据而设计的专用数据库。像 Pinecone 这样的矢量数据库通过为嵌入提供优化的存储和查询功能来满足这一要求。向量数据库具有独立向量索引所缺乏的传统数据库的功能,以及传统基于标量的数据库所缺乏的处理向量嵌入的专业性。

截图 松果