使用 embeddings 可以实现如下的一些 NLP 任务:
- 搜索(根据与查询字符串的相关性对结果进行排名)
- 聚类(文本字符串按相似度分组)
- 推荐(推荐具有相关文本字符串的项)
- 异常检测(识别相关性很小的异常值)
- 多样性测量(分析相似度分布)
- 分类(文本字符串根据它们最相似的标签进行分类)
Doc:https://platform.openai.com/docs/guides/embeddings/what-are-embeddings
OpenAI 目前提供很多种用于句向量计算的模型,并推荐我们使用一个第二代码的模型,名字为:text-embedding-ada-002,该模型能够用于几乎所有的场景。该模型支持的最长输入长度为:8192,得到的向量维度为:1536。
关于该模型的说明:https://openai.com/blog/new-and-improved-embedding-model
下面是获得输入向量的示例代码:
import requests
import json
def get_embeddings(sentence):
request_url = 'https://api.openai.com/v1/embeddings'
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + open('openai_api_key').read()}
data = json.dumps({"model": "text-embedding-ada-002", 'input': sentence})
response = requests.post(request_url, headers=headers, data=data)
response = json.loads(response.text)
sentence_embedding = response['data'][0]['embedding']
print('潜入向量维度:', len(sentence_embedding))
return sentence_embedding
if __name__ == '__main__':
result = get_embeddings('根据输入文本生成句子嵌入向量')
print(result)
程序输出结果:
潜入向量维度: 1536
[-0.026847607, -0.0045562806, -0.009105458...]
需要注意的是,Embedding 模型是不能够下载到本地,并且 OpenAI 官方对 API 的访问作出了一系列限制,即:我们小数量去测试使用是 OK,OpenAI 速率限制如下:
RPM 表示每分钟的请求次数,TPM 表示每分钟请求的 Token 数量。
用在生产环境下是需要付费的。付费是按照每次请求和响应的 Token 数量来计算的,价格如下:
价格链接为:https://openai.com/pricing
如果需要预估下自己的数据集中大概有多少个 Token,可以使用 OpenAI 的分词器统计一下,首先使用下面的命令安装,注意 tiktoken 需要 Python3.8 版本:
pip install tiktoken
示例代码如下:
import tiktoken
def test():
# 先获得模型使用的分词器
encoding = tiktoken.get_encoding('cl100k_base')
# 定义输入句子
inputs = '根据输入文本生成句子嵌入向量'
tokens = encoding.encode(inputs)
print('Token 内容:', tokens)
print('Token 数量:', len(tokens))
if __name__ == '__main__':
test()
程序输出结果:
Token 内容: [15308, 117, 16423, 32296, 17161, 22656, 45059, 5877, 98, 45829, 161, 113, 234, 17701, 70141, 33857]
Token 数量: 16
不同的模型对应的分词器的名称如下:
更多关于 tiktoken 的内容链接为:https://github.com/openai/openai-cookbook/tree/main/examples,链接中的 How_to_count_tokens_with_tiktoken.ipynb 文件有详细的描述。
接下来,我们实现通过句向量匹配问题,实现代码如下:
import requests
import openai
import tenacity
import torch
import pickle
import json
import torch
import pandas as pd
import numpy as np
from tqdm import tqdm
openai.api_key = open('openai_api_key').read()
@tenacity.retry(wait=tenacity.wait_fixed(5))
def get_embedding(question):
outputs = openai.Embedding.create(model='text-embedding-ada-002', input=question)
return outputs['data'][0]['embedding']
def generate_embedding():
trains = pd.read_csv('data/question.csv', usecols=['question']).to_numpy().tolist()
trains = [train[0] for train in trains][:1000]
progress = tqdm(range(len(trains)), desc='generate embedding1')
question_embeddings = []
for question in trains:
embedding = get_embedding(question)
question_embeddings.append(embedding)
progress.update()
progress.close()
pickle.dump(question_embeddings, open('data/question_embeddings.pkl', 'wb'))
open('data/questions_selected.txt', 'w').write('\n'.join(trains))
def similarity_matching():
embeddings = pickle.load(open('data/question_embeddings.pkl', 'rb'))
message_inputs = '今天早上突然发烧了,浑身酸疼,吃点啥药啊?'
print('输入问题:', message_inputs)
print('-' * 60)
message_embeds = get_embedding(message_inputs)
questions = open('data/questions_selected.txt').readlines()
question_indexes = list(range(len(questions)))
question_scores = []
for embed in embeddings:
score = torch.cosine_similarity(torch.tensor(), torch.tensor([message_embeds]))
question_scores.append(score.item())
sorted_indexes = np.argsort(-np.array(question_scores))[:5]
print('相似问题:')
for index in sorted_indexes:
print(round(question_scores[index], 4), questions[index].strip())
if __name__ == '__main__':
# generate_embedding()
similarity_matching()
程序输出结果:
输入问题: 今天早上突然发烧了,浑身酸疼,吃点啥药啊?
------------------------------------------------------------
相似问题:
0.8755 全身发烫,头痛,总觉得冷,四肢无力,感觉身上酸痛
0.8744 发烧,头疼,恶心,呕吐打什么针好的快
0.8735 头有点胀痛,全身无力,脖子和腰都很酸痛一次喝酒后吹风,然后就发烧大病3天,之后身体就觉得没以前好,不知是什么症状。
0.8732 发烧全身发烫怎么办?能不能开空调的啊??开始是全身无力,吃了药好了点。晚上睡觉空调开起来的,早上身体很烫。
0.8718 儿童发烧38。3度。有点咳嗽,吃什么药最好