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使用urllib2提交http post请求的方法
May 26 Python
Go语言基于Socket编写服务器端与客户端通信的实例
Feb 19 Python
Python实现的科学计算器功能示例
Aug 04 Python
flask中主动抛出异常及统一异常处理代码示例
Jan 18 Python
Python iter()函数用法实例分析
Mar 17 Python
Python爬虫包BeautifulSoup异常处理(二)
Jun 17 Python
Python unittest 简单实现参数化的方法
Nov 30 Python
python opencv如何实现图片绘制
Jan 19 Python
Java Unsafe类实现原理及测试代码
Sep 15 Python
python使用scapy模块实现ping扫描的过程详解
Jan 21 Python
python如何构建mock接口服务
Jan 28 Python
Python与C++中梯度方向直方图的实现
Mar 17 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/07/21 PHP
php使用date和strtotime函数输出指定日期的方法
2014/11/14 PHP
php缓冲输出实例分析
2015/01/05 PHP
Yii框架实现图片上传的方法详解
2017/05/20 PHP
php中青蛙跳台阶的问题解决方法
2018/10/14 PHP
PHP将整数数字转换为罗马数字实例分享
2019/03/17 PHP
在 Laravel 中动态隐藏 API 字段的方法
2019/10/25 PHP
Javascript算符的优先级介绍
2013/03/20 Javascript
JS鼠标滑过图片时切换图片实现思路
2013/09/12 Javascript
Get中文乱码IE浏览器Get中文乱码解决方案
2013/12/26 Javascript
javascript 中__proto__和prototype详解
2014/11/25 Javascript
JavaScript的代码编写格式规范指南
2015/12/07 Javascript
【JS+CSS3】实现带预览图幻灯片效果的示例代码
2016/03/17 Javascript
noty ? jQuery通知插件全面解析
2016/05/18 Javascript
JS常用字符串方法(推荐)
2021/01/15 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
2016/11/29 Javascript
AngularJS路由切换实现方法分析
2017/03/17 Javascript
谈谈JS中的!!
2017/12/07 Javascript
微信小程序搜索框样式并实现跳转到搜索页面(小程序搜索功能)
2020/03/10 Javascript
用Python给文本创立向量空间模型的教程
2015/04/23 Python
Python的Django REST框架中的序列化及请求和返回
2016/04/11 Python
简单谈谈Python流程控制语句
2016/12/04 Python
Python中字典和集合学习小结
2017/07/07 Python
利用python将pdf输出为txt的实例讲解
2018/04/23 Python
Python操作多维数组输出和矩阵运算示例
2019/11/28 Python
PyCharm+Pipenv虚拟环境开发和依赖管理的教程详解
2020/04/16 Python
Python环境管理virtualenv&virtualenvwrapper的配置详解
2020/07/01 Python
python Matplotlib数据可视化(2):详解三大容器对象与常用设置
2020/09/30 Python
关于PySnooper 永远不要使用print进行调试的问题
2021/03/04 Python
CSS3颜色值RGBA与渐变色使用介绍
2020/03/06 HTML / CSS
如何配置、使用和清除Smarty缓存
2015/12/23 面试题
大学生新闻专业个人自我评价
2013/11/12 职场文书
培训演讲稿范文
2014/01/12 职场文书
学子宴答谢词
2014/01/25 职场文书
西安交大自主招生自荐信
2014/01/27 职场文书
电子商务实训报告总结
2014/11/05 职场文书