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与shell的3种交互方式介绍
Apr 11 Python
Pyhthon中使用compileall模块编译源文件为pyc文件
Apr 28 Python
浅谈python import引入不同路径下的模块
Jul 11 Python
Python自定义函数定义,参数,调用代码解析
Dec 27 Python
Python用 KNN 进行验证码识别的实现方法
Feb 06 Python
python获取地震信息 微信实时推送
Jun 18 Python
pyinstaller打包opencv和numpy程序运行错误解决
Aug 16 Python
简单了解python中的f.b.u.r函数
Nov 02 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
Jul 31 Python
基于python requests selenium爬取excel vba过程解析
Aug 12 Python
使用python-cv2实现视频的分解与合成的示例代码
Oct 26 Python
python 中关于pycharm选择运行环境的问题
Oct 31 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中字符查找函数strpos、strrchr与strpbrk用法
2014/11/18 PHP
jQuery对象和DOM对象的相互转化实现代码
2010/03/02 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
2011/07/22 Javascript
查看大图功能代码jquery版
2013/11/05 Javascript
javascript控制台详解
2015/06/25 Javascript
jQuery插件支持同一页面被多次调用
2016/02/14 Javascript
jQuery实现控制文字内容溢出用省略号(…)表示的方法
2016/02/26 Javascript
详解jQuery简单的表单应用
2016/12/16 Javascript
jQuery简单实现MD5加密的方法
2017/03/03 Javascript
JS实现仿饿了么在浏览器标签页失去焦点时网页Title改变
2017/06/01 Javascript
微信小程序实现的图片保存功能示例
2019/04/24 Javascript
如何在微信小程序中实现Mixins方案
2019/06/20 Javascript
vue穿梭框实现上下移动
2021/01/29 Vue.js
python基于socket实现网络广播的方法
2015/04/29 Python
Python读写txt文本文件的操作方法全解析
2016/06/26 Python
Python 使用requests模块发送GET和POST请求的实现代码
2016/09/21 Python
python中字符串比较使用is、==和cmp()总结
2018/03/18 Python
python 通过logging写入日志到文件和控制台的实例
2018/04/28 Python
python版本单链表实现代码
2018/09/28 Python
python去重,一个由dict组成的list的去重示例
2019/01/21 Python
python opencv 读取本地视频文件 修改ffmpeg的方法
2019/01/26 Python
OpenCV+Python识别车牌和字符分割的实现
2019/01/31 Python
Python Selenium参数配置方法解析
2020/01/19 Python
python安装cx_Oracle和wxPython的方法
2020/09/14 Python
Python jieba结巴分词原理及用法解析
2020/11/05 Python
python3实现飞机大战
2020/11/29 Python
基于html5实现的图片墙效果
2014/10/16 HTML / CSS
简单介绍HTML5中的文件导入
2015/05/08 HTML / CSS
国际化的太阳镜及太阳镜配件零售商:Sunglass Hut
2016/07/26 全球购物
香港最大的洋酒零售连锁店:屈臣氏酒窖(Watson’s Wine)
2018/12/10 全球购物
荷兰的时尚市场:To Be Dressed
2019/05/06 全球购物
Bata印度官网:源自欧洲舒适鞋履品牌
2020/01/30 全球购物
给儿子的表扬信
2014/01/15 职场文书
红歌会主持词
2015/07/02 职场文书
培训学校2015年度工作总结
2015/07/20 职场文书
校园文化艺术节开幕词
2016/03/04 职场文书