文本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
个项。 - 最后,返回这些推荐的项。