使用 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度。有点咳嗽,吃什么药最好