4
4
# Apache 2.0
5
5
6
6
import torch
7
+ import torch .nn as nn
7
8
import torch .nn .functional as F
8
9
9
10
10
- def compute_delta_feat (x , weight ):
11
+ def compute_delta_feat (x , weight , enable_padding ):
11
12
'''
12
13
Args:
13
14
x: input feat of shape [batch_size, seq_len, feat_dim]
14
15
15
16
weight: coefficients for computing delta features;
16
- it has a shape of [feat_dim, 1, kernel_size].
17
+ it has shape [feat_dim, 1, kernel_size].
18
+
19
+ enable_padding: True to add padding.
17
20
18
21
Returns:
19
- a tensor fo shape [batch_size, seq_len, feat_dim]
22
+ a tensor of shape [batch_size, seq_len, feat_dim]
20
23
'''
21
24
22
25
assert x .ndim == 3
@@ -27,51 +30,61 @@ def compute_delta_feat(x, weight):
27
30
28
31
feat_dim = x .size (2 )
29
32
30
- pad_size = weight .size (2 ) // 2
33
+ if enable_padding :
34
+ pad_size = weight .size (2 ) // 2
31
35
32
- # F.pad requires a 4-D tensor in our case
33
- x = x .unsqueeze (0 )
36
+ # F.pad requires a 4-D tensor in our case
37
+ x = x .unsqueeze (0 )
34
38
35
- # (0, 0, pad_size, pad_size) == (left, right, top, bottom)
36
- padded_x = F .pad (x , (0 , 0 , pad_size , pad_size ), mode = 'replicate' )
39
+ # (0, 0, pad_size, pad_size) == (left, right, top, bottom)
40
+ x = F .pad (x , (0 , 0 , pad_size , pad_size ), mode = 'replicate' )
37
41
38
- # after padding, we have to convert it back to 3-D
39
- # since conv1d requires 3-D input
40
- padded_x = padded_x .squeeze (0 )
42
+ # after padding, we have to convert it back to 3-D
43
+ # since conv1d requires 3-D input
44
+ x = x .squeeze (0 )
41
45
42
46
# conv1d requires a shape of [batch_size, feat_dim, seq_len]
43
- padded_x = padded_x .permute (0 , 2 , 1 )
47
+ x = x .permute (0 , 2 , 1 )
44
48
45
49
# NOTE(fangjun): we perform a depthwise convolution here by
46
50
# setting groups == number of channels
47
- y = F .conv1d (input = padded_x , weight = weight , groups = feat_dim )
51
+ y = F .conv1d (input = x , weight = weight , groups = feat_dim )
48
52
49
- # now convert y back to be of shape [batch_size, seq_len, feat_dim]
53
+ # now convert y back to shape [batch_size, seq_len, feat_dim]
50
54
y = y .permute (0 , 2 , 1 )
51
55
52
56
return y
53
57
54
58
55
- class AddDeltasTransform :
59
+ class AddDeltasTransform ( nn . Module ) :
56
60
'''
57
61
This class implements `add-deltas` in kaldi with
58
62
order == 2 and window == 2.
59
63
60
- It generates the identical output as kaldi's `add-deltas` with default
61
- parameters given the same input.
64
+ It can generate the identical output as kaldi's `add-deltas`.
65
+
66
+ See transform_test.py
62
67
'''
63
68
64
- def __init__ (self ):
65
- # yapf: disable
66
- self .first_order_coef = torch .tensor ([- 0.2 , - 0.1 , 0 , 0.1 , 0.2 ])
67
- self .second_order_coef = torch .tensor ([0.04 , 0.04 , 0.01 , - 0.04 , - 0.1 , - 0.04 , 0.01 , 0.04 , 0.04 ])
68
- # yapf: enable
69
+ def __init__ (self ,
70
+ first_order_coef = [- 1 , 0 , 1 ],
71
+ second_order_coef = [1 , 0 , - 2 , 0 , 1 ],
72
+ enable_padding = False ):
73
+ '''
74
+ Note that this class has no trainable `nn.Parameters`.
75
+
76
+ Args:
77
+ first_order_coef: coefficient to compute the first order delta feature
78
+
79
+ second_order_coef: coefficient to compute the second order delta feature
80
+ '''
81
+ super ().__init__ ()
69
82
70
- # TODO(fangjun): change the coefficients to the following as suggested by Dan
71
- # [-1, 0, 1]
72
- # [1, 0, -2, 0, 1]
83
+ self . first_order_coef = torch . tensor ( first_order_coef )
84
+ self . second_order_coef = torch . tensor ( second_order_coef )
85
+ self . enable_padding = enable_padding
73
86
74
- def __call__ (self , x ):
87
+ def forward (self , x ):
75
88
'''
76
89
Args:
77
90
x: a tensor of shape [batch_size, seq_len, feat_dim]
@@ -94,9 +107,22 @@ def __call__(self, x):
94
107
self .first_order_coef = self .first_order_coef .to (device )
95
108
self .second_order_coef = self .second_order_coef .to (device )
96
109
97
- first_order = compute_delta_feat (x , self .first_order_coef )
98
- second_order = compute_delta_feat (x , self .second_order_coef )
99
-
100
- y = torch .cat ([x , first_order , second_order ], dim = 2 )
110
+ first_order = compute_delta_feat (x , self .first_order_coef ,
111
+ self .enable_padding )
112
+ second_order = compute_delta_feat (x , self .second_order_coef ,
113
+ self .enable_padding )
114
+
115
+ if self .enable_padding :
116
+ y = torch .cat ([x , first_order , second_order ], dim = 2 )
117
+ else :
118
+ zeroth = (x .size (1 ) - second_order .size (1 )) // 2
119
+ first = (first_order .size (1 ) - second_order .size (1 )) // 2
120
+
121
+ y = torch .cat ([
122
+ x [:, zeroth :- zeroth , :],
123
+ first_order [:, first :- first , :],
124
+ second_order ,
125
+ ],
126
+ dim = 2 )
101
127
102
128
return y
0 commit comments