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中IPYTHON入门实例
May 11 Python
python比较2个xml内容的方法
May 11 Python
通过实例浅析Python对比C语言的编程思想差异
Aug 30 Python
Python队列的定义与使用方法示例
Jun 24 Python
Python实现PS图像调整之对比度调整功能示例
Jan 26 Python
Django 多语言教程的实现(i18n)
Jul 07 Python
对python多线程SSH登录并发脚本详解
Feb 14 Python
Django Admin后台添加数据库视图过程解析
Apr 01 Python
Django Xadmin多对多字段过滤实例
Apr 07 Python
解决python中显示图片的plt.imshow plt.show()内存泄漏问题
Apr 24 Python
Python进行统计建模
Aug 10 Python
python中subplot大小的设置步骤
Jun 28 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中关于普通表单多文件上传的处理方法
2011/03/25 PHP
解析php函数method_exists()与is_callable()的区别
2013/06/21 PHP
基于php和mysql的简单的dao类实现crud操作功能
2014/01/27 PHP
php实现QQ空间获取当前用户的用户名并生成图片
2015/07/25 PHP
分享微信扫码支付开发遇到问题及解决方案-附Ecshop微信支付插件
2015/08/23 PHP
PHP 应用容器化以及部署方法
2018/02/12 PHP
css3实现背景模糊的三种方式
2021/03/09 HTML / CSS
50个比较实用jQuery代码段
2011/09/18 Javascript
密码强度检测效果实现原理与代码
2013/01/04 Javascript
同时使用n个window onload加载实例介绍
2013/04/25 Javascript
js函数定时器实现定时读取系统实时连接数
2014/04/30 Javascript
javascript制作幻灯片(360度全景图片)
2015/07/28 Javascript
利用jQuery及AJAX技术定时更新GridView的某一列数据
2015/12/04 Javascript
全面解析Bootstrap中transition、affix的使用方法
2016/05/30 Javascript
微信小程序左滑删除效果的实现代码
2017/02/20 Javascript
js实现华丽的九九乘法表效果
2017/03/29 Javascript
微信小程序基于slider组件动态修改标签透明度的方法示例
2017/12/04 Javascript
antd vue table跨行合并单元格,并且自定义内容实例
2020/10/28 Javascript
python实现文本去重且不打乱原本顺序
2016/01/26 Python
利用Python命令行传递实例化对象的方法
2016/11/02 Python
Python学生信息管理系统修改版
2018/03/13 Python
PyCharm代码整体缩进,反向缩进的方法
2018/06/25 Python
Python拆分大型CSV文件代码实例
2019/10/07 Python
Python chardet库识别编码原理解析
2020/02/18 Python
python实现PCA降维的示例详解
2020/02/24 Python
Python使用requests xpath 并开启多线程爬取西刺代理ip实例
2020/03/06 Python
python新手学习使用库
2020/06/11 Python
python os.listdir()乱码解决方案
2021/01/31 Python
快速创建 HTML5 Canvas 电信网络拓扑图的示例代码
2018/03/21 HTML / CSS
加拿大拼图大师:Puzzle Master
2020/12/28 全球购物
秘书行业自我鉴定范文
2013/12/30 职场文书
2014年客服工作总结与计划
2014/12/09 职场文书
2015年公司工作总结
2015/04/25 职场文书
使用numpy实现矩阵的翻转(flip)与旋转
2021/06/03 Python
Python机器学习应用之基于线性判别模型的分类篇详解
2022/01/18 Python
Android自定义双向滑动控件
2022/04/19 Java/Android