V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sunhk25
V2EX  ›  Python

Python +mongodb:如何快速计算大量向量近似度

  •  
  •   sunhk25 · 2019-07-04 15:34:19 +08:00 · 3322 次点击
    这是一个创建于 1756 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • 语料库 20 万句的向量( 250 维)值放到 DB 后,python 查询指定文章最相似的 TOP50。
    • 相似度的计算在用 numpy,计算时间是 2+秒,但是从 DB 把数据拿到内存就需要 7 秒。
    • 降维之类的方法不太懂,请教各位正常该如何实现相似检索?
    第 1 条附言  ·  2019-07-05 18:08:17 +08:00
    Redis 的读取和 JSON.load 加起来的时间是 pickle 的几倍,不知道哪里姿势不对,为什么那么多人推荐 Redis。用的是 Python3.6。
    10 条回复    2021-12-23 23:30:49 +08:00
    chengxiao
        1
    chengxiao  
       2019-07-04 16:22:04 +08:00
    250 维....这不是数据库能处理的吧?
    lunaticus7
        2
    lunaticus7  
       2019-07-04 16:33:33 +08:00
    `但是从 DB 把数据拿到内存就需要 7 秒` 是指取 20000 * 250 向量?
    特征向量为什么要存 mangoDB 嘛,这点量也没多少,直接塞内存,精度可以转成 np.float32 甚至 np.float16,能省很多内存,这些精度做检索够用

    解决了了从数据库读特征向量的问题后,就可以优化检索计算了

    大方向就是分级检索:先用低运算量低精度的 metirc (句向量的话直接 cosine 就行)快速检索出一个较大的候选集,然后在候选集内部再用正常的高精度低速 metirc 得出最终结果


    懒得折腾可以直接上 fb 家的 faiss

    PS.你什么算法啊,20w 数据相似度居然要算 2s ?
    sunhk25
        3
    sunhk25  
    OP
       2019-07-04 16:59:09 +08:00
    @lunaticus7
    谢谢意见,7s 是指从数据库拿数据
    现在就是简单的计算内积,20 万的话就要 1G 内存
    250 * 20 * 10000 * 24 / (1024 * 1024) = 1144.4MB
    owenliang
        4
    owenliang  
       2019-07-04 17:58:20 +08:00
    不行就把计算摘出去,换个 c++/golang 做一下,1 秒内肯定没有问题。
    necomancer
        5
    necomancer  
       2019-07-04 22:56:28 +08:00   ❤️ 1
    numpy 的 dot 和 einsum 都比较慢,你可以考虑用 numba 的 guvectorize
    @guvectorize([(float64[:], float64[:], float64[:])],
    '(n),(n)->()', target='parallel')
    def my_inner_prod(a, b, ret):
    tmp1 = tmp2 = tmp3 = 0
    for i in range(a.shape[0]):
    tmp1 += a[i] * b[i]
    tmp2 += a[i] * a[i]
    tmp3 += b[i] * b[i]
    ret[0] = tmp1 / (tmp2 * tmp3) ** 0.5
    这个是 cos(theta),如果不除以模量则只要 tmp1 就可以了
    可以快很多。只要向量维度是对齐的,比如 (100000,250) . (100000,250) -> (100000,)
    或者(100000,250) . (1,250) -> (100000,)
    降维是不是可以考虑 PCA?
    necomancer
        6
    necomancer  
       2019-07-04 22:59:55 +08:00
    In [29]: a = np.random.random((200000,250))

    In [30]: my_inner_prod(a,a)
    Out[30]: array([1., 1., 1., ..., 1., 1., 1.])

    In [31]: %timeit my_inner_prod(a,a)
    49.3 ms ± 850 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

    I7-3687u
    TobiahShaw
        7
    TobiahShaw  
       2019-07-05 12:00:39 +08:00
    想降维的话可以用下 PCA,分析一下主成分试一下,可以提前计算相似度存在 kv 服务,用的时候直接取
    ebingtel
        8
    ebingtel  
       2019-07-05 13:56:17 +08:00
    1、 预计算,不要求实时性的话
    2、用 redis 进行 bit 计算和存储
    sunhk25
        9
    sunhk25  
    OP
       2019-07-05 14:58:53 +08:00
    @ebingtel 正在调查用 memchached 还是 radis 呢。
    Redis 做缓存,mongodb 做持久化,两者结合的话会不会好一点?
    ldyisbest
        10
    ldyisbest  
       2021-12-23 23:30:49 +08:00
    试试向量数据库 milvus
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1081 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 22:38 · PVG 06:38 · LAX 15:38 · JFK 18:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.