-
Notifications
You must be signed in to change notification settings - Fork 0
/
preprocessing_pipeline.py
140 lines (108 loc) · 4.1 KB
/
preprocessing_pipeline.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import os
import pickle
import librosa
import numpy as np
'''
This module is created to aid the user when preprocessing
data from any DataSet to use in the auto encoder
Components available in this module are:
1. Loader
2. Saver
3. Padder
4. Normalizer
5. Extractor
'''
class PreprocessingPipeline:
'''
Performs all the task necessary for preprocessing any data
for the purpose of using the preprocessed data in the my
variational autoencoder
'''
def __init__(self):
#Major components
self._loader = None
self.saver = None
self.padder = None
self.extractor = None
self.normalizer = None
self.min_max = {}
self._samples_num = None
def process(self, data_path):
#Process each file found in the directory
for root, _, files in os.walk(data_path):
for file in files:
file_path = os.path.join(root, file)
self._process_file(file_path)
print(f'processed {file}...')
self.saver.save_min_max(self.min_max) #Save original min-max values
def _process_file(self, file_path):
signal = self.loader.load_sound(file_path)
if len(signal) < self._samples_num:
pad = self._samples_num - len(signal)
signal = self.padder._add_padding(signal, 'right', pad)
features = self.extractor.extract_log_spec(signal)
normalized_features = self.normalizer.normalize(features)
save_path = self.saver.save_features(normalized_features, file_path)
self.min_max[save_path] = {
'min' : features.min(),
'max' : features.max()
}
@property
def loader(self):
return self._loader
@loader.setter
def loader(self, loader):
self._loader = loader
self._samples_num = int(loader.sr * loader.duration)
class Loader:
'''Loads from directory'''
def __init__(self, sr = 22050, duration = 3000, mono = True):
self.sr = sr
self.duration = duration
self.mono = mono
def load_sound(self, file_path):
return librosa.load(file_path,
sr = self.sr,
duration = self.duration,
mono = self.mono)[0]
#Loader for other data types will be added in future updates
class Padder:
'''Applies padding to the data'''
def __init__(self, mode = 'constant'):
self.mode = mode
def _add_padding(self, data, position, pad_num):
pad = (0, pad_num) if position == 'right' else (pad_num, 0)
return np.pad(data, pad, mode = self.mode)
class Extractor:
'''Extracts special features from data'''
def __init__(self, frame_size, hop_length):
self.frame_size = frame_size
self.hop_length = hop_length
def extract_log_spec(self, signal):
stft = librosa.stft(signal,
n_fft = self.frame_size,
hop_length = self.hop_length)[:-1] #To even the length of the data
return librosa.amplitude_to_db(np.abs(stft))
class MinMaxNormalizer:
'''Normalize any data to values between {min} and {max}'''
def __init__(self, min, max):
self.min = min
self.max = max
def normalize(self, data):
return ((data - data.min()) / (data.max() - data.min())) + (self.max - self.min) + self.min
def denormalize(self, normalized_data, orig_min, orig_max):
return ((normalized_data - self.min) / (self.max - self.min)) + (orig_max - orig_min) + orig_min
class Saver:
'''Saving function ment to save features and other values'''
def __init__(self, features_path, min_max_path):
self.features_path = features_path
self.min_max_path = min_max_path
def save_features(self, features, file_path):
file_name = os.path.split(file_path)[1]
save_path = os.path.join(self.features_path, file_name + '.npy')
np.save(save_path, features)
return save_path
def save_min_max(self, min_max):
save_path = os.path.join(self.min_max_path, 'min_max.pkl')
with open(save_path, 'wb') as f:
pickle.dump(min_max, f)