编程语言
首页 > 编程语言> > 【语音识别】基于矢量量化(VQ)说话人识别matlab源码

【语音识别】基于矢量量化(VQ)说话人识别matlab源码

作者:互联网

一、简介

矢量量化方法,即vector quantization,其具体定义为:将一个向量空间中的点用其中的一个有限子集来进行编码的过程。在矢量量化编码中,关键是码本的建立和码字搜索算法。比如常见的聚类算法,就是一种矢量量化方法。而在ANN近似最近邻搜索中,向量量化方法又以乘积量化(PQ, Product Quantization)最为典型。在之前的博文基于内容的图像检索技术的最后,对PQ乘积量化的方法做过简单的概要。在这一小节里,小白菜结合自己阅读的论文和代码对PQ乘积量化、倒排乘积量化(IVFPQ)做一种更加直观的解释。
1 PQ乘积量化
PQ乘积量化的核心思想还是聚类,或者说具体应用到ANN近似最近邻搜索上,K-Means是PQ乘积量化子空间数目为1的特例。PQ乘积量化生成码本和量化的过程可以用如下图示来说明:
在这里插入图片描述
在训练阶段,针对N个训练样本,假设样本维度为128维,我们将其切分为4个子空间,则每一个子空间的维度为32维,然后我们在每一个子空间中,对子向量采用K-Means对其进行聚类(图中示意聚成256类),这样每一个子空间都能得到一个码本。这样训练样本的每个子段,都可以用子空间的聚类中心来近似,对应的编码即为类中心的ID。如图所示,通过这样一种编码方式,训练样本仅使用的很短的一个编码得以表示,从而达到量化的目的。对于待编码的样本,将它进行相同的切分,然后在各个子空间里逐一找到距离它们最近的类中心,然后用类中心的id来表示它们,即完成了待编码样本的编码。

正如前面所说的,在矢量量化编码中,关键是码本的建立和码字的搜索算法,在上面,我们得到了建立的码本以及量化编码的方式。剩下的重点就是查询样本与dataset中的样本距离如何计算的问题了。

在查询阶段,PQ同样在计算查询样本与dataset中各个样本的距离,只不过这种距离的计算转化为间接近似的方法而获得。PQ乘积量化方法在计算距离的时候,有两种距离计算方式,一种是对称距离,另外一种是非对称距离。非对称距离的损失小(也就是更接近真实距离),实际中也经常采用这种距离计算方式。下面过程示意的是查询样本来到时,以非对称距离的方式(红框标识出来的部分)计算到dataset样本间的计算示意:
在这里插入图片描述
具体地,查询向量来到时,按训练样本生成码本的过程,将其同样分成相同的子段,然后在每个子空间中,计算子段到该子空间中所有聚类中心得距离,如图中所示,可以得到4*256个距离,这里为便于后面的理解说明,小白菜就把这些算好的距离称作距离池。在计算库中某个样本到查询向量的距离时,比如编码为(124, 56, 132, 222)这个样本到查询向量的距离时,我们分别到距离池中取各个子段对应的距离即可,比如编码为124这个子段,在第1个算出的256个距离里面把编号为124的那个距离取出来就可,所有子段对应的距离取出来后,将这些子段的距离求和相加,即得到该样本到查询样本间的非对称距离。所有距离算好后,排序后即得到我们最终想要的结果。

从上面这个过程可以很清楚地看出PQ乘积量化能够加速索引的原理:即将全样本的距离计算,转化为到子空间类中心的距离计算。比如上面所举的例子,原本brute-force search的方式计算距离的次数随样本数目N成线性增长,但是经过PQ编码后,对于耗时的距离计算,只要计算4*256次,几乎可以忽略此时间的消耗。另外,从上图也可以看出,对特征进行编码后,可以用一个相对比较短的编码来表示样本,自然对于内存的消耗要大大小于brute-force search的方式。

在某些特殊的场合,我们总是希望获得精确的距离,而不是近似的距离,并且我们总是喜欢获取向量间的余弦相似度(余弦相似度距离范围在[-1,1]之间,便于设置固定的阈值),针对这种场景,可以针对PQ乘积量化得到的前top@K做一个brute-force search的排序。
2 倒排乘积量化
倒排PQ乘积量化(IVFPQ)是PQ乘积量化的更进一步加速版。其加速的本质逃不开小白菜在最前面强调的是加速原理:brute-force搜索的方式是在全空间进行搜索,为了加快查找的速度,几乎所有的ANN方法都是通过对全空间分割,将其分割成很多小的子空间,在搜索的时候,通过某种方式,快速锁定在某一(几)子空间,然后在该(几个)子空间里做遍历。在上一小节可以看出,PQ乘积量化计算距离的时候,距离虽然已经预先算好了,但是对于每个样本到查询样本的距离,还是得老老实实挨个去求和相加计算距离。但是,实际上我们感兴趣的是那些跟查询样本相近的样本(小白菜称这样的区域为感兴趣区域),也就是说老老实实挨个相加其实做了很多的无用功,如果能够通过某种手段快速将全局遍历锁定为感兴趣区域,则可以舍去不必要的全局计算以及排序。倒排PQ乘积量化的”倒排“,正是这样一种思想的体现,在具体实施手段上,采用的是通过聚类的方式实现感兴趣区域的快速定位,在倒排PQ乘积量化中,聚类可以说应用得淋漓尽致。

