1. 自适应
做了说话人识别,就一直就一些疑问:
什么是 (领域)自适应(domain adaption)?它跟 迁移学习(Transfer Learning) 有什么区别?
做自适应最终的效果能到什么程度?
PLDA是什么?跟自适应的关系是什么?
作用
自适应的作用是,补偿实际数据与已经训练的三音素模型中声学条件不匹配的问题,包括说话人特性(说话方式、口音等)及环境特性(如录音设备、房间混响等)。
方法
(1)传统模型的自适应方法
在GMM-HMM模型中,自适应方法有特征空间变换和模型空间变换。Kaldi中主要采用的是特征空间变换方法(记住这个名称,后面会有解释): LDA、MLLT和fMLLR,其本质都是在训练过程中估计变换矩阵,然后构造变换后的特征,再迭代训练新的声学模型参数。
LDA+MLLT针对环境特性,拼接上下文多帧数据,再通过特征变换进行降维处理,因为与说话人无关,所以估计的是全局矩阵。
fMLLR针对说话人特性,基于每个说话人或每个utterance进行变换矩阵估计。
(2)深度神经网络的自适应方法
在DNN-HMM模型中,由于DNN的鉴别特性,GMM下的自适应方法不能直接拿来用,DNN下的自适应方法主要有线性变换、正则项法、子空间法(i-vector)。
迁移学习和自适应
简单粗暴的来说,自适应就是一种迁移学习的方法。
那如何理解自适应的本质?之前提到的”特征空间变换“又是什么意思?
领域自适应是迁移学习原先就有的概念,在研究源域和目标域时,基于某一特征,会发现两个域的数据分布差别很大。
假设要选择某一区域的颜色信息作为图像特征,上图红线表示source dataset的颜色信息值分布,蓝线表示target dataset的颜色信息值分布,很明显对于这一特征来讲,两个域的数据本来就是有shift的。而这个shift导致我们evaluate这个模型的时候准确率会大大降低,那么这个区域的颜色信息就不适合选择特征。
既然这个特征不合适,那我们就换特征。领域自适应旨在利用各种的feature transformation手段,学习一个域间不变的特征表达,基于这一特征,我们就可以更好的同时对两个域的数据进行分类了。
2. PLDA 自适应
PLDA
PLDA(Probabilistic Linear Discriminant Analysis)是一种信道补偿算法,号称概率形式的LDA算法,PLDA算法的信道补偿能力比LDA更好,已经成为目前最好的信道补偿算法。
建模
定义第i个说话人的第
j
j
j条语音为
x
x
xij,然后定义
x
x
xij的生成模型为:
x
i
j
=
μ
+
F
h
i
+
G
w
i
j
+
ϵ
i
j
x_{i j}=\mu+F h_{i}+G w_{i j}+\epsilon_{i j}
xij=μ+Fhi+Gwij+ϵij
模型分为两个部分:
- 信号部分: μ + F h i \mu+F h_{i} μ+Fhi,只与说话人身份有关,该项描述了个体之间的差异。
- 噪声部分: G w i j + ϵ i j G w_{i j}+\epsilon_{i j} Gwij+ϵij,同一个人每次说话也会有差异,描述了个体内部的差异。
- μ \mu μ是全体训练数据的平均值;
- F F F可以看做是身份空间,包含了可以用来表示各种身份的基底;
- h i h_i hi就可以看做是一个人的身份(或者是人物在身份空间中的位置);
- G可以看做是误差空间,包含了可以用来表示同一身份不同变化的基底;
- w i j w_{ij} wij表示的是在误差空间中的位置;
- ϵ i j \epsilon_{i j} ϵij 用来表示随机误差,该项为零均高斯分布,方差为 Σ。
由于我们只关心区分说话人,所以并不需要计算误差空间,所以可以把噪声部分的两项合并,则得到:
X
i
j
=
μ
+
F
h
i
+
ϵ
i
j
X_{i j}=\mu+F h_{i}+\epsilon_{i j}
Xij=μ+Fhi+ϵij,其中
ϵ
\epsilon
ϵ~N(0, Σ),
h
i
h_i
hi~N(0,1)。
我们注意到等号右边的中间两项分别是一个矩阵和一个向量的表示形式,这便是因子分析的又一核心部分。这两个矩阵F和G包含了各自假想变量空间中的基本因子,这些因子可以看做是各自空间的特征向量。比如,F的每一列就相当于类间空间的特征向量,G的每一列相当于类内空间的特征向量。而两个向量可以看做是分别在各自空间的特征表示,比如hi就可以看做是Xij在说话人空间中的特征表示。在识别打分阶段,如果两条语音的hi特征相同的似然度越大,那么这两条语音就更确定地属于同一个说话人。
训练
训练PLDA模型,就是通过训练数据估计出参数 ϕ \phi ϕ和 Σ Σ Σ。估计这两个参数的方法是经典EM算法迭代求解,即猜(E-step)-反思(M-step),重复。
实际上,在 Kaldi 中一般是用训练集的 ivector 来训练PLDA模型,再用于最后的打分。
(以ivector方法为例:训练集音频——mfcc特征——训练 UBM 和 ivector extractor——提取ivector特征——PLDA打分)
测试
在测试阶段,我们不再像LDA那样去基于consine距离来计算得分,而是去计算两条语音是否由说话人空间中的特征hi生成,或者由hi生成的似然程度,而不用去管类内空间的差异。在这里,我们使用对数似然比来计算得分。如下图所示:
n1和n2分别是两个语音的x-vector(或i-vector)矢量,这两条语音来自同一空间的假设为Hs,来自不同的空间的假设为Hd。
其中 p ( n 1 , n 2 ∣ h s ) p(n1, n2 | hs) p(n1,n2∣hs)为两条语音来自同一空间的似然函数;
p ( n 1 ∣ h d ) p(n1 | hd) p(n1∣hd), p ( n 2 ∣ h d ) p(n2 | hd) p(n2∣hd)分别为 n 1 n1 n1和 n 2 n2 n2来子不同空间的似然函数。通过计算对数似然比,就能衡量两条语音的相似程度。
得分越高,两条语音属于同一说话人的可能性越大。
具体的PLDA得分计算也有不同的实现。
Kladi中的源码解读
Plda的自适应类:
/*
This class takes unlabeled iVectors from the domain of interest and uses their
mean and variance to adapt your PLDA matrices to a new domain.
This class also stores stats for this form of adaptation.
*/
翻译:
这个类,从感兴趣的domain中读取未标记的ivector,用他们的均值和方差调整PLDA矩阵,转换为新的
domain,这个类同时会保存这个自适应的形式
class PldaUnsupervisedAdaptor {
public:
PldaUnsupervisedAdaptor(): tot_weight_(0.0) { }
// Add stats to this class. Normally the weight will be 1.0.
void AddStats(double weight, const Vector<double> &ivector);
void AddStats(double weight, const Vector<float> &ivector);
void UpdatePlda(const PldaUnsupervisedAdaptorConfig &config,
Plda *plda) const;
private:
double tot_weight_;
Vector<double> mean_stats_;
SpMatrix<double> variance_stats_;
};
需要注意的是,如果数据质量不行或者数据量不足,很可能会使得最后的识别效果变差!
更多请点击:关于PLDA在kaldi中的基础知识和代码完整版
参考: