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中的floor()方法
May 15 Python
Python中动态创建类实例的方法
Mar 24 Python
python执行使用shell命令方法分享
Nov 08 Python
python 常见字符串与函数的用法详解
Nov 23 Python
Python用61行代码实现图片像素化的示例代码
Dec 10 Python
Django 用户认证组件使用详解
Jul 23 Python
django中瀑布流写法实例代码
Oct 14 Python
python自动下载图片的方法示例
Mar 25 Python
python 发送邮件的示例代码(Python2/3都可以直接使用)
Dec 03 Python
Python 求向量的余弦值操作
Mar 04 Python
Python中三种花式打印的示例详解
Mar 19 Python
Python docx库删除复制paragraph及行高设置图片插入示例
Jul 23 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学习资料汇总与网址
2007/03/16 PHP
linux实现php定时执行cron任务详解
2013/12/24 PHP
ThinkPHP中公共函数路径和配置项路径的映射分析
2014/11/22 PHP
Laravel5.1数据库连接、创建数据库、创建model及创建控制器的方法
2016/03/29 PHP
深入浅析Yii admin的权限控制
2016/08/31 PHP
centos 7.2下搭建LNMP环境教程
2016/11/20 PHP
如何取得中文输入的真实长度?
2006/06/24 Javascript
再次更新!MSClass (Class Of Marquee Scroll通用不间断滚动JS封装类 Ver 1.6)
2007/02/05 Javascript
javascript继承之为什么要继承
2012/11/10 Javascript
JavaScript数组Array对象增加和删除元素方法总结
2015/01/20 Javascript
jQuery实现鼠标悬停显示提示信息窗口的方法
2015/04/30 Javascript
详解jquery事件delegate()的使用方法
2016/01/25 Javascript
Bootstrap表单布局样式源代码
2016/07/04 Javascript
微信小程序 数组中的push与concat的区别
2017/01/05 Javascript
JS+HTML5实现上传图片预览效果完整实例【测试可用】
2017/04/20 Javascript
JS图片轮播与索引变色功能实例详解
2017/07/06 Javascript
关于自定义Egg.js的请求级别日志详解
2018/12/12 Javascript
浅谈Vue CLI 3结合Lerna进行UI框架设计
2019/04/14 Javascript
解决layui追加或者动态修改的表单元素“没效果”的问题
2019/09/18 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
[46:43]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第二局
2016/03/02 DOTA
详解Python发送邮件实例
2016/01/10 Python
利用Python破解验证码实例详解
2016/12/08 Python
Django自定义认证方式用法示例
2017/06/23 Python
使用11行Python代码盗取了室友的U盘内容
2018/10/23 Python
如何在Cloud Studio上执行Python代码?
2019/08/09 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
2021/02/20 Python
让IE支持CSS3的不完全兼容方案
2014/09/19 HTML / CSS
html5实现完美兼容各大浏览器的播放器
2014/12/26 HTML / CSS
Ralph Lauren英国官方网站:Ralph Lauren UK
2018/04/03 全球购物
DELPHI面试题研发笔试试卷
2015/11/08 面试题
全神贯注教学反思
2014/02/03 职场文书
铅球加油稿100字
2014/09/26 职场文书
公务员处分决定书
2015/06/25 职场文书
学校扫黄打非工作总结
2015/10/15 职场文书
SpringBoot2零基础到精通之数据与页面响应
2022/03/22 Java/Android