倒排PQ乘积量化整个过程如下图所示:
在这里插入图片描述
在PQ乘积量化之前,增加了一个粗量化过程。具体地,先对N个训练样本采用K-Means进行聚类,这里聚类的数目一般设置得不应过大,一般设置为1024差不多,这种可以以比较快的速度完成聚类过程。得到了聚类中心后,针对每一个样本x_i,找到其距离最近的类中心c_i后,两者相减得到样本x_i的残差向量(x_i-c_i),后面剩下的过程,就是针对(x_i-c_i)的PQ乘积量化过程,此过程不再赘述。

在查询的时候,通过相同的粗量化,可以快速定位到查询向量属于哪个c_i(即在哪一个感兴趣区域),然后在该感兴趣区域按上面所述的PQ乘积量化距离计算方式计算距离。

二、源代码

function mfc=my_mfcc(x,fs)
%MY_MFCC:获取Speaker recognition的参数
%x:输入语音信号  fs:采样率
%mfc:十二个mfcc系数和一个能量 以及一阶和二阶差分 共36个参数 每一行为一帧数据
%clc,clear
%[x,fs]=audioread('wo6.wav');
N=256;p=24;
bank=mel_banks(p,N,fs,0,fs/2);
% 归一化mel滤波器组系数
bank=full(bank);
bank=bank/max(bank(:));

% 归一化倒谱提升窗口
w = 1 + 6 * sin(pi * [1:12] ./ 12);
w = w/max(w);

% 预加重滤波器
x=double(x);
x=filter([1 -0.9375],1,x);

% 语音信号分帧
sf=check_ter(x,N,128,10);

x=div_frame(x,N,128);
%sf=sp_ter(x,4,16);
%m=zeros(size(x,1),13);
m=zeros(1,13);
% 计算每帧的MFCC参数
for i=1:size(x,1)
    if sf(i)==1
        % j=j+1;
         y = x(i,:);
         y = y' .* hamming(N);
         energy=log(sum(y.^2)+eps);%能量
         y = abs(fft(y));
         y = y.^2+eps;
        c1=dct(log(bank * y));
        c2 = c1(2:13).*w';%取2~13个系数
        %m(i,:)=[c2;energy]';
        m1=[c2;energy]';
        %m1=c2';
        m=[m;m1];
    end
    
end

%差分系数
dm = zeros(size(m));
dmm= zeros(size(m));
for i=2:size(m,1)-1
  dm(i,:) = (m(i,:) - m(i-1,:));
end
for i=3:size(m,1)-2
  dmm(i,:) = (dm(i,:) - dm(i-1,:));
end
%dm = dm / 3;
function v=lbg(x,k)
%lbg:完成lbg均值聚类算法
% lbg(x,k) 对输入样本x,分成k类。其中,x为row*col矩阵,每一列为一个样本,
% 每个样本有row个元素。
% [v1 v2 v3 ...vk]=lbg(...)返回k个分类,其中vi为结构体,vi.num为该类
% 中含有元素个数,vi.ele(i)为第i个元素值,vi.mea为相应类别的均值

[row,col]=size(x);
%u=zeros(row,k);%每一列为一个中心值
epision=0.03;%选择epision参数
delta=0.01;
%u2=zeros(row,k);
%LBG算法产生k个中心
u=mean(x,2);%第一个聚类中心,总体均值
for i3=1:log2(k)
    u=[u*(1-epision),u*(1+epision)];%双倍
    %time=0;
    D=0;
    DD=1;
    while abs(D-DD)/DD>delta   %sum(abs(u2(:).^2-u(:).^2))>0.5&&(time<=80)   %u2~=u
        DD=D;
        for i=1:2^i3            %初始化
            v(i).num=0;
            v(i).ele=zeros(row,1);
        end
        for i=1:col %第i个样本
            distance=dis(u,x(:,i));%第i个样本到各个中心的距离
            [val,pos]=min(distance);
             v(pos).num=v(pos).num+1;%元素的数量加1
            if v(pos).num==1    %ele为空
                v(pos).ele=x(:,i);
            else
                v(pos).ele=[v(pos).ele,x(:,i)];
            end
        end
        for i=1:2^i3 
            u(:,i)=mean(v(i).ele,2);%新的均值中心
            for m=1:size(v(i).ele,2)
                D=D+sum((v(i).ele(m)-u(:,i)).^2);
            end
        end
    end
end

三、运行结果

在这里插入图片描述

四、备注

完整代码或者代写添加QQ1575304183

往期回顾>>>>>>

【信号处理】基于HMM的睡眠状态检测matlab源码

【语音识别】基于BP神经网络的语音情感识别matlab源码

【情感识别】基于改进KNN语音情感分类识别malab源码含GUI

【语音识别】基于高斯混合模型(GMM)的语音识别matlab源码

【语音识别】基于动态时间规整(DTW)的孤立字语音识别matlab源码

【语音识别】基于隐马尔可夫模型(HMM)的孤立字语音识别matlab源码

标签:PQ,乘积,样本,距离,VQ,源码,聚类,量化,识别
来源: https://blog.csdn.net/qq_34763204/article/details/115799963