基于 OpenAI 实现文本相似度匹配

使用 embeddings 可以实现如下的一些 NLP 任务:

  1. 搜索(根据与查询字符串的相关性对结果进行排名)
  2. 聚类(文本字符串按相似度分组)
  3. 推荐(推荐具有相关文本字符串的项)
  4. 异常检测(识别相关性很小的异常值)
  5. 多样性测量(分析相似度分布)
  6. 分类(文本字符串根据它们最相似的标签进行分类)

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度。有点咳嗽,吃什么药最好
未经允许不得转载:一亩三分地 » 基于 OpenAI 实现文本相似度匹配
评论 (0)

1 + 9 =