annoy超平面多维近似向量查找工具
需求:有800万的中文词向量,要查询其中任意一个词向量对应的k个与其最邻近的向量。通常情况下如果向量集比较小的话,几十万个向量(几个G这种),我们都可以用gensim的word2vec来查找,但是880万词向量有16个G,加到内存中就爆炸了,而且gensim中的查找属于暴力搜索,即全都遍历比较余弦相似度来进行查找,因此几百万量级的词向量查找起来就很慢了。这里我需要用更快速的工具来进行查找,找到了两个工具,一个是facebook的faiss包另一个是annoy包。Faiss只能部署在linux,而且看着好复杂,各种索引类型啥的,估计够我研究一阵,索性使用了annoy包;
关于annoy包的使用方法参考这两个网址足够:
1、https://github.com/spotify/annoy
2、https://markroxor.github.io/gensim/static/notebooks/annoytutorial.html
1是官方文档,写的非常简单,但是我刚开始没有认真看,所以走了很多弯路;2是一个notebook实践案例,基于gensim的,我就是被这个版本给坑了。。。这里面有很多说道,首先我先说一下代码逻辑,其实很简单,首先是读取你的带 word和vec的txt向量文件作为model:
model = gensim.models.KeyedVectors.load_word2vec_format('D:\\describe\\dic\\synonyms_vector.txt',binary=False,unicode_errors='ignore')
annoy_index = AnnoyIndexer(model, 100) # 生成索引
fname = 'synonyms_txt_index'
annoy_index.save(fname) # 将索引文件保存到硬盘
代码说明
这四行代码目的是
1、加载model
2、对model进行聚类计算
3、建立一个二叉树集合的索引(树的数量为100),
4、将索引保存到硬盘
接下来我们就可以根据建立的这个索引来查找近似向量了:
annoy_index2 = AnnoyIndexer() # 初始化索引
annoy_index2.load(fname)
annoy_index2.model = model
这三行就是来加载索引,值得注意的是这里的model就是之前最开始加载的txt文件对应的model
接下来问题来了,执行
word = ‘人民’
vector1 = model[word]
approximate_neighbors = model.most_similar([vector1], topn=30, indexer=annoy_index2)
这里想要查询“人民”对应的前30个相近词,通过加载索引来查询,可是最终的查询速度跟我没建立索引之前的暴力搜索(即word2vec自带搜索)是一样的,但是如果我在这个加载索引之前先进行一个词的暴力搜索,然后再对其他的词进行加载索引搜索,速度就会快出很多倍,这让我百思不得其解,最后没办法我就先用暴力搜索先搜索一个词,然后剩下的词都用annoy搜索,这样速度还是很快的;
但是我还是想弄明白到底怎么回事,于是我去官网问作者,作者就说了一句,你需要进行整数映射,(而且应该是非负整数),靠!!!其实官网写的明明白白:
a.add_item(i, v) adds item i (any nonnegative integer) with vector v. Note that it will allocate memory for max(i)+1 items.
也就是说我的txt文件格式需要如下这种格式:
1 vecor
2 vecor
而不是开头是汉语单词以及对应的vector,最后再做一个integer到word的映射字典即可;
接下来我对作者给出的github上的版本进行了验证,代码如下:
from annoy import AnnoyIndex
import random
f = 100 # 需要加载的向量的维度
t = AnnoyIndex(f)# 初始化一个索引
dict = {}
with open('C:\\Users\Administrator\Desktop\synonyms\\synonyms_vector.txt','r',encoding='utf-8') as f:
count = 0
for line in f:
result = line.split()
if len(result)>10:
count+=1
word = result[0]
dict[count] = word
vector = list(map(eval, result[1:])) # 需要将txt中的str格式vec转化为float格式
t.add_item(count, vector)
t.build(10)# 建立基于二叉树的近似查找索引文件
t.save('C:\\Users\Administrator\Desktop\synonyms\\test.ann')
u = AnnoyIndex(100)
u.load('C:\\Users\Administrator\Desktop\synonyms\\test.ann')
simi_id = u.get_nns_by_item(880, 20,include_distances=True)# 这里需要说明 880是vec.txt文件中第880个词,即 投资 这个词对应的序号,20代表查找和“投资”最近20个近义词
id = simi_id[0]
score = simi_id[1]
# print(simi_id)
# for i,j in zip(id,score):
# print(dict[i])
# print(0.5*(abs(1-j))+0.5)
result =[(dict[i],0.5*(abs(1-j))+0.5) for i,j in zip(id,score)]# 将结果转化一下,得到如下结果
输出结果(result):
[('投资', 1.0), ('融资', 0.6934992074966431), ('投资者', 0.6180032193660736), ('投资额', 0.6166684031486511), ('房地产', 0.6127455532550812), ('外资', 0.6104367673397064)]
这里面需要指出几点需要注意的地方:
1、需要将txt中的str格式vec转化为float格式,否则会报错;
2、我建立了一个字典映射,这样能够最后从查询到的近似向量对应的id值查询到映射的词;
3、最后那个0.5*(abs(1-j))+0.5是余弦相似度归一化的计算公式,作者程序中建立的距离索引以及最后查找返回值都是默认angular模式(即j的值),也即是余弦相似度,即angular=1-cosin,且其值域为[0,2](因为cosin值域为[-1,1])。但是我们通常只需要求取cosin的绝对值,即其值域应该位于[0,1]。所以我先用1-angular 获取cosin 然后再求取绝对值,最后再进行归一化((1+余弦相似度)/2)即可。
4、对于上面代码求取结果我与word2vec的most_similar方法结果进行对比,近似度基本一致,前三位精度完全一致,说明最后的余弦相似度求取向量相似度就是按照我上面说的方法来进行的;
最后附上余弦相似度计算方法参考网址:余弦相似度python实现
PS:关于annoy加载索引还需要注意一点,索引文件路径必须是英文路径,否则程序就会提示查找不到文件,望注意!!!
annoy超平面多维近似向量查找工具的更多相关文章
- 小程序入口构造工具&二维码测试工具
小程序入口构造工具&二维码测试工具 本文将介绍我们小程序中隐藏的两个工具页面.原理虽不复杂,收益却实实在在,或许也能给诸君带来启发. 入口构造工具 痛点 PM&运营 投放链接 PM&a ...
- vue项目条形码和二维码生成工具试用
项目开发需要,优惠券分不同类型,简单的使用id生成条形码供店铺使用,麻烦点的需要多个字段的就需要使用二维码来展示了,对应的效果如下 条形码(一维码)使用工具code128 需引入code128.js ...
- ZBar 是款桌面电脑用条形码/二维码扫描工具
ZBar 是款桌面电脑用条形码/二维码扫描工具 windows平台python 2.7环境编译安装zbar 最近一个项目需要识别二维码,找来找去找到了zbar和zxing,中间越过无数坑,总算基本 ...
- 二维码生成工具类java版
注意:这里我不提供所需jar包的路径,我会把所有引用的jar包显示出来,大家自行Google package com.net.util; import java.awt.BasicStroke; im ...
- Java 二维码生成工具类
/** * 二维码 工具 * * @author Rubekid * */ public class QRcodeUtils { /** * 默认version */ public static fi ...
- Ansible 运维自动化 ( 配置管理工具 )
背景 出差背景,要搞项目的自动化部署.因为只直接对接生产分发,机器又非常多,这样以往使用的bat只能作为应急方案了,还是得考虑使用专业化的工具来做这个事情! 当下有许多的运维自动化工具( 配置管理 ) ...
- 谷歌zxing 二维码生成工具
一.加入maven依赖 <!-- 谷歌zxing 二维码 --> <dependency> <groupId>com.google.zxing</groupI ...
- 【Win】Clso QR Tool 二维码小工具
一个可以生成并识别二维码的windows小工具,纯绿色.不含糖. 可以通过输入文本生成二维码,或者加载本地图片.剪贴板内的图片,直接解析出二维码内容. 支持自定义LOGO. 下载文件 (当前版本:1. ...
- 开发ASP.NET MVC 开发名片二维码生成工具 (原创)
在网上找了很多,都只能生成网址,不能生成名片二维码,于是自己动手. 第一步,写视图界面,主要代码如下: <script type="text/javascript"> ...
随机推荐
- 关于SG函数
Sprague-Grundy定理(SG定理): 游戏和的SG函数等于各个游戏SG函数的Nim和.这样就可以将每一个子游戏分而治之,从而简化了问题.而Bouton定理就是Sprague-Grundy定理 ...
- Python笔记_第三篇_面向对象_4.单下划线和双下划线
说道这里我们需要稍微暂停一下.前面我们说到了类是作为一个对象存放容器.这个容器里面有属性和方法.最好的理解类的方式就是把类想想成一个容器. 然后构造了一个析构函数和构造函数,然后又对object和se ...
- GO、 智能合约、cannot use transactionRecordId + strconv.Itoa(id) (type string) as type byte in append
1.报错详情 2.在写fabric go智能合约发送的错误,像我这样的新手就是踩坑踩坑踩坑 3.下面是代码片段 4.研究了一下append用法.也看了下GO语言官网文章: var test_str [ ...
- Python语言学习前提:基础语法
一.变量 1.变量:存储数据.存储数据需要对应内存空间,基于变量的数据类型,解释器会分配指定内存,决定什么数据被存储到内存中. 变量数据类型:整数.小数.字符. 2.变量赋值:变量在使用前必须赋值,赋 ...
- ZJNU 1130 - 龟兔赛跑——中高级
只需求出乌龟最短耗时跟兔子耗时比即可将起点 0 和终点 N+1 也看做充电站,进行动态规划对第i个点进行动态规划,则可以得到状态转移方程为dp[i] = max{dp[j]+time[i][j]} j ...
- linux操作提示:“Can't open file for writing”或“operation not permitted”的解决办法
在linux上使用vi命令修改一个文件内容的时候,发现无法保存,每次写完使用":q!"命令可以正常退出但是使用":wq!"命令保存文件并退出时出现一下信息提示: ...
- python_数据类型_总结
- day40-进程-生产者消费者模型进阶
#1.队列的数据是安全的,因为队列内置了一把锁,大家都来抢占资源的时候,A在操作数据的时候,B就无法操作该数据. # 下面代码有两个生产者和三个消费者,包子吃完之后,接着放的两个None被marry和 ...
- day12-模块导入
# 一.import import demo # in demo.py -- 导入demo模块,执行里面的print语句. print(demo.money) # 8000000 -- 打印demo的 ...
- Mysql 和 Java对比异同
1.求两个时间的差(天数) mysql : to_days 距离公元0年的天数 select TO_DAYS('2017-10-18 00:00:00'),TO_DAYS(NOW()), (TO_DA ...