乘积量化

1。简介

  乘积量化(PQ)算法是和VLAD算法是由法国INRIA实验室一同提出来的,为的是加快图像的检索速度,所以它是一种检索算法,在矢量量化(Vector Quantization,VQ)的基础上发展而来,虽然PQ不算是新算法,但是这种思想还是挺有用处的,本文没有添加公式。

  它原文中是接在VLAD算法后面,假设我们使用VLAD算法获得了1M的图像表达向量,向量的维度为D=128,则对于一幅查询图像来说,我们需要计算1M个余弦距离,这样实时性就比较差。所以如何加快这种距离的计算速度就是PQ算法所要完成的任务。当然为了解决这个问题,已经有很多算法被提出了,如KDTree,LSH,ITQ等都是为解决这个问题而提出的,属于KNN或ANN范畴。

2。空间切分

  首先,PQ先将D维空间切分成M份:即将128维空间切分成M个D/M维的子空间,如下图所示M=8(在原文中,作者由于是在PCA之后进行的PQ检索,所以进行了一个随机旋转,因为PCA之后特征值的顺序是按照从大到小排列的)

  用代码表示就是把向量维度切分:

int ds= d / nsq;
for ( int i = ; i < nsq; i ++ )
{
for ( int j = ; j < ds; j ++ )
{
vs.push_back( vtrain.row( i*ds + j ) );
}
}
//vtrain的转置是原始128维向量,vs是其中的一个子向量

3。量化

  这样就可以在每个子空间内都会有1M个短向量,我们为每个子空间单独训练一本码书,图中码书规模为k=256,维度d=D/M=128/8=16,代码只要在上面的外循环中添加k-means聚类即可:

kmeans( vs, ks, labelssub, TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, , 0.001 ),
, KMEANS_PP_CENTERS, centers );

  到这里我们就有M=8本子码书,下面我们依次量化每个子空间的数据,量化的过程就是计算每个短向量距离最近的聚类中心,距离就是L2距离,可以调用OpenCV函数,也可以自己写一个距离计算函数,但是要统一,如:

float my_norm_L2( Mat mat1, Mat mat2 )
{
int d = mat1.cols;
float sum_d = 0.0;
for ( int i = ; i < d; i ++ )
{
float pp = mat1.at<float>( , i ) - mat2.at<float>( , i );
sum_d = sum_d + pp*pp;
}
return sum_d;
}

4。压缩

  现在考虑一个D=128维的原始向量,它被切分成了M=8个d=16维的短向量,同时每个短向量都对应一个量化的索引值,索引值即该短向量距离最近的聚类中心的编号,每一个原始向量就可以压缩成M个索引值构成的压缩向量,只要设计好了数据结构,就可以获得所有1M数据的压缩向量。压缩向量其实就是M个索引值,每个索引值对应一个聚类中心,所以要同时保存压缩向量和聚类中心。

  其实一个向量被8个索引值同时索引,而如果把这8个索引值转换成一个的话是多大呢,k的M次方,这里应该是256的8次方,这是一个很大很大的数,而上面的操作就等效于生成了一个这么大规模的码书。为什么这么说呢,因为每一个短向量(或称子向量)量化的过程都有k个选择,而一个原始向量有M个选择,类似于8位256进制的数可以表示的最大数值:

          

  对于query图像的原始向量也经过上述流程的切分和量化过程,最后生成同样的M维压缩向量。

5。距离计算

  对于训练数据和测试数据都压缩完成后,接下来就是讨论如何计算两个压缩向量之间的距离呢?而且是快速的计算。

  作者提供了两种距离计算方式,分别为 “对称距离计算” 和 “非对称距离计算” ,分别如下左右图所示:

对称距离计算:直接使用两个压缩向量x,y的索引值所对应的码字q(x),q(y)之间的距离代替之,而q(x),q(y)之间的距离可以离线计算,因此可以把q(x),q(y)之间的距离制作成查找表,只要按照压缩向量的索引值进行对应的查找就可以了,所以速度非常快;

非对称距离计算:使用x,q(y)之间的距离代替x,y之间的距离,其中x是测试向量。虽然y的个数可能有上百万个,但是q(y)的个数只有k个,对于每个x,我们只需要在输入x之后先计算一遍x和k个q(y)的距离,制成查找表(因为只有k个,所以速度是非常快的),然后按照y对应的压缩向量索引值进行取值操作就可以了。

Mat sumidxtab( Mat &D, Mat&x, Mat & dis )
{
dis = Mat::zeros( , x.rows, CV_32FC1 );
for ( int i = ; i < x.rows; i ++ )
{
float distmp = ;
for ( int j = ; j < D.cols; j ++ )
{
distmp = distmp + D.at<float>( x.at<int>( i, j ), j ) ;//ADC距离计算方式;
}
dis.at<float>( , i ) = distmp;
}
return dis;
}
//D为查找表,x为压缩向量,dis为最终的距离

6。总结

  不管哪种计算方法都可以实现快速的距离计算,但是非对称距离计算由于只量化了y,所以计算的距离精度更高,效果也更好。距离计算过程中只需要存储码书和对应的索引值就可以完全抛弃原始的图像表达向量,实现数据的压缩和距离的快速计算。

  但是需要明白的是,这种算法是基于量化的,所以必然存在量化误差,所以距离的计算并不是完全准确的。通常通过这种算法迅速返回N个结果,然后再在N个结果中进行进一步的匹配计算,得到比较准确的结果。

  在原文中,还有基于PQ的非线性计算方法IVFADC,它的速度更快,精度反而更高了,有时间再介绍。其实后续人们不断改进了PQ算法,如OPQ,Multi-ADC,DPQ,AQ/APQ,TQ,LOPQ等等,其中OPQ,Multi-ADC的提升效果还是比较明显的。

乘积量化(Product Quantization)的更多相关文章

  1. ANN中乘积量化与多维倒排小结

    目前特征向量的比对加速优化能极大缩短比对耗时,改善用户体验. 优化的途径主要有两种,一是使用指令集(SSE,AVX)加速运算.二是使用ANN替代暴力搜索. 乘积量化和倒排索引组合是ANN中效果较好且实 ...

  2. 暴力求解——最大乘积 Maximum Product,UVa 11059

    最大乘积 Maximum Product 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=84562#problem/B 解题思路 ...

  3. 最大乘积 Maximun Product

    最大乘积 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=84562#problem/B 题意: 输入n个元素组成的序列s,你需要 ...

  4. [Swift]LeetCode628. 三个数的最大乘积 | Maximum Product of Three Numbers

    Given an integer array, find three numbers whose product is maximum and output the maximum product. ...

  5. 最大乘积(Maximum Product,UVA 11059)

    Problem D - Maximum Product Time Limit: 1 second Given a sequence of integers S = {S1, S2, ..., Sn}, ...

  6. LeetCode 238. 除自身以外数组的乘积( Product of Array Except Self)

    题目描述 给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积. 示例: 输 ...

  7. 【LeetCode】1464. 数组中两元素的最大乘积 Maximum Product of Two Elements in an Array (Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力 找最大次大 日期 题目地址:https://le ...

  8. [Swift]LeetCode318. 最大单词长度乘积 | Maximum Product of Word Lengths

    Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the tw ...

  9. FastText 分析与实践

    一. 前言 自然语言处理(NLP)是机器学习,人工智能中的一个重要领域.文本表达是 NLP中的基础技术,文本分类则是 NLP 的重要应用.在 2016 年, Facebook Research 开源了 ...

随机推荐

  1. Java实现Kafka的生产者和消费者例子

    Kafka的结构与RabbitMQ类似,消息生产者向Kafka服务器发送消息,Kafka接收消息后,再投递给消费者.生产者的消费会被发送到Topic中,Topic中保存着各类数据,每一条数据都使用键. ...

  2. 关于强制IE不使用兼容模式渲染网页

    现在IE11是唯一受微软支持的IE浏览器. IE11有兼容模式,开启后有网页会出错. 在html header标签下加上 <meta http-equiv="X-UA-Compatib ...

  3. 《Web Development with Go》Middleware之共享数据

    这个库值得学, 好像写起来越来越溜 package main import ( "fmt" "log" "net/http" //" ...

  4. JavaScript-----10.作用域

    1.作用域 一段程序代码中所用到的名字不是总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域.目的是为了提高程序的可靠性,更重要的是减少命名冲突. 在es6之前,js的作用域有:全 ...

  5. 多对多表结构的设计ManyToManyField(不会生成某一列、生成一张表):

    示例: 脚本: from django.db import models# Create your models here. class Publisher(models.Model): name = ...

  6. doc 如何在指定的位置打印字符和颜色

    编程:在屏幕中间分别显示绿色,绿底红色,白底蓝色的字符串weclome to masm! B8000H~BFFFFH共32KB 的空间,为80*25彩色字符模式的显示缓冲区. 在80*25彩色字符模式 ...

  7. python - selenium模块简介

    为什么要使用Selenium? 很多浏览器渲染页面的方式都很难找出其规律, 但是利用Selenium来驱动加载网页就可以直接拿到javaScript渲染后的结果了, 不需要再担心其相关的加密系统 声明 ...

  8. Go语言常见坑

    可变参数是空接口类型当参数的可变参数是空接口类型时,传人空接口的切片时需要注意参数展开的问题.func main() { var a = []interface{}{1, 2, 3} fmt.Prin ...

  9. Java向上下转型中的陷阱{详细}

    1: 多态   多态时继承下面的产物,之所以存在向上向下转型的目的,就是解决参数传递的不变形,体现面向接口编程的重要性, 1.1 方法的多态性   ①. 方法的重载:同一个方法名称可以根据参数的类型或 ...

  10. SpringBoot入门(简单详细教程)

    Spring Boot 简介 简化Spring应用开发的一个框架:整个Spring技术栈的一个大整合:J2EE开发的一站式解决方案: 微服务 martin fowler:微服务:架构风格(服务微化): ...