Python利用Faiss库实现ANN近邻搜索的方法详解


Posted in Python onAugust 03, 2020

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
0 10 [0.25866490602493286, 0.3560594320297241, 0.15…
1 20 [0.12449632585048676, -0.29282501339912415, -0…
2 30 [0.9557555317878723, 0.6764761805534363, 0.114…
3 40 [0.3184879720211029, 0.6365472078323364, 0.596…
4 50 [0.45523127913475037, 0.34402626752853394, -0….

构建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
0 10 [0.5974288582801819, 0.17486965656280518, 0.04…
1 20 [1.3099910020828247, 0.5037978291511536, 0.260…
2 30 [-1.1886241436004639, -0.13511677086353302, 0….
3 40 [1.0809299945831299, 1.0048035383224487, 0.986…
4 50 [0.42388680577278137, 0.5294889807701111, -0.6…
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
0 1 Toy Story (1995) Animation|Children's|Comedy
1 2 Jumanji (1995) Adventure|Children's|Fantasy
2 3 Grumpier Old Men (1995) Comedy|Romance
3 4 Waiting to Exhale (1995) Comedy|Drama
4 5 Father of the Bride Part II (1995) Comedy
df_result = pd.merge(target_ids, df_movie)
df_result.head()

MovieID Title Genres
0 3380 Railroaded! (1947) Film-Noir
1 2900 Monkey Shines (1988) Horror|Sci-Fi
2 1953 French Connection, The (1971) Action|Crime|Drama|Thriller
3 121 Boys of St. Vincent, The (1993) Drama
4 3285 Beach, The (2000) Adventure|Drama

总结

到此这篇关于Python利用Faiss库实现ANN近邻搜索的文章就介绍到这了,更多相关Python用Faiss库ANN近邻搜索内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python urlopen()函数 示例分享
Jun 12 Python
分享15个最受欢迎的Python开源框架
Jul 13 Python
利用Python如何生成随机密码
Apr 20 Python
python字典多键值及重复键值的使用方法(详解)
Oct 31 Python
利用Python代码实现数据可视化的5种方法详解
Mar 25 Python
Python实现检测文件MD5值的方法示例
Apr 11 Python
python+opencv 读取文件夹下的所有图像并批量保存ROI的方法
Jan 10 Python
Django框架反向解析操作详解
Nov 28 Python
Django框架配置mysql数据库实现过程
Apr 22 Python
Python 实现自动登录+点击+滑动验证功能
Jun 10 Python
Python自动化测试中yaml文件读取操作
Aug 20 Python
Python进程间的通信之语法学习
Apr 11 Python
Python pexpect模块及shell脚本except原理解析
Aug 03 #Python
python爬虫使用正则爬取网站的实现
Aug 03 #Python
python获取整个网页源码的方法
Aug 03 #Python
flask开启多线程的具体方法
Aug 02 #Python
基于opencv实现简单画板功能
Aug 02 #Python
django下创建多个app并设置urls方法
Aug 02 #Python
Django如何在不停机的情况下创建索引
Aug 02 #Python
You might like
php实现的遍历文件夹下所有文件,编辑删除
2010/01/05 PHP
PHP技术开发技巧分享
2010/03/23 PHP
yii框架通过控制台命令创建定时任务示例
2014/04/30 PHP
php+ajax导入大数据时产生的问题处理
2014/06/11 PHP
ThinkPHP3.1数据CURD操作快速入门
2014/06/19 PHP
PHP操作FTP类 (上传、下载、移动、创建等)
2016/03/31 PHP
PHP flush 函数使用注意事项
2016/08/26 PHP
PHP实现根据数组的值进行分组的方法
2017/04/20 PHP
PHP PDOStatement::bindColumn讲解
2019/01/30 PHP
PHP8.0新功能之Match表达式的使用
2020/07/19 PHP
基于jquery的inputlimiter 实现字数限制功能
2010/05/30 Javascript
自写的一个jQuery圆角插件
2010/10/26 Javascript
JQuery实现用户名无刷新验证的小例子
2013/03/22 Javascript
JS小功能(onmouseover实现选择月份)实例代码
2013/11/28 Javascript
JavaScript中用toString()方法返回时间为字符串
2015/06/12 Javascript
30分钟快速掌握Bootstrap框架
2016/05/24 Javascript
JS实现仿百度文库评分功能
2017/01/12 Javascript
Javascript中document.referrer隐藏来源的方法
2017/01/16 Javascript
微信小程序实现顶部选项卡(swiper)
2020/06/19 Javascript
Angular实现的简单查询天气预报功能示例
2017/12/27 Javascript
vue.js与element-ui实现菜单树形结构的解决方法
2018/04/21 Javascript
vuex操作state对象的实例代码
2018/04/25 Javascript
VUE简单的定时器实时刷新的实现方法
2019/01/20 Javascript
原生js实现五子棋游戏
2020/05/28 Javascript
[01:13:59]LGD vs Mineski Supermajor 胜者组 BO3 第三场 6.5
2018/06/06 DOTA
[50:12]EG vs Fnatic 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
python错误:AttributeError: 'module' object has no attribute 'setdefaultencoding'问题的解决方法
2014/08/22 Python
Python 文件操作的详解及实例
2017/09/18 Python
python 设置输出图像的像素大小方法
2019/07/04 Python
python3用PyPDF2解析pdf文件,用正则匹配数据方式
2020/05/12 Python
思想品德自我评价
2014/02/04 职场文书
团拜会策划方案
2014/06/07 职场文书
公司离职证明标准格式
2014/11/18 职场文书
辞职信的写法
2015/02/27 职场文书
2015年高三教学工作总结
2015/07/21 职场文书
创业计划书之酒厂
2019/10/14 职场文书