Embedding的近邻搜索是当前图推荐系统非常重要的一种召回方式,通过item2vec、矩阵分解、双塔DNN等方式都能够产出训练好的user embedding、item embedding,对于embedding的使用非常的灵活:
- 输入user embedding,近邻搜索item embedding,可以给user推荐感兴趣的items
- 输入user embedding,近邻搜搜user embedding,可以给user推荐感兴趣的user
- 输入item embedding,近邻搜索item embedding,可以给item推荐相关的items
然而有一个工程问题,一旦user embedding、item embedding数据量达到一定的程度,对他们的近邻搜索将会变得非常慢,如果离线阶段提前搜索好在高速缓存比如redis存储好结果当然没问题,但是这种方式很不实时,如果能在线阶段上线几十MS的搜索当然效果最好。
Faiss是Facebook AI团队开源的针对聚类和相似性搜索库,为稠密向量提供高效相似度搜索和聚类,支持十亿级别向量的搜索,是目前最为成熟的近似近邻搜索库。
接下来通过jupyter notebook的代码,给大家演示下使用faiss的简单流程,内容包括:
- 读取训练好的Embedding数据
- 构建faiss索引,将待搜索的Embedding添加进去
- 取得目标Embedding,实现搜索得到ID列表
- 根据ID获取电影标题,返回结果
对于已经训练好的Embedding怎样实现高速近邻搜索是一个工程问题,facebook的faiss库可以构建多种embedding索引实现目标embedding的高速近邻搜索,能够满足在线使用的需要
安装命令:
conda install -c pytorch faiss-cpu
提前总结下faiss使用经验:
1. 为了支持自己的ID,可以用faiss.IndexIDMap包裹faiss.IndexFlatL2即可
2. embedding数据都需要转换成np.float32,包括索引中的embedding以及待搜索的embedding
3. ids需要转换成int64类型
1. 准备数据
import pandas as pd import numpy as np
df = pd.read_csv("./datas/movielens_sparkals_item_embedding.csv") df.head()
id
features
构建ids
ids = df["id"].values.astype(np.int64) type(ids), ids.shape (numpy.ndarray, (3706,)) ids.dtype dtype('int64') ids_size = ids.shape[0] ids_size 3706
构建datas
import json import numpy as np datas = [] for x in df["features"]: datas.append(json.loads(x)) datas = np.array(datas).astype(np.float32) datas.dtype dtype('float32') datas.shape (3706, 10) datas[0] array([ 0.2586649 , 0.35605943, 0.15589039, -0.7067125 , -0.07414215, -0.62500805, -0.0573845 , 0.4533663 , 0.26074877, -0.60799956], dtype=float32) # 维度 dimension = datas.shape[1] dimension 10
2. 建立索引
import faiss index = faiss.IndexFlatL2(dimension) index2 = faiss.IndexIDMap(index) ids.dtype dtype('int64') index2.add_with_ids(datas, ids) index.ntotal 3706
4. 搜索近邻ID列表
df_user = pd.read_csv("./datas/movielens_sparkals_user_embedding.csv") df_user.head() id features
id
features
user_embedding = np.array(json.loads(df_user[df_user["id"] == 10]["features"].iloc[0])) user_embedding = np.expand_dims(user_embedding, axis=0).astype(np.float32) user_embedding array([[ 0.59742886, 0.17486966, 0.04345559, -1.3193961 , 0.5313592 , -0.6052168 , -0.19088413, 1.5307966 , 0.09310367, -2.7573566 ]], dtype=float32) user_embedding.shape (1, 10) user_embedding.dtype dtype('float32') topk = 30 D, I = index.search(user_embedding, topk) # actual search I.shape (1, 30) I array([[3380, 2900, 1953, 121, 3285, 999, 617, 747, 2351, 601, 2347, 42, 2383, 538, 1774, 980, 2165, 3049, 2664, 367, 3289, 2866, 2452, 547, 1072, 2055, 3660, 3343, 3390, 3590]])
5. 根据电影ID取出电影信息
target_ids = pd.Series(I[0], name="MovieID") target_ids.head() 0 3380 1 2900 2 1953 3 121 4 3285 Name: MovieID, dtype: int64 df_movie = pd.read_csv("./datas/ml-1m/movies.dat", sep="::", header=None, engine="python", names = "MovieID::Title::Genres".split("::")) df_movie.head()
MovieID
Title
Genres
df_result = pd.merge(target_ids, df_movie) df_result.head()
MovieID
Title
Genres
总结
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 【雨果唱片】中国管弦乐《鹿回头》WAV
- APM亚流新世代《一起冒险》[FLAC/分轨][106.77MB]
- 崔健《飞狗》律冻文化[WAV+CUE][1.1G]
- 罗志祥《舞状元 (Explicit)》[320K/MP3][66.77MB]
- 尤雅.1997-幽雅精粹2CD【南方】【WAV+CUE】
- 张惠妹.2007-STAR(引进版)【EMI百代】【WAV+CUE】
- 群星.2008-LOVE情歌集VOL.8【正东】【WAV+CUE】
- 罗志祥《舞状元 (Explicit)》[FLAC/分轨][360.76MB]
- Tank《我不伟大,至少我能改变我。》[320K/MP3][160.41MB]
- Tank《我不伟大,至少我能改变我。》[FLAC/分轨][236.89MB]
- CD圣经推荐-夏韶声《谙2》SACD-ISO
- 钟镇涛-《百分百钟镇涛》首批限量版SACD-ISO
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】