---
# System prepended metadata

title: Data Pre-process（DP）
tags: [Product Quantizer]

---

# Data Pre-process（DP）
###### tags: `Product Quantizer`
[ToC]
### 动机
进行PQ量化前对特征进行量化的动机还是很容易理解的，主要是原始特征有两个问题会使得量化误差变大
* 特征维度间非独立。特征的维度之中可能是非独立的，这样同样的码数表达的信息就会变少，也就会造成更大的量化误差。
* 特征间非平衡。这个问题更严重，原本特征间的方差是不相等的，举个清晰的例子，假设为了让特征独立对特征进行了PCA变化，这样变换后的特征方差是沿着维度逐渐减小并且变化非常明显，那么根据PQ的原理，他会每$D/m$个chanel作为一个子量化器，进行聚类。这时候问题就很明显来了，每个子量化器的方差可以看作其包含的所有chanel的方差之和。因此前面的量化器每个chanel的方差都很大，后面量化器方差都很小，但是，每一个子量化器的聚类中心数目都一样多，这样就会造成前面子量化器表达能力不足，后面的有余，最终的量化效果差。
### 方法
既然问题出在了特征间非独立和不平衡，那么一些解决方案也就自然的沿着这两条线索进行,一般的，如果要解决非独立的问题，基本上会对特征进行一个PCA降维，各种方法主要解决的问题一般是维度之间非平衡问题。需要注意的是，用PCA会大大加剧维度不平衡问题，那么就一定要使用量化器均衡的策略。
#### 维度动态比特分配

相关论文：
* Transform Coding for Fast Approximate Nearest Neighbor Search in High Dimensions
* Spectral Hashing
为了解决前面的维度方差大，信息量大的问题，就动态的分配每个特征维度分配到的比特数，方差大的维度分配给的量化比特就多，小的就少。
#### 随机正交旋转变换
![image alt](https://imgpile.com/images/N67lIE.png "title" =300x400)
上图中，$xoy$可以看作PCA后的数据分布，$x_{r}oy_{r}$可以看作一组正交基，将原始的数据映射到新的正交基，可以看作对其做了旋转操作，在新的坐标系中，数据在两个轴上的分布均衡，量化误差相应的也会变小。
相关论文：
* Aggregating Local Descriptors into a Compact Image Representation
* Iterative Quantization: A Procrustean Approach to Learning Binary Codes
将PCA后的特征，随机映射到一组随机标准正交基组成的空间中，可以保持原始特征间的相对位置关系（旋转具有保距性），并且由于维度很多，可以在统计意义上实现每个维度的方差均衡。（没找到数学证明随机旋转矩阵可以实现方差均衡），用swav网络提取的object365特征，共取了10万个样本，每个样本2048维度，对原始特征，PCA后的特征以及旋转后的特征各个维度的方差进行比较，结果如下图

![image alt](https://imgpile.com/images/Ng9D9R.png)
可以看到，PCA相对于原始特征，方差（能量）更加集中在少数的维度，三条曲线的平坦区，PCA的线是最低的，在旋转后，每个维度的能量变得非常均匀，同时，由于做的是正交变换，各个维度之间，仍然是独立的。
#### OPQ
随机旋转矩阵只是随机的选择一个正交矩阵进行映射，并不一定能保证数据在每一个维度的方差相等，或者说，没有结合真实的数据分布进行调整最优的旋转矩阵，那么是否可以根据一定的规则，找到最优的旋转矩阵呢？
相关论文：
Optimized Product Quantization
将旋转矩阵的优化放在PQ的训练中，以最小化量化误差为目标，交替优化聚类中心和旋转矩阵。
* 无参数模式：
![image alt](https://imgpile.com/images/NgD1mM.png)
步骤很简单，
* 初始化。首先初始化一个$R$,可以用随机正交矩阵作为初始化起点。然后初始化聚类中心$\{C^m\}^{M}_{m=1}$以及所有$x$的聚类index $\{i^{m}\}_{m=1}^{M}$，这一个可以通过对数据进行几个iter的聚类得到一个初步结果。
* 循环主体
    1.优化codebook。所有数据乘以旋转矩阵，得到旋转后的数据$\hat{x}$.然后对于每一个sub quantizer，用属于每一个聚类中心的所有$\hat{x}$的均值来计算旋转后的聚类中心$\hat{x}^m(j)$,然后再反过来用这些更新的聚类中心算出所有$\hat{x}$的新的映射index.
    2.优化旋转矩阵。将旋转矩阵求解看作一个优化问题，使得原始数据（如果前面有PCA步骤，那么则是PCA后的数据）经过旋转矩阵后得到的数据$X$，与$X$经过量化器encode-decode后的数据$Y$之间的误差最小，公式表达为：
   $$\substack{min\\R}||RX-Y||_{F}^{2},...X^{\in D*n},Y^{\in D*n},R^{\in D*D}$$
    $$s.t. R^{T}R=I$$
    其中$||.||_{F}$是个矩阵范数，代表矩阵所有元素的和。这个优化问题有固定的解法，叫做 *Orthogonal Procrustes problem*，对$XY^T$进行奇异值分解，$XY^T=USV^T$,然后$R=VU^T$,详细证明见[正交普鲁克问题](https://blog.csdn.net/itnerd/article/details/104598742)
    
  循环进行上述两个步骤进行一定的Iter数目，使得误差足够小。一般来说，作者给出的经验值是100个iter就够了。相对于直接使用一个随机初矩阵来说，这种结合数据特性进行迭代优化的方法更能贴合数据，求得更优的旋转矩阵。代价就是训练过程会穿插一个SVD分解，不过由于训练对于搜索来说一般不经常发生，所以是可以接受的。
  
### 补充一个我对SVD物理含义的理解
[从数据降维角度理解SVD](https://hackmd.io/g1t_9vMOTVWs_2bnQeKCEw)


