I wrote little program for isolated word recognition using DTW algorithm. In folder with main program i have another folder "Data20dict", with 20 more folders in it, and each one is called by voice command, like copy, exit, input etc. Each of these 20 folders has aobut 20 utterances of this command, recorded in *.wav format. Total amount of utterances is 437. For DTW algorithm i use this module:https://github.com/pierre-rouanet/dtw.
My code is below:

from numpy.linalg import norm
from dtw import dtw
import os
import timeit
import librosa
from sklearn.model_selection import train_test_split

DATA_PATH = './Data20dict/'

train = dict()
test = dict()

#Read all sound files from all directories
#and create dictionary with all commands(keys) with their utterances
for path in sorted(os.listdir(DATA_PATH)):
    full_path = os.path.join(DATA_PATH, path)
    if os.path.isdir(full_path):
        class_name = path.upper()
        class_files = [os.path.join(full_path, f) for f in sorted(os.listdir(full_path))][:-15]
        waves = [librosa.load(file, sr=SAMPLE_RATE)[0] for file in class_files]
        train_waves, test_waves = train_test_split(waves, test_size=0.2)
        train[class_name] = train_waves
        test[class_name] = test_waves

train_mfccs = dict()
test_mfccs = dict()

#All utterances are transformed to mfcc matrices
for class_name in train:
    mfccs = []
    for sound in train[class_name]:
        mfcc = librosa.feature.mfcc(y = sound, sr = SAMPLE_RATE, hop_length = 512, n_mfcc = 13)
    train_mfccs[class_name] = mfccs

    mfccs = []
    for sound in test[class_name]:
        mfcc = librosa.feature.mfcc(y = sound, sr = SAMPLE_RATE, hop_length = 512, n_mfcc = 13)
    test_mfccs[class_name] = mfccs

#Each utternace from test samples compares with 
#all utternaces from train samples
correct_dtw = 0
total = 0
a = timeit.default_timer() 
for key_test, val_test in test_mfccs.items():
    for test_words in val_test:
        total += 1
        max_dist = [float("inf")]
        for key_train, val_train in train_mfccs.items():
            for train_words in val_train:
                dist, _, _, _ = dtw(test_words.T, train_words.T, dist=lambda x, y: norm(x - y, ord=1))
                if dist < max_dist:
                    max_dist = dist
                    output_label_dtw = key_train
        if key_test == output_label_dtw:
            correct_dtw += 1

dtw_time = timeit.default_timer() - a
print('\nNumber of test samples: {}'.format(total))
print('\nDTW: Correct recognized {} from {} test samples'.format(correct_dtw, total))
percent_correct_dtw = round((correct_dtw/total * 100.0),2)
print('\nDTW: Percent of recognition: ', percent_correct_dtw)
print('\nDTW: Spent time for recognition: ', dtw_time, 'seconds')

Results are next:
1 attempt:
Number of test samples: 34
DTW: Correct recognized 33 from 34 test samples
DTW: Percent of recognition: 97.06
DTW: Spent time for recognition: 35.58901049389533 seconds

2 attempt:
Number of test samples: 97
DTW: Correct recognized 96 from 97 test samples
DTW: Percent of recognition: 98.97
DTW: Spent time for recognition: 384.3671420063365 seconds

Do you have any ideas, what can slow my code, or how to improve it by decreasing time, needed for word recognition?

  • $\begingroup$ Have you profiled the script? $\endgroup$ – A_A May 24 '18 at 10:51
  • $\begingroup$ I didnt, but after your comment found how to do it, and made it The longest part is computing lambdas - norm x-y Dont know how to attach *.result file $\endgroup$ – R0stislav May 24 '18 at 11:51
  • $\begingroup$ Nice, first - i import fastdtw from given dtw module. Second - swapped my norm computing to the next codeline: dist, _, _, _ = fastdtw(test_words.T, train_words.T, 'euclidean'), and that did great job(of course for my project). Total time is decreased to 49.18780634997893 seconds (from 384.3671420063365 seconds ) Thanks! $\endgroup$ – R0stislav May 24 '18 at 12:02
  • $\begingroup$ ...you are...welcome (?) The only "problem" that we have now is that this question will be circulating forever as "unanswered". I see two possible ways forward: 1) You answer your own question and accept it, 2) You consider deleting the question as it did not turn out to be an incredibly challenging one (?). Option 1 might be the way to go given that we don't speak about profiling very frequently here and it would also possibly work better for your rep score too. All the best. $\endgroup$ – A_A May 24 '18 at 12:11
  • $\begingroup$ Will try not to forgive accepting my answer in 2 days $\endgroup$ – R0stislav May 24 '18 at 12:33

So, profiling works very well. Figured out that problem was in computing lambdas in dtw() function. For solving this i import fastdtw function from given dtw module:
from dtw import fastdtw
Next, the codeline
dist, _, _, _ = dtw(mfcctest.T, mfcctrain.T, dist=lambda x, y: norm(x - y, ord=1))
Should be swapped to
dist, _, _, _ = fastdtw(test_words, train_words.T, 'euclidean')
That way time greatly reduced, and code running almost 8x faster.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.