基于动态时间规整算法(DTW)的相似度计算
在孤立词语音识别中,最为简单有效的方法是采用DTW(Dynamic Time Warping,动态时间归整)算法。
该算法基于动态规划(DP)的思想,解决了发音长短不一的模板匹配问题,是语音识别中出现较早、较为经典的一种算法,用于孤立词识别。
该算法由日本学者Itakura提出,它的本质是一种衡量两个长度不同的时间序列的相似度的方法。
在大部分的学科中,时间序列是数据的一种常见表示形式。对于时间序列处理来说,一个普遍的任务就是比较两个序列的相似性。
在时间序列中,需要比较相似性的两段时间序列的长度可能并不相等,在语音识别领域表现为不同人的语速不同。
因为语音信号具有相当大的随机性,即使同一个人在不同时刻发同一个音,也不可能具有完全的时间长度。
而且同一个单词内的不同音素的发音速度也不同,比如有的人会把“A”这个音拖得很长,或者把“i”发的很短。
例如图A所示,实线和虚线分别是同一个词“pen”的两个语音波形(在y轴上拉开了,以便观察)。
可以看到他们整体上的波形形状很相似,但在时间轴上却是不对齐的。
例如在第20个时间点的时候,实线波形的a点会对应于虚线波形的b’点,这样传统的通过比较距离来计算相似性很明显不靠谱。因为很明显,实线的a点对应虚线的b点才是正确的。
我们在比较上述两个时间序列时,需要将其中一个(或者两个)序列在时间轴下warping扭曲,以达到更好的对齐。而DTW就是实现这种warping扭曲的一种有效方法。DTW通过把时间序列进行延伸和缩短,来计算两个时间序列性之间的相似性。
举一个相对通俗的例子,当然通俗意味着并不那么严谨。
有两个人都拼写了cat这个单词,我们对他们的声音以0.5s/次的频率进行采样,记录的值是对应26个字母的序号。
第一个人花了1.5秒读完,他的采样数据为序列 Q{3,1,20},也就是说他在第一个0.5秒报出了字母c,在第二个0.5秒报出了字母a,在第三个0.5秒报出了字母t。
第二个人花了2.5秒读完,他的采样数据为序列 C{3,3,1,1,20},可以认为他在报字母c,a时发音比较长各用去1秒,然后在第五个0.5秒报出了字母t。
那如果要用计算机来识别他们所报的是不是同一个单词,该怎么办呢?
由于两个人的时间序列的特征值数量不一致,所以不能将它们转为统一纬度空间的点进行欧几里德的距离计算。
我们采取的办法是将Q[1]与C[1],C[2]/Q[2]与C[3],C[4]一对多的进行比较。而dtw算法就是帮助我们在更为复杂的数据下找出这样的特征值映射关系。
下面我们开始介绍dtw算法,在介绍时会以上面这个例子作为辅助。
假设我们有两个时间序列Q和C,他们的长度分别是n和m。实际语音匹配运用中,一个序列为参考模板,一个序列为测试模板,序列中的每个点的值为语音序列中每一帧的特征值。
Q = q1, q2,…,qi,…, qn ;
C = c1, c2,…, cj,…, cm ;
如果以上面的例子为例,那么序列应该为:
Q=3,1,20
C=3,3,1,1,20
为了对齐这两个序列,我们需要构造一个n x m的矩阵网格,矩阵元素(i, j)表示qi和cj两个点的距离d(qi, cj),一般采用欧几里德距离。以矩阵元素[1,1]=0为例,他的值就是q1与c1的哦欧几里德距离。
dtw算法可以归结为寻找一条通过此网格中若干格点的路径。
我们把这条路径定义为warping path规整路径,并用W来表示, W的第k个元素定义为wk=(i,j),i和j分别为矩阵的行数和列数。表示路径中的第k点经过矩阵中的元素(i,j)。
这条路径的现实意义就是为我们描述了两个时间序列特征点映射关系。比如w1=(1,1),它表示的就是q1应该与c1进行比较。
这条路径不是随意选择的,需要满足以下几个约束:
1.边界条件
路径的第一个元素为(1, 1),最后一个元素为(m, n)。原因是显而易见的,任何一种语音的发音快慢都有可能变化,但是其各部分的先后次序不可能改变。
也就是说q1一定是和c1进行比较,而qn一定是和cm进行比较,这是非常好理解的。
2.连续性
如果wk-1= (a’, b’),那么对于路径的下一个点wk=(a, b)需要满足 (a-a’) <=1和 (b-b’) <=1。也就是不可能跨过某个点去匹配,只能和自己相邻的点对齐。
这个也非常好理解,我们用上面的例子接着说。
我们将c1,c2一起和q1比较,有非常合理的解释:第一个人的c字母用了0.5秒,而第二个人用了1秒。
但是如果将c1,c3一起喝q1进行比较,将c2和q2进行比较就无论如何找不出一个合理的解释了。
3.单调性
如果wk-1= (a’, b’),那么对于路径的下一个点wk=(a, b)需要满足0<=(a-a’)和0<= (b-b’)。这限制W上面的点必须是随着时间单调进行的。
这个我们也可以很直观的认同。
在匹配两个人的是否报出同一个单词时,肯定也是从头到尾依次进行比较的。
结合连续性和单调性约束,每一个格点的路径就只有三个方向了。例如如果路径已经通过了格点(i, j),那么下一个通过的格点只可能是下列三种情况之一:(i+1, j),(i, j+1)或者(i+1, j+1)。
我们把矩阵元素看成点,把箭头看出点之间的有向加权边,那么每一条边的权重或者说距离是多少呢?答案就是箭头指向元素的值。
好了,现在我们已经把问题转变成了在有向加权图中寻找一条确定起点和终点的最短路径了。
我们就以上面的cat矩阵为例子,一步一步来寻找这条最短路径,并且尝试揭示其背后每一步的意义所在。
w1=(1,1),这是这条最短路径的确定起点,由边界条件决定。
现在下一步的路径有3个选择,(1,1)->(1,2)的距离为0,(1,1)->(2,1)的距离为2,(1,1)->(2,2)的距离为2,根据最短路径算法我们选择移动到(1,2),即w2=(2,1)。
这一步的背后的现实意义是什么呢?我们发现q1没有发生变化而c1前进至了c2,这是告诉我们把c1和c2一起和q1比较是使两者最为相似的一种比较方法。
按照最短路径的算法计算(这里不再赘述),我们最终可以得到下面的最短路径,(1,1)->(1,2)->(2,3)->(2,4)->(3,5)。
这条路径和我们之前所说的"将Q[1]与C[1],C[2]/Q[2]与C[3],C[4]一对多的进行比较"完全一致。
而我们将这条路径中所有边的距离加起来,就是这两个时间序列比较后的差异(类似长度相同序列转化为多维空间欧后计算的几里德距离)。
具体到这个例子中,我们可以看到距离=0,也就是说我们识别出了这两个人说的是同一个单词。
相信到这里大家已经从现实意义上理解了dtw的算法和它背后的现实意义。
大家在网上可以找到很多关于dtw的文章,上面有很多公式你看着头晕,其实其中的大部分都是用数学角度描述有向加权图的最短路径搜索,懂得自然懂。
网上基本用的是动态规划,你也可以用迪克斯特拉算法,总而言之这些都只是求最短路径的手段。千万要先站着宏观的角度搞清楚整个算法想干什么再着眼于具体的公式,不然初学者很容易被绕晕。
最后我们简单的说一下,这个算法在现实世界中时如何用的。
假定一个孤立字(词)语音识别系统,利用模板匹配法进行识别。
这时一般是把整个单词作为识别单元。在训练阶段,用户将词汇表中的每一个单词说一遍,提取特征后作为一个模板,存入模板库。
在识别阶段,对一个新来的需要识别的词,也同样提取特征,然后采用DTW算法和模板库中的每一个模板进行匹配,计算距离。求出最短距离也就是最相似的那个就是识别出来的字了。
该算法基于动态规划(DP)的思想,解决了发音长短不一的模板匹配问题,是语音识别中出现较早、较为经典的一种算法,用于孤立词识别。
该算法由日本学者Itakura提出,它的本质是一种衡量两个长度不同的时间序列的相似度的方法。
在大部分的学科中,时间序列是数据的一种常见表示形式。对于时间序列处理来说,一个普遍的任务就是比较两个序列的相似性。
在时间序列中,需要比较相似性的两段时间序列的长度可能并不相等,在语音识别领域表现为不同人的语速不同。
因为语音信号具有相当大的随机性,即使同一个人在不同时刻发同一个音,也不可能具有完全的时间长度。
而且同一个单词内的不同音素的发音速度也不同,比如有的人会把“A”这个音拖得很长,或者把“i”发的很短。
![](http://www.verycto.com/uploads/151005/20130620200710531.jpg)
可以看到他们整体上的波形形状很相似,但在时间轴上却是不对齐的。
例如在第20个时间点的时候,实线波形的a点会对应于虚线波形的b’点,这样传统的通过比较距离来计算相似性很明显不靠谱。因为很明显,实线的a点对应虚线的b点才是正确的。
我们在比较上述两个时间序列时,需要将其中一个(或者两个)序列在时间轴下warping扭曲,以达到更好的对齐。而DTW就是实现这种warping扭曲的一种有效方法。DTW通过把时间序列进行延伸和缩短,来计算两个时间序列性之间的相似性。
举一个相对通俗的例子,当然通俗意味着并不那么严谨。
有两个人都拼写了cat这个单词,我们对他们的声音以0.5s/次的频率进行采样,记录的值是对应26个字母的序号。
第一个人花了1.5秒读完,他的采样数据为序列 Q{3,1,20},也就是说他在第一个0.5秒报出了字母c,在第二个0.5秒报出了字母a,在第三个0.5秒报出了字母t。
由于两个人的时间序列的特征值数量不一致,所以不能将它们转为统一纬度空间的点进行欧几里德的距离计算。
我们采取的办法是将Q[1]与C[1],C[2]/Q[2]与C[3],C[4]一对多的进行比较。而dtw算法就是帮助我们在更为复杂的数据下找出这样的特征值映射关系。
下面我们开始介绍dtw算法,在介绍时会以上面这个例子作为辅助。
假设我们有两个时间序列Q和C,他们的长度分别是n和m。实际语音匹配运用中,一个序列为参考模板,一个序列为测试模板,序列中的每个点的值为语音序列中每一帧的特征值。
Q = q1, q2,…,qi,…, qn ;
如果以上面的例子为例,那么序列应该为:
Q=3,1,20
C=3,3,1,1,20
为了对齐这两个序列,我们需要构造一个n x m的矩阵网格,矩阵元素(i, j)表示qi和cj两个点的距离d(qi, cj),一般采用欧几里德距离。以矩阵元素[1,1]=0为例,他的值就是q1与c1的哦欧几里德距离。
![](http://www.verycto.com/uploads/151005/%28Y%7BRME7HNR[DR[N97N9@KLI.png)
dtw算法可以归结为寻找一条通过此网格中若干格点的路径。
我们把这条路径定义为warping path规整路径,并用W来表示, W的第k个元素定义为wk=(i,j),i和j分别为矩阵的行数和列数。表示路径中的第k点经过矩阵中的元素(i,j)。
这条路径的现实意义就是为我们描述了两个时间序列特征点映射关系。比如w1=(1,1),它表示的就是q1应该与c1进行比较。
这条路径不是随意选择的,需要满足以下几个约束:
1.边界条件
路径的第一个元素为(1, 1),最后一个元素为(m, n)。原因是显而易见的,任何一种语音的发音快慢都有可能变化,但是其各部分的先后次序不可能改变。
也就是说q1一定是和c1进行比较,而qn一定是和cm进行比较,这是非常好理解的。
2.连续性
如果wk-1= (a’, b’),那么对于路径的下一个点wk=(a, b)需要满足 (a-a’) <=1和 (b-b’) <=1。也就是不可能跨过某个点去匹配,只能和自己相邻的点对齐。
这个也非常好理解,我们用上面的例子接着说。
我们将c1,c2一起和q1比较,有非常合理的解释:第一个人的c字母用了0.5秒,而第二个人用了1秒。
但是如果将c1,c3一起喝q1进行比较,将c2和q2进行比较就无论如何找不出一个合理的解释了。
3.单调性
如果wk-1= (a’, b’),那么对于路径的下一个点wk=(a, b)需要满足0<=(a-a’)和0<= (b-b’)。这限制W上面的点必须是随着时间单调进行的。
这个我们也可以很直观的认同。
在匹配两个人的是否报出同一个单词时,肯定也是从头到尾依次进行比较的。
结合连续性和单调性约束,每一个格点的路径就只有三个方向了。例如如果路径已经通过了格点(i, j),那么下一个通过的格点只可能是下列三种情况之一:(i+1, j),(i, j+1)或者(i+1, j+1)。
![](http://www.verycto.com/uploads/151005/X9HDQSGA%29S6ERQSA%281WEX%7DN.png)
好了,现在我们已经把问题转变成了在有向加权图中寻找一条确定起点和终点的最短路径了。
我们就以上面的cat矩阵为例子,一步一步来寻找这条最短路径,并且尝试揭示其背后每一步的意义所在。
w1=(1,1),这是这条最短路径的确定起点,由边界条件决定。
现在下一步的路径有3个选择,(1,1)->(1,2)的距离为0,(1,1)->(2,1)的距离为2,(1,1)->(2,2)的距离为2,根据最短路径算法我们选择移动到(1,2),即w2=(2,1)。
![](http://www.verycto.com/uploads/151005/1.png)
按照最短路径的算法计算(这里不再赘述),我们最终可以得到下面的最短路径,(1,1)->(1,2)->(2,3)->(2,4)->(3,5)。
![](http://www.verycto.com/uploads/151005/2.png)
而我们将这条路径中所有边的距离加起来,就是这两个时间序列比较后的差异(类似长度相同序列转化为多维空间欧后计算的几里德距离)。
具体到这个例子中,我们可以看到距离=0,也就是说我们识别出了这两个人说的是同一个单词。
相信到这里大家已经从现实意义上理解了dtw的算法和它背后的现实意义。
大家在网上可以找到很多关于dtw的文章,上面有很多公式你看着头晕,其实其中的大部分都是用数学角度描述有向加权图的最短路径搜索,懂得自然懂。
网上基本用的是动态规划,你也可以用迪克斯特拉算法,总而言之这些都只是求最短路径的手段。千万要先站着宏观的角度搞清楚整个算法想干什么再着眼于具体的公式,不然初学者很容易被绕晕。
最后我们简单的说一下,这个算法在现实世界中时如何用的。
假定一个孤立字(词)语音识别系统,利用模板匹配法进行识别。
这时一般是把整个单词作为识别单元。在训练阶段,用户将词汇表中的每一个单词说一遍,提取特征后作为一个模板,存入模板库。
在识别阶段,对一个新来的需要识别的词,也同样提取特征,然后采用DTW算法和模板库中的每一个模板进行匹配,计算距离。求出最短距离也就是最相似的那个就是识别出来的字了。
DTW为(Dynamic Time Warping,动态时间归准)的简称。应用很广,主要是在模板匹配中,比如说用在孤立词语音识别,计算机视觉中的行为识别,信息检索等中。可能大家学过这些类似的课程都看到过这个算法,公式也有几个,但是很抽象,当时看懂了但不久就会忘记,因为没有具体的实例来加深印象。
这次主要是用语音识别课程老师上课的一个题目来理解DTW算法。
首先还是介绍下DTW的思想:假设现在有一个标准的参考模板R,是一个M维的向量,即R={R(1),R(2),……,R(m),……,R(M)},每个分量可以是一个数或者是一个更小的向量。现在有一个才测试的模板T,是一个N维向量,即T={T(1),T(2),……,T(n),……,T(N)}同样每个分量可以是一个数或者是一个更小的向量,注意M不一定等于N,但是每个分量的维数应该相同。
由于M不一定等于N,现在要计算R和T的相似度,就不能用以前的欧式距离等类似的度量方法了。那用什么方法呢?DTW就是为了解决这个问题而产生的。
首先我们应该知道R中的一个分量R(m)和T中的一个分量T(n)的维数是相同的,它们之间可以计算相似度(即距离)。在运用DTW前,我们要首先计算R的每一个分量和T中的每一个分量之间的距离,形成一个M*N的矩阵。(为了方便,行数用将标准模板的维数M,列数为待测模板的维数N)。
然后下面的步骤该怎么计算呢?用个例子来看看。
这个例子中假设标准模板R为字母ABCDEF(6个),测试模板T为1234(4个)。R和T中各元素之间的距离已经给出。如下:
既然是模板匹配,所以各分量的先后匹配顺序已经确定了,虽然不是一一对应的。现在题目的目的是要计算出测试模板T和标准模板R之间的距离。因为2个模板的长度不同,所以其对应匹配的关系有很多种,我们需要找出其中距离最短的那条匹配路径。现假设题目满足如下的约束:当从一个方格((i-1,j-1)或者(i-1,j)或者(i,j-1))中到下一个方格(i,j),如果是横着或者竖着的话其距离为d(i,j),如果是斜着对角线过来的则是2d(i,j).其约束条件如下图像所示:
其中g(i,j)表示2个模板都从起始分量逐次匹配,已经到了M中的i分量和T中的j分量,并且匹配到此步是2个模板之间的距离。并且都是在前一次匹配的结果上加d(i,j)或者2d(i,j),然后取最小值。
所以我们将所有的匹配步骤标注后如下:
怎么得来的呢?比如说g(1,1)=4, 当然前提都假设是g(0,0)=0,就是说g(1,1)=g(0,0)+2d(1,1)=0+2*2=4.
g(2,2)=9是一样的道理。首先如果从g(1,2)来算的话是g(2,2)=g(1,2)+d(2,2)=5+4=9,因为是竖着上去的。
如果从g(2,1)来算的话是g(2,2)=g(2,1)+d(2,2)=7+4=11,因为是横着往右走的。
如果从g(1,1)来算的话,g(2,2)=g(1,1)+2*d(2,2)=4+2*4=12.因为是斜着过去的。
综上所述,取最小值为9. 所有g(2,2)=9.
当然在这之前要计算出g(1,1),g(2,1),g(1,2).因此计算g(I,j)也是有一定顺序的。
其基本顺序可以体现在如下:
计算了第一排,其中每一个红色的箭头表示最小值来源的那个方向。当计算了第二排后的结果如下:
最后都算完了的结果如下:
到此为止,我们已经得到了答案,即2个模板直接的距离为26. 我们还可以通过回溯找到最短距离的路径,通过箭头方向反推回去。如下所示:
到这里,估计大家动手算一下就会明白了。其实很简单,通过例子的学习后再回去看那些枯燥的理论公式就发现很容易了。
在实际应用中,比如说语音识别中的孤立词识别,我们首先训练好常见字的读音,提取特征后作为一个模板。当需要识别一个新来的词的时候,也同样提取特征,然后和训练数据库中的每一个模板进行匹配,计算距离。求出最短距离的那个就是识别出来的字了。
matlab代码:
function dist = dtw(t,r) n = size(t,1); m = size(r,1); % 帧匹配距离矩阵 d = zeros(n,m); for i = 1:n for j = 1:m d(i,j) = sum((t(i,:)-r(j,:)).^2); end end % 累积距离矩阵 D = ones(n,m) * realmax; D(1,1) = d(1,1); % 动态规划 for i = 2:n for j = 1:m D1 = D(i-1,j); if j>1 D2 = D(i-1,j-1); else D2 = realmax; end if j>2 D3 = D(i-1,j-2); else D3 = realmax; end D(i,j) = d(i,j) + min([D1,D2,D3]); end end dist = D(n,m);