首页 > 其他分享 >query改写

query改写

时间:2023-03-20 14:55:05浏览次数:46  
标签:kernel cache 改写 bias lru vecs query

标准query库的构建,如何才能打造一个高质量的标准query库

  • 前面说了,query改写模块主要是为了让高频query的错体、变体归一,所以query库中就必须包含头部pv部分的query。
  • 其次有些运营类的query,比如白名单的query,或者商业策略规定的买词等query也需要加入。
  • 还有一些规则类的词、app名称、当下火爆的一些梗或者新事物新词也需要包含进去。
  • 标准库绝大部分query的来源,就是在海量的用户输入query中用K-means的方式聚类,将离主类中心最近的query作为我们的标准库中的query,这个具体需要多少中心query需要自己判断,一般来说其实不用太多,万级别足够了。


什么?K-means速度太慢?这里推荐使用faiss gpu版本自带的K-means,目前500w query、1w的聚类中心大约半小时即可聚类完成,使用方法如下:

def train_kmeans(input_vecs, k_centers, niter=30, redo=10):
    model = faiss.Kmeans(
        input_vecs.shape[-1],
        k_centers, niter=niter, gpu=True, max_points_per_centroid=int(1e7), verbose=True, nredo=redo, seed=42)
    model.train(input_vecs.astype(np.float32))
    return model

这里有几个参数,niter代表kmeans的迭代次数,一般30就足够了,nredo代表重试次数,faiss构建kmeans时会多次重复train kmeans然后对比最终loss来判断哪次聚类最好,然后最终返回那个最好的聚类中心,这个参数一般选1就好,不放心可以选个2~5之间的数,再多就不礼貌了。0~0。

query embedding的方式,如何才能在短query场景下充分的表示信息

这个我司目前使用的是苏剑林开源的无监督的预训练模型simbert(4层312维),最后再加一层whitening解决空间坍缩问题,向量最终被whitening压缩至256维,想要详细了解simbert和whitening的同学可以移步苏神的文章:

有条件(主要是有时间+有钱)的大佬们可以尝试标注数据训练自己的有监督相似检索模型,并且在评论区留下微信,请务必让我成为你的朋友,你可以免费得到一个大腿挂件。0w0。

其实笔者之前也使用过无监督simcse,不知道是打开方式不对还是场景不合适,simcse的效果不如simbert,当然也不会差到哪去,感兴趣的同学可以多尝试尝试各种SOTA模型。

总之simbert + whitening是一个相当不错的baseline,而且比较百搭,不论是短query场景还是中长query场景都表现相当稳定。


bert whitening:

def compute_kernel_bias(vecs, n_components=256):
    """计算kernel和bias
    vecs.shape = [num_samples, embedding_size],
    最后的变换:y = (x + bias).dot(kernel)
    """
    mu = vecs.mean(axis=0, keepdims=True)
    cov = np.cov(vecs.T)
    u, s, vh = np.linalg.svd(cov)
    W = np.dot(u, np.diag(1 / np.sqrt(s)))
    return W[:, :n_components], -mu


def transform_and_normalize(vecs, kernel=None, bias=None):
    """ 最终向量标准化
    """
    if not (kernel is None or bias is None):
        vecs = (vecs + bias).dot(kernel)
    return vecs / (vecs**2).sum(axis=1, keepdims=True)**0.5


v_data = np.array(v_data)    
kernel,bias=compute_kernel_bias(v_data,256)
v_data=transform_and_normalize(v_data, kernel=kernel, bias=bias)

  



线上部署Bert和Faiss遇到的问题

诡异的多进程性能反而下降

准备好上面的所有物料后,笔者开始将query rewrite部署上线,由于我司的query rewrite模块是query parser中的一部分,query parser是我司使用纯python编写的一个后端,是综合了多种query理解功能的一个服务,在上线rewrite模块前为了应对线上高并发场景,开启了十个进程,当笔者用同样的进程数部署了query rewrite时发现了诡异的一幕:

  • 本来离线测试P99 6ms的onnx bert线上P99耗时飙升到了100ms;
  • 本来离线测试P99 0.5ms的HNSW index也耗时飙到了100ms左右;
  • 按道理进程越多性能越高才对,但是现在线上压测完全不达标,发生了肾么情况?0.o?

原来python自编程序一般没办法使用其他的核,所以我们的原始代码使用多进程来提高并发性能。但是onnx和faiss其实都是有多进程优化的,天生就可以使用其他的核,导致进程数开的越多,进程之间的抢资源现象会越严重,从而导致线上推理和检索没办法速度很快。

对于faiss如何解决这个问题,只需要设置如下环境变量即可:

  • 如果想在python里面配置:
os.environ["MKL_NUM_THREADS"] = '1'
os.environ["NUMEXPR_NUM_THREADS"] = '1'
os.environ["OMP_NUM_THREADS"] = '1'
  • 如果想直接在启动shell脚本里配置:
export MKL_NUM_THREADS=1
export NUMEXPR_NUM_THREADS=1
export OMP_NUM_THREADS=1

但是对于onnx bert来说,以上办法还是不行,最后笔者发现进程数由10减少至2才能使性能和离线一致,最近笔者仍然在解决这个问题,目前的切入点是多进程间共享内存的方法。

Python自带lru_cache优雅的进一步减轻线上压力

为了让高频出现的query不再被重新推理,笔者使用了python自带的cache方法,大大的帮我们缓解了线上压力,python自带的cache使用起来非常方便和优雅,而且线程安全,只需要使用装饰器lru_cache即可做到:

def lru_search_init(max_cache_length):
    @lru_cache(max_cache_length, typed=False)
    def lru_search(text: str, topk: int) -> (ndarray, ndarray, ndarray):
        # your search code
        return 
    return lru_search

searcher = lru_search_init(1024)

像上述代码一样构建的searcher就具备了lru_cache的能力,max_cache_length为最大缓存的条数,如果输入为None则为全部缓存,不建议,会爆内存,如果输入为0或者负数则代表不缓存。如果想清空缓存,可以使用:

searcher.cache_clear()



标签:kernel,cache,改写,bias,lru,vecs,query
From: https://www.cnblogs.com/qiaoqifa/p/17236300.html

相关文章

  • Jquery安装以及引用
    1.安装Jquery文件进入官网-进行安装-安装完成后-拖拽Jquery.js文件至项目下(根目录或者JS目录下)-在html-body-进行引入<scriptsrc='引入刚才jquery包'></script> ......
  • 【Java】Mybatis Plus LambdaQueryWrapper梳理
    【Java】Mybatis-PlusLambdaQueryWrapper梳理前言为了更方便的实现动态SQL,MybatisPlus在其基础上扩展了LambdaQueryWrapper,LambdaQueryWrapper提供了​​更加简便的查......
  • jQuery
    jQuery语法1、引用声明:<scriptsrc="jQuery文件URL"type="text/javascript"charset="UTF-8"></script>2、基础语法结构:jQuery的美元符号$是jQuery的简写文档就绪......
  • Html jquery AJAX 循环 延时 刷新
    JSON(PHP)<?php@header("content-type:application/json;charset=UTF-8");echo'{"status":200,"data":{"name":"55","student":[{"id":10001,"name":"张三"},{......
  • 2023 ICPC香港区域赛(UCup) D Shortest Path Query
    啊对对对,下次题解写详细一点好不好。首先考虑naive的\(O(n^2)\),记\(dp[i][j]\)表示从\(1\)走到\(i\),恰好走了\(j\)条黑边的时候走过白边的最少数量。\(O(nm)\)......
  • JQuery教程
    JQuery教程一、简介概述jQuery是一套兼容多浏览器的javascript脚本库.。核心理念是写得更少,做得更多,使用jQuery将极大的提高编写javascript代码的效率,帮助开发......
  • 【Ajax技术】JQuery处理XML数据
    我们将之前写的应用使用jquery返回xml数据程序清单服务端Servelt:AjaxXMLServer.java静态页面:ajaxJqueryXml.htmljavascript脚本文件:verifyj......
  • 将一个普通方法改写为异步方法
    如何将一个普通方法改写成异步方法? ///<summary>///把一个普通无参,无返回值的方法转为异步方法///</summary>///<paramname="srcAct......
  • Dcat-Admin改写ajax实现请求过滤同名参数
    //方案一Admin::script( <<<JS(function($){//备份jquery的ajax方法var_ajax=$.ajax;//重写jquery的ajax方法......
  • SQL优化改写案例11(上海某单位项目报表系统)
     记录一下上海某个内网报表系统的项目的一个案例,里面的逻辑比较复杂,很多视图套视图的语句。最多的一个视图除了它本身以外,一层层嵌套了7个视图在里面,贼恶心。而最难受......