最近上导师的语音识别的课,对DTW讲了很多,之前写的一篇是最简单的一个,打算抽时间写一个DTW系列的几篇,从最简单的DTW到近似HMM的DTW算法,通过一步一步的改进,希望能对语音识别前期的发展有更深入的了解。
——————————————- DTW (一)———————————————————–
这篇主要是整理一个最简单的例子,之前写的一篇整理一下,主要是一个序列作为模板 T,这个模板可以是一个单词的特征序列,也可以是一个单词的模板,求测试系列 S 的匹配的最佳路径,即路径长度最短, 从而计算对应的序列的相似度。
语音背景就是: 主要是在孤立词识别中做模版匹配时, 测试序列和模板序列的时间不一致,不能都从第一个点开始计算相似度,而应该找到波形相对应的点进行计算,这时候需要对测试序列的时间进行规整warping(使得feature to feature), 然后再计算相似度。
数据说明:模板序列 T = (t1, t2, …, tn)模板长度为n, 测试就序列 S = (s1,s2, …, sm)测试序列长度为m。 对应到语音中T有n帧特征,而S具有m帧特征,由于帧与帧之间是 可以计算距离的(一般可以用欧式距离),这里我们模拟定义一个 shape为(m, n) 距离矩阵的 A, 其中A(i, j) 表示 帧S(i) 与 T(j) 之间的欧式距离。
NOTE: i 和 j 有点乱:明天再整理一下。
demo ref: http://www.cnblogs.com/tornadomeet/archive/2012/03/23/2413363.html
#coding: utf-8
import numpy as np
# 假设T的长度是4,S的长度是6, A为S到T的距离矩阵
A = [[2, 1, 5, 1],
[3, 4, 8, 2],
[5, 2, 4, 3],
[4, 7, 2, 4],
[1, 5, 1, 6],
[2, 1, 7, 5]]
A = np.array(A)
m, n = A.shape
'''
定义距离条件,假设横轴是T(j), 1<=j<=n, 纵轴为S(i), 1<=i<=m:
1.由于存在时序关系,在(T(j),S(i))点 仅有三条出去到达三个点: (T(j+1), S(i)),(T(j),S(i+1)),(T(j+1),S(i+1))
2.定义一个累积距离矩阵D,D的shape跟A的shape一致,记录的是从(T(1),S(1))到达该点的最短路径,即最小loss
3.定义一个矩阵G,shape是(m,n,2), 记录的是到达D(i,j)时的前一时刻的坐标
4.需要注意的是t=1时刻的处理,即D(1,j) 和 D(i,1) 的值。
5.定义D(i,j)的递推式:
#为了方便理解,D能1开始计数,但A是从0开始计数
path1. D(i,j) = D(i-1, j) + A(i-1,j-1)
path2. D(i,j) = D(i-1, j-1) + 2*A(i-1,j-1)
path3. D(i,j) = D(i, j-1) + A(i-1,j-1)
D(i,j) = min(path1, path2, path3)
有点类似于Viterbi。
'''
D = np.ones((m+1, n+1))
G = np.ones((m+1, n+1, 2))
#D(1,1)点的计算,设D(0,0)为0
D[1][1] = 0 + 2 * A[0][0] #4
#D(1, j) 第一行的计算, j>=2
for j in range(2, n+1):
D[1][j] = D[1][j-1] + A[0][j-1]
#D(i,1) 第一列的计算,i>=2
for i in range(2, m+1):
D[i][1] = D[i-1][1] + A[i-1][0]
for i in range(2, m+1):
for j in range(2, n+1):
#一般情况
temp = [D[i-1][j]+A[i-1][j-1], D[i-1, j-1]+2*A[i-1][j-1], D[i, j-1] + A[i-1][j-1]]
sel_dict = {0:[i-1, j], 1:[i-1, j-1], 2:[i, j-1]}
min_index = temp.index(min(temp))
D[i][j] = min(temp)
G[i][j] = sel_dict[min_index]
print D
#当回溯到起点的时候
R = []
x, y =m, n
while x != 1 or y != 1:
temp = G[x][y]
R.append(temp)
a, b = temp
x = a
y = b
print R
R的返回值:
[array([ 5., 3.]), array([ 4., 3.]), array([ 3., 2.]), array([ 2., 2.]), array([ 1., 2.]), array([ 1., 1.])]
注意下标,我这里从1开始计数的。
-----OK