如何通过Python使用OpenAI GPT(#8:文本嵌入机制)

您所在的位置:网站首页 python中concatenate函数 如何通过Python使用OpenAI GPT(#8:文本嵌入机制)

如何通过Python使用OpenAI GPT(#8:文本嵌入机制)

2023-03-29 03:57| 来源: 网络整理| 查看: 265

嵌入(Embedding)概述

一句话描述这个功能:OpenAI的文本嵌入可以度量两个文本字符串有多么相似。

嵌入,一般常用于搜索查询中寻找最相关的结果,把文本内容根据相似度分组,推荐相似的内容,寻找差异最大的文本,分析文本之间彼此差异多大,对文本打标签等任务。

从实践的角度看,嵌入,是把真实世界的对象和关系表达为向量的方法。在同一个向量空间中比较两个东西有多么相似。

使用场景

OpenAI的文本嵌入可以测量文本字符串的相关性,可以用于多种目的。

下面是一些使用场景:

NLP任务,比如情感分析、语义相似度、情绪分类为机器学习的模型,比如关键词匹配、文档分类、话题建模,提供文本嵌入功能。为文本生成语言无关的表示,开展跨语言的文本比较为文本搜索引擎和自然语言理解系统提升精度通过对比用户输入的文本和一大批文本字符串,创建个性化推荐

我们可以把这些场景作如下归纳:

搜索:根据和查询语句的相关性对结果排序聚类:将文本根据其相似度进行分组推荐:推荐和文本相关的东西异常检测:识别相关性不大的异常点多样性测量:分析相似度分布分类:根据既定的标签对文本进行分类

下面是实际使用这个东西的案例(用的未必是OpenAI的):

特斯拉

非结构化数据处理起来很麻烦,从头构造一个模型来处理原始文本、图片和视频是很麻烦的。另外由于隐私限制,也不容易获得原始数据。需要许多的算力,大的数据集和较长时间,才能构建一个好的模型。

嵌入技术,可以从一个上下文(车上的图片)提取信息,用在另一个上下文中(比如游戏)。这称为迁移学习,帮我们无需大量真实世界的数据就能训练模型。

特斯拉在其自动驾驶汽车中使用了这个技术。

Kalendar AI

Kalendar AI是一款销售触达产品,使用嵌入方法,自动地从3亿多条的数据集中,匹配正确的促销策略给不同的客户。

这里的自动化依赖于客户档案的嵌入结果与销售策略进行比较,按照相似度匹配。根据OpenAI的说法,这样做相比以往的方法可以削减40%到56%的无效目标。

Notion

Notion是一个在线工具,通过OpenAI的嵌入功能提升了其搜索能力,超越了之前所用的基于关键词匹配的系统。这个新功能让Notion更好地理解其平台上内容的结构、上下文和含义,让用户可以更加准确而快速地搜索和寻找文档。

DALL-E 2

DALL-E 2是一个将文本转化为图片的系统。它使用了两个模型:Prior和Decoder。Prior接受文本标签,创建CLIP图嵌入,随后Decoder接收CLIP图嵌入,生成一幅图片。图片的尺寸在64x64到1024x1024之间。

需求

为了使用嵌入功能,你需要安装下面这些Python包:

pip install datalib matplotlib plotly scipy scikit-learn

确保你安装在了正确的虚拟开发环境中。这些包还会连带着安装pandas和Numpy这类工具。

这些包都是AI和数据科学中最常用的包:

pandas是一个快速、强大、灵活而易于使用的开源数据分析和处理工具。numpy是另一个Python库,添加了对大型多维度矩阵的支持,还包含了一批操作这些高维对象的数学函数。matplotlib是一个画图库,是numpy的扩展。plotly是一个交互式的开源的基于浏览器的图形库。scipy是一个免费开源的科学计算库。理解文本嵌入

让我们从一个具体的例子开始:

response = openai.Embedding.create( model="text-embedding-ada-002", input="I am a programmer", ) print(response)

这里我们使用的是ada,OpenAI中最好的嵌入模型。OpenAI团队推荐在几乎所有的场景中都使用text-embedding-ada-002模型,因为它更好、更便宜和更易使用。

其输出看起来像下面这样:

{ "data": [ { "embedding": [ -0.0169205479323864, -0.019740639254450798, -0.011300412937998772, -0.016452759504318237, [..] 0.003966170828789473, -0.011714739724993706 ], "index": 0, "object": "embedding" }], "model": "text-embedding-ada-002-v2", "object": "list", "usage": { "prompt_tokens": 4, "total_tokens": 4 } }

我们也可以通过这样的方式直接访问嵌入结果:

print(response["embedding"])

这个程序会输出诸如0.010284645482897758和0.013211660087108612的浮点数。

这些浮点数代表的是输入文本“I am a programmer”的嵌入结果,由OpenAI的的text-embedding-ada-002模型生成。

嵌入方法是对输入文本的一种高维表示,可以捕获其含义。它有时候也指代向量表示,或者一个嵌入向量。

一次嵌入,是使用大量的值对对象进行表示,比如文本。每个值代表对象含义的一个方面,以及对象在这个特定方面的强度。在文本的场景中,这个方面可以代表话题、情绪或者其它的语义特征。

换句话说,你需要理解,由嵌入终端生成的向量表示,是对数据的一种表达,而这种表达可以被机器学习的模型和算法理解。这是一种获取输入并把它转成模型和算法可用的格式的方法。

接下来我们看看如何在不同的场景下使用。

多个输入的嵌入

上一个例子中,我们使用了

input="I am a programmer"

也可以使用多个输入,如下:

response = openai.Embedding.create( model="text-embedding-ada-002", input=["I am a programmer", "I am a writer"], ) for data in response["data"]: print(data["embedding"])

注意,每一条输入都不应该超过8192个token的长度。

语义搜索

这一部分中我们会使用OpenAI的嵌入功能实现一个语义搜索。

这是一个基本的例子,不过后面我们还会看到许多高级的例子。

我们创建一个文件,叫做words.csv,包含一列名为text的数据,全都是随机的单词:

text apple banana cherry dog cat house car tree phone computer television book music food water sky air sun moon star ocean desk bed sofa lamp carpet window door floor ceiling wall clock watch jewelry ring necklace bracelet earring wallet key photo

在处理数据,包括csv文件的时候,pandas是一个很厉害的工具,特别适合我们现在的场景。我们使用pandas读取文件,创建dataframe。

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

dataframe是最常用的pandas对象。

pandas官方文档把dataframe描述成一个二维的标签数据结构,其中的列还可以是不同的类型。你可以把它想象成一个电子表格或者SQL表。

如果你打印df对象,可以看见这样的输出:

下一步我们要为dataframe中的每一个词获取嵌入。为此,我们不再使用openai.Embedding.create()函数,而是get_embedding。两者类似,但是前者返回包含嵌入结果的JSON,而后者直接返回嵌入结果的列表,在dataframe中更加实用。

函数工作如下:

get_embedding("Hello", engine='text-embedding-ada-002') # will return [-0.02499537356197834, -0.019351257011294365, ..etc]

我们会使用每个dataframe对象都有的apply函数,将一个函数应用到dataframe的一个轴上。

# import the function to get the embedding from openai.embeddings_utils import get_embedding # get the embedding for each word in the dataframe df['embedding'] = df['text'].apply(lambda x: get_embedding(x, engine='text-embedding-ada-002'))

现在我们的dataframe有两个轴,其一是text,其二是embedding,后者包含的是前者每一个词的嵌入。

我们把dataframe保存到另一个csv文件中:

df.to_csv('embeddings.csv')

新的文件看起来像下面这样:

它有3列:id、text和embedding。

现在让我们读取新文件,把最后一列转换成numpy数字。为什么呢?

因为下一步中我们会用到cosine_similarity函数,而其需要一个numpy的数组,而非默认的字符串。

那么为什么不使用普通的Python数组呢?

实际上,numpy的数组广泛应用于数值计算中。普通的数组对这类计算毫无帮助。此外,numpy数组的内存开销更少,速度更快。这是因为numpy数组是同构的数据类型集合,保存在连续的内存空间中,而普通的Python列表不是的。

回到我们的代码,我们通过下面的办法进行转换:

df['embedding'] = df['embedding'].apply(eval).apply(np.array)

现在我们可以等待用户输入,使用cosine_similarity函数进行语义搜索:

# get the search term from the user user_search = input('Enter a search term: ') # get the embedding for the search term user_search_embedding = get_embedding(user_search, engine='text-embedding-ada-002') # import the function to calculate the cosine similarity from openai.embeddings_utils import cosine_similarity # calculate the cosine similarity between the search term and each word in the dataframe df['similarity'] = df['embedding'].apply(lambda x: cosine_similarity(x, user_search_embedding))

上面的代码中我们可以看到3个操作:

user_search_embedding = get_embedding(user_search, engine='text-embedding-ada-002'),这一行使用get_embedding函数获取用户搜索输入user_search的嵌入结果。from openai.embeddings_utils import cosine_similarity,这一行从openai.embeddings_utils模块中导入cosine_similarity函数。它可以计算两个嵌入之间的余弦相似度。df['similarity'] = df['embedding'].apply(lambda x: cosine_similarity(x, user_search_embedding)),这一行在dataframe中新建一列,称为similarity,使用apply函数和lambda表达式计算用户搜索词和dataframe中每个词的相似度。

每一对嵌入的相似度比较结果保存在similarity列中。

完整的代码如下:

运行代码之后,我输入了“”office,这时df结构如下:

Unnamed: 0 text embedding similarity 0 apple [0.0077999732457101345, -0.02301608957350254, ... 0.830448 1 banana [-0.013975119218230247, -0.03290277719497681, ... 0.805773 2 cherry [0.006462729535996914, -0.018950263038277626, ... 0.792155 3 dog [-0.0033353185281157494, -0.017689190804958344... 0.828782 4 cat [-0.0070945825427770615, -0.017328109592199326... 0.802046 5 house [-0.007152134086936712, 0.007141574751585722, ... 0.874455 6 car [-0.0074789817444980145, -0.021566664800047874... 0.821671 7 tree [-0.0047506773844361305, -0.013216584920883179... 0.825486 8 phone [-0.0014101049164310098, -0.022890757769346237... 0.853214 9 computer [-0.003125436371192336, -0.014225165359675884,... 0.861776 10 television [-0.004810569807887077, -0.019971350207924843,... 0.799359 ......

通过similarity一列,我们看到每个词和office在语义上多么接近。这个浮点数越大,就说明其与text一列中的词越接近。

有的词,比如necklace、bracelet、earring的分数是0.77,而desk的得分是0.88。

为了让结果更加好读,我们可以根据这一列对dataframe进行排序,取最接近的10个:

# sort the dataframe by the similarity axis df = df.sort_values(by='similarity', ascending=False) df.head(10)

头部的单词如下:

Unnamed: 0 text embedding similarity 21 desk [0.012774260714650154, -0.020844005048274994, ... 0.890026 5 house [-0.007152134086936712, 0.007141574751585722, ... 0.874455 9 computer [-0.0031794828828424215, -0.014211298897862434... 0.861704 28 floor [0.018742715939879417, -0.021140681579709053, ... 0.861481 8 phone [-0.0014101049164310098, -0.022890757769346237... 0.853214 11 book [-0.006843345705419779, -0.019184302538633347,... 0.838138 24 lamp [0.006820859387516975, -0.008771182037889957, ... 0.834019 27 door [-0.004844364244490862, -0.026875808835029602,... 0.833317 40 photo [0.004297871608287096, -0.03132128715515137, -... 0.833313 13 food [0.022335752844810486, -0.02753201313316822, -... 0.831723

你还可以尝试一下别的单词,看看结果是什么样的。

余弦相似度

两个词之间的相似度是通过我们所说的【余弦相似度】来计算的。使用这个方法并不需要你理解其中的数学细节,但是如果你想深入这个领域,你可以读一下本节。跳过也没有关系,不会影响你理解和使用OpenAI的API来构建智能应用。

余弦相似度是一种计算两个向量相似度的方法。它会看两个向量(线)之间的夹角,然后进行比较。而余弦相似度指的就是两个向量的夹角的余弦。其结果是-1到1之间的值。如果向量相同,那么结果就是1;如果完全相反,那就是-1;如果呈90°,那么结果就是0。其数学公式如下:

Similarity=(A\cdot B)\div (||A|| \cdot ||B||)

A和B是向量A\cdot B 是向量乘法,把两组向量中的每个位置上的数字捉对相乘,最后把乘积加起来。||A||是向量A的长度,对向量中每个元素求平方,相加,再开根号得到。

我们考察两个向量:A = [2,3,5,2,6,7,9,2,3,4]和B = [3,6,3,1,0,9,2,3,4,5]。

下面是计算余弦相似度的Python代码:

# import numpy and norm from numpy.linalg import numpy as np from numpy.linalg import norm # define two vectors A = np.array([2,3,5,2,6,7,9,2,3,4]) B = np.array([3,6,3,1,0,9,2,3,4,5]) # print the vectors print("Vector A: {}".format(A)) print("Vector B: {}".format(B)) # calculate the cosine similarity cosine = np.dot(A,B)/(norm(A)*norm(B)) # print the cosine similarity print("Cosine Similarity between A and B: {}".format(cosine))

我们也可以使用scipy计算:

import numpy as np from scipy import spatial # define two vectors A = np.array([2,3,5,2,6,7,9,2,3,4]) B = np.array([3,6,3,1,0,9,2,3,4,5]) # print the vectors print("Vector A: {}".format(A)) print("Vector B: {}".format(B)) # calculate the cosine similarity cosine = 1 - spatial.distance.cosine(A, B) # print the cosine similarity print("Cosine Similarity between A and B: {}".format(cosine))

还可以使用scikit-learn计算:

import numpy as np from sklearn.metrics.pairwise import cosine_similarity # define two vectors A = np.array([2,3,5,2,6,7,9,2,3,4]) B = np.array([3,6,3,1,0,9,2,3,4,5]) # print the vectors print("Vector A: {}".format(A)) print("Vector B: {}".format(B)) # calculate the cosine similarity cosine = cosine_similarity([A],[B]) # print the cosine similarity print("Cosine Similarity: {}".format(cosine[0][0]))



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3