蝴蝶书--ChatGPT使用指南——相似度匹配

文本token化后需要一种方式来表示这些token,one-hot方法太生硬了,需要一个稠密表示

通过调用大模型的embedding API进行处理,在本人用过的里面,gpt支持传输多段文字,而ZHIPUAI一次只能传一个

调用代码如下:

import os
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
import openai
# OPENAI_API_KEY = "填入专属的API key"
openai.api_key = OPENAI_API_KEY
text = "我喜欢你"
model = "text-embedding-ada-002"
emb_req = openai.Embedding.create(input=[text], model=model)
emb = emb_req.data[0].embedding

在自然语言处理领域,我们一般使用cosine相似度作为语义相似度的度量,评估两个向量在语义空间上的分布情况:

from openai.embeddings_utils import get_embedding, cosine_similarity
# 注意它默认的模型是text-similarity-davinci-001,我们也可以换成text-embedding-ada-002
text1 = "我喜欢你"
text2 = "我钟意你"
text3 = "我不喜欢你"
emb1 = get_embedding(text1)
emb2 = get_embedding(text2)
emb3 = get_embedding(text3)
cosine_similarity(emb1, emb2)
0.9246855139297101
cosine_similarity(emb1, emb3)
0.8578009661644189
cosine_similarity(emb2, emb3)
0.8205299527695261

直接喂给大模型

content = "请告诉我下面三句话的相似程度:\n1. 我喜欢你。\n2. 我钟意你。\n3.我不喜欢你。\n"
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo", 
    messages=[{"role": "user", "content": content}]
)

response.get("choices")[0].get("message").get("content")

QA任务

把QA库进行embedding,把新的问题embedding之后去进行相似度检索,得出answer

聚类

对文本embedding之后,为了方便显示,对向量进行降维,可视化可以看到embedding做到了聚类的效果

推荐

推荐相比QA要更复杂一些,主要包括以下几个方面:

  • 刚开始用户没有记录时的推荐(一般行业称为冷启动问题)。
  • 除了相似还有其他要考虑的因素:比如热门内容、新内容、内容多样性、随时间变化的兴趣变化等等。
  • 编码(Embedding输入)问题:我们应该取标题呢,还是文章,还是简要描述或者摘要,还是都要计算。
  • 规模问题:推荐面临的量级一般会远超QA,除了横向扩展机器,是否能从流程和算法设计上提升效率。
  • 用户反馈对推荐系统的影响问题:用户反感或喜欢与文章本身并没有直接关系,比如用户喜欢体育新闻但讨厌中国足球。
  • 线上实时更新问题。

首先维护一个用户偏好和行为记录:

from typing import List
@dataclass
class User:
    
    user_name: str

@dataclass
class UserPrefer:
    
    user_name: str
    prefers: List[int]


@dataclass
class Item:
    
    item_id: str
    item_props: dict


@dataclass
class Action:
    
    action_type: str
    action_props: dict


@dataclass
class UserAction:
    
    user: User
    item: Item
    action: Action
    action_time: str

插入用户画像

u1 = User("u1")
up1 = UserPrefer("u1", [1, 2])
# sdf.iloc[1] 正好是sport(类别为2)
i1 = Item("i1", {
    "id": 1, 
    "catetory": "sport",
    "title": "Swimming: Shibata Joins Japanese Gold Rush", 
    "description": "\
    ATHENS (Reuters) - Ai Shibata wore down French teen-ager  Laure Manaudou to win the women's 800 meters \
    freestyle gold  medal at the Athens Olympics Friday and provide Japan with  their first female swimming \
    champion in 12 years.", 
    "content": "content"
})
a1 = Action("浏览", {
    "open_time": "2023-04-01 12:00:00", 
    "leave_time": "2023-04-01 14:00:00",
    "type": "close",
    "duration": "2hour"
})
ua1 = UserAction(u1, i1, a1, "2023-04-01 12:00:00")

处理召回

import random
class Recall:
    
    def __init__(self, df: pd.DataFrame):
        self.data = df
    
    def user_prefer_recall(self, user, n):
        up = self.get_user_prefers(user)
        idx = random.randrange(0, len(up.prefers))
        return self.pick_by_idx(idx, n)
    
    def hot_recall(self, n):
        # 随机进行示例
        df = self.data.sample(n)
        return df
    
    def user_action_recall(self, user, n):
        actions = self.get_user_actions(user)
        interest = self.get_most_interested_item(actions)
        recoms = self.recommend_by_interest(interest, n)
        return recoms
    
    def get_most_interested_item(self, user_action):
        """
        可以选近一段时间内用户交互时间、次数、评论(相关属性)过的Item
        """
        # 就是sdf的第2行,idx为1的那条作为最喜欢(假设)
        # 是一条游泳相关的Item
        idx = user_action.item.item_props["id"]
        im = self.data.iloc[idx]
        return im
    
    def recommend_by_interest(self, interest, n):
        cate_id = interest["Class Index"]
        q_emb = interest["embedding"]
        # 确定类别
        base = self.data[self.data["Class Index"] == cate_id]
        # 此处可以复用QA那一段代码,用给定embedding计算base中embedding的相似度
        base_arr = np.array(
            [v.embedding for v in base.itertuples()]
        )
        q_arr = np.expand_dims(q_emb, 0)
        sims = cosine_similarity(base_arr, q_arr)
        # 排除掉自己
        idxes = sims.argsort(0).squeeze()[-(n+1):-1]
        return base.iloc[reversed(idxes.tolist())]
    
    def pick_by_idx(self, category, n):
        df = self.data[self.data["Class Index"] == category]
        return df.sample(n)
    
    def get_user_actions(self, user):
        dct = {"u1": ua1}
        return dct[user.user_name]
    
    def get_user_prefers(self, user):
        dct = {"u1": up1}
        return dct[user.user_name]
    
    def run(self, user):
        ur = self.user_action_recall(user, 5)
        if len(ur) == 0:
            ur = self.user_prefer_recall(user, 5)
        hr = self.hot_recall(3)
        return pd.concat([ur, hr], axis=0)

recommend_by_interest(self, interest, n)方法根据用户的兴趣向量和指定的数量,从数据中推荐与用户兴趣相似的项。具体流程如下:

  • 首先,从兴趣向量中获取兴趣类别的索引(cate_id)和嵌入向量(q_emb)。
  • 接着,确定数据中与该类别索引相匹配的项(base)。
  • 将数据中这些项的嵌入向量提取出来,形成一个二维数组 base_arr
  • 将用户兴趣的嵌入向量扩展为二维数组 q_arr
  • 使用余弦相似度计算用户兴趣向量与数据中每个项的嵌入向量之间的相似度(sims)。
  • 根据相似度降序排列,选择与用户兴趣最相似的前 n 个项。
  • 最后,返回这些推荐的项。
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值