nkululeko 0.48.0__py3-none-any.whl → 0.49.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nkululeko/augment.py CHANGED
@@ -38,7 +38,13 @@ def main(src_dir):
38
38
  util.debug(f'train shape : {expr.df_train.shape}, test shape:{expr.df_test.shape}')
39
39
 
40
40
  # augment
41
- expr.augment()
41
+ augmenting = util.config_val('DATA', 'augment', False)
42
+ if augmenting:
43
+ expr.augment()
44
+
45
+ random_splicing = util.config_val('DATA', 'random_splice', False)
46
+ if random_splicing:
47
+ expr.random_splice()
42
48
 
43
49
  print('DONE')
44
50
 
nkululeko/augmenter.py CHANGED
@@ -12,8 +12,8 @@ class Augmenter:
12
12
  """
13
13
  augmenting the train split
14
14
  """
15
- def __init__(self, train_df):
16
- self.train_df = train_df
15
+ def __init__(self, df):
16
+ self.df = df
17
17
  self.util = Util()
18
18
  # Define a standard transformation that randomly add augmentations to files
19
19
  self.audioment = Compose([
@@ -30,15 +30,15 @@ class Augmenter:
30
30
  # audeer.mkdir(newpath)
31
31
  return fp.replace(fullpath, np)
32
32
 
33
- def augment(self):
33
+ def augment(self, sample_selection):
34
34
  """
35
35
  augment the training files and return a dataframe with new files index.
36
36
  """
37
- files = self.train_df.index.get_level_values(0).values
37
+ files = self.df.index.get_level_values(0).values
38
38
  store = self.util.get_path('store')
39
39
  filepath = f'{store}augmentations/'
40
40
  audeer.mkdir(filepath)
41
- self.util.debug(f'augmenting the training set to {filepath}')
41
+ self.util.debug(f'augmenting {sample_selection} samples to {filepath}')
42
42
  newpath = ''
43
43
  for i, f in enumerate(files):
44
44
  signal, sr = audiofile.read(f)
@@ -50,9 +50,9 @@ class Augmenter:
50
50
  audiofile.write(f'{newpath}{filename}', signal=sig_aug, sampling_rate=sr)
51
51
  if i%10==0:
52
52
  print(f'augmented {i} of {len(files)}')
53
- df_ret = self.train_df.copy()
53
+ df_ret = self.df.copy()
54
54
  df_ret = df_ret.set_index(map_file_path(df_ret.index, lambda x: self.changepath(x, newpath)))
55
- aug_db_filename = self.util.config_val('DATA', 'augment', 'augment.csv')
55
+ aug_db_filename = self.util.config_val('DATA', 'augment_result', 'augment.csv')
56
56
  target = self.util.config_val('DATA', 'target', 'emotion')
57
57
  df_ret[target] = df_ret['class_label']
58
58
  df_ret = df_ret.drop(columns=['class_label'])
nkululeko/constants.py CHANGED
@@ -1 +1 @@
1
- VERSION = '0.48.0'
1
+ VERSION = '0.49.0'
nkululeko/dataset.py CHANGED
@@ -51,7 +51,15 @@ class Dataset:
51
51
  train_tables = ast.literal_eval(trains)
52
52
  tables += train_tables
53
53
  return tables
54
-
54
+
55
+ def _load_db(self):
56
+ root = self.util.config_val_data(self.name, '', '')
57
+ self.util.debug(f'{self.name}: loading from {root}')
58
+ try:
59
+ self.db = audformat.Database.load(root)
60
+ except FileNotFoundError:
61
+ self.util.error( f'{self.name}: no database found at {root}')
62
+ return root
55
63
 
56
64
  def load(self):
57
65
  """Load the dataframe with files, speakers and task labels"""
@@ -59,6 +67,7 @@ class Dataset:
59
67
  store = self.util.get_path('store')
60
68
  store_file = f'{store}{self.name}.pkl'
61
69
  self.util.debug(f'{self.name}: loading ...')
70
+ root = self._load_db()
62
71
  # self.got_speaker, self.got_gender = False, False
63
72
  if not self.start_fresh and os.path.isfile(store_file):
64
73
  self.util.debug(f'{self.name}: reusing previously stored file {store_file}')
@@ -71,29 +80,23 @@ class Dataset:
71
80
  f'samples: got targets: {self.is_labeled}, got speakers: {self.got_speaker}, '\
72
81
  f'got sexes: {self.got_gender}')
73
82
  return
74
- root = self.util.config_val_data(self.name, '', '')
75
- self.util.debug(f'{self.name}: loading from {root}')
76
- try:
77
- db = audformat.Database.load(root)
78
- except FileNotFoundError:
79
- self.util.error( f'{self.name}: no database found at {root}')
80
83
  tables = self._get_tables()
81
84
  self.util.debug(f'{self.name}: loading tables: {tables}')
82
85
  #db = audb.load(root, )
83
86
  # map the audio file paths
84
- db.map_files(lambda x: os.path.join(root, x))
87
+ self.db.map_files(lambda x: os.path.join(root, x))
85
88
  # the dataframes (potentially more than one) with at least the file names
86
89
  df_files = self.util.config_val_data(self.name, 'files_tables', '[\'files\']')
87
90
  df_files_tables = ast.literal_eval(df_files)
88
91
  # The label for the target column
89
92
  self.col_label = self.util.config_val_data(self.name, 'label', self.target)
90
- df, self.is_labeled, self.got_speaker, self.got_gender, self.got_age = self._get_df_for_lists(db, df_files_tables)
93
+ df, self.is_labeled, self.got_speaker, self.got_gender, self.got_age = self._get_df_for_lists(self.db, df_files_tables)
91
94
  if False in {self.is_labeled, self.got_speaker, self.got_gender, self.got_age}:
92
95
  try :
93
96
  # There might be a separate table with the targets, e.g. emotion or age
94
97
  df_targets = self.util.config_val_data(self.name, 'target_tables', f'[\'{self.target}\']')
95
98
  df_target_tables = ast.literal_eval(df_targets)
96
- df_target, got_target2, got_speaker2, got_gender2, got_age2 = self._get_df_for_lists(db, df_target_tables)
99
+ df_target, got_target2, got_speaker2, got_gender2, got_age2 = self._get_df_for_lists(self.db, df_target_tables)
97
100
  self.is_labeled = got_target2 or self.is_labeled
98
101
  self.got_speaker = got_speaker2 or self.got_speaker
99
102
  self.got_gender = got_gender2 or self.got_gender
@@ -117,7 +120,6 @@ class Dataset:
117
120
  df.got_age = self.got_age
118
121
  df.got_speaker = self.got_speaker
119
122
  self.df = df
120
- self.db = db
121
123
  self.df.is_labeled = self.is_labeled
122
124
  self.util.debug(f'Loaded database {self.name} with {df.shape[0]} '\
123
125
  f'samples: got targets: {self.is_labeled}, got speakers: {self.got_speaker}, '\
nkululeko/experiment.py CHANGED
@@ -292,18 +292,38 @@ class Experiment:
292
292
 
293
293
  def augment(self):
294
294
  """
295
- Augment the training set
295
+ Augment the selected samples
296
296
  """
297
297
  from nkululeko.augmenter import Augmenter
298
- augmenter = Augmenter(self.df_train)
299
- augmenter.augment()
300
-
301
- # def augment_train(self):
302
- # """Augment the train dataframe"""
303
- # from nkululeko.augmenter import Augmenter
304
- # augment_train = Augmenter(self.df_train)
305
- # df_train_aug = augment_train.augment()
306
- # self.df_train = self.df_train.append(df_train_aug)
298
+ sample_selection = self.util.config_val(' DATA', 'augment', 'train')
299
+ if sample_selection=='all':
300
+ df = pd.concat([self.df_train, self.df_test])
301
+ elif sample_selection=='train':
302
+ df = self.df_train
303
+ elif sample_selection=='test':
304
+ df = self.df_test
305
+ else:
306
+ self.util.error(f'unknown augmentation selection specifier {sample_selection}, should be [all | train | test]')
307
+
308
+ augmenter = Augmenter(df)
309
+ augmenter.augment(sample_selection)
310
+
311
+ def random_splice(self):
312
+ """
313
+ Random-splice the selected samples
314
+ """
315
+ from nkululeko.randomsplicer import Randomsplicer
316
+ sample_selection = self.util.config_val(' DATA', 'random_splice', 'train')
317
+ if sample_selection=='all':
318
+ df = pd.concat([self.df_train, self.df_test])
319
+ elif sample_selection=='train':
320
+ df = self.df_train
321
+ elif sample_selection=='test':
322
+ df = self.df_test
323
+ else:
324
+ self.util.error(f'unknown augmentation selection specifier {sample_selection}, should be [all | train | test]')
325
+ randomsplicer = Randomsplicer(df)
326
+ randomsplicer.run(sample_selection)
307
327
 
308
328
 
309
329
  def analyse_features(self, needs_feats):
@@ -119,7 +119,6 @@ def runPCA(df):
119
119
  # PCA
120
120
  pca = PCA(n_components=2)
121
121
  principalComponents = pca.fit_transform(x)
122
- print(type(principalComponents))
123
122
  if np.any(np.isnan(principalComponents)):
124
123
  print ('pc is nan')
125
124
  print(f'count: {np.count_nonzero(np.isnan(principalComponents))}')
@@ -0,0 +1,76 @@
1
+ # randomsplicer.py
2
+
3
+ """
4
+ Code originally by Oliver Pauly
5
+
6
+ Based on an idea by Klaus Scherer
7
+
8
+ K. R. Scherer, “Randomized splicing: A note on a simple technique for masking speech content”
9
+ Journal of Experimental Research in Personality, vol. 5, pp. 155–159, 1971.
10
+
11
+ Evaluated in:
12
+ F. Burkhardt, Anna Derington, Matthias Kahlau, Klaus Scherer, Florian Eyben and Björn Schuller: Masking Speech Contents by Random Splicing: is Emotional Expression Preserved?, Proc. ICASSP, 2023
13
+
14
+ """
15
+
16
+ import pandas as pd
17
+ from nkululeko.util import Util
18
+ import nkululeko.randomsplicing as rsp
19
+ import numpy as np
20
+ import audiofile as af
21
+ import os
22
+ from audformat.utils import map_file_path
23
+ import audeer
24
+
25
+ class Randomsplicer:
26
+ """
27
+ augmenting the train split
28
+ """
29
+ def __init__(self, df):
30
+ self.df = df
31
+ self.util = Util()
32
+
33
+ def changepath(self, fp, np):
34
+ fullpath = os.path.dirname(fp)
35
+ return fp.replace(fullpath, np)
36
+
37
+ def run(self, sample_selection):
38
+ """
39
+ random splice the selected samples and return a dataframe with new files index.
40
+ adjustable parameters:
41
+ * p_reverse: probability of some samples to be in reverse order (default: 0.3)
42
+ * top_db: top db level for silence to be recognized (default: 12)
43
+ """
44
+
45
+ p_reverse=0.3
46
+ top_db=12
47
+
48
+ files = self.df.index.get_level_values(0).values
49
+ store = self.util.get_path('store')
50
+ filepath = f'{store}randomspliced/'
51
+ audeer.mkdir(filepath)
52
+ self.util.debug(f'random splicing {sample_selection} samples to {filepath}')
53
+ newpath = ''
54
+ for i, f in enumerate(files):
55
+ signal, sr = af.read(f)
56
+ filename = os.path.basename(f)
57
+ parent = os.path.dirname(f).split('/')[-1]
58
+ sig_new = rsp.random_splicing(
59
+ signal, sr,
60
+ p_reverse=p_reverse,
61
+ top_db=top_db,
62
+ )
63
+
64
+ newpath = f'{filepath}/{parent}/'
65
+ audeer.mkdir(newpath)
66
+ af.write(f'{newpath}{filename}', signal=sig_new, sampling_rate=sr)
67
+ if i%10==0:
68
+ print(f'random spliced {i} of {len(files)}')
69
+ df_ret = self.df.copy()
70
+ df_ret = df_ret.set_index(map_file_path(df_ret.index, lambda x: self.changepath(x, newpath)))
71
+ db_filename = self.util.config_val('DATA', 'random_splice_result', 'random_spliced.csv')
72
+ target = self.util.config_val('DATA', 'target', 'emotion')
73
+ df_ret[target] = df_ret['class_label']
74
+ df_ret = df_ret.drop(columns=['class_label'])
75
+ df_ret.to_csv(db_filename)
76
+ return df_ret
@@ -0,0 +1,74 @@
1
+ """
2
+ Code originally by Oliver Pauly
3
+
4
+ Based on an idea by Klaus Scherer
5
+
6
+ K. R. Scherer, “Randomized splicing: A note on a simple technique for masking speech content”
7
+ Journal of Experimental Research in Personality, vol. 5, pp. 155–159, 1971.
8
+
9
+ Evaluated in:
10
+ F. Burkhardt, Anna Derington, Matthias Kahlau, Klaus Scherer, Florian Eyben and Björn Schuller: Masking Speech Contents by Random Splicing: is Emotional Expression Preserved?, Proc. ICASSP, 2023
11
+
12
+ """
13
+ import numpy as np
14
+ import librosa
15
+ import audiofile as af
16
+
17
+ def random_splicing(
18
+ signal, sr,
19
+ p_reverse=0.0,
20
+ top_db=12,
21
+ ):
22
+ """
23
+ randomly splice the signal and re-arrange.
24
+
25
+ p_reverse: probability of some samples to be in reverse order
26
+ top_db: top db level for silence to be recognized
27
+
28
+ """
29
+ signal /= np.max(abs(signal))
30
+
31
+ indices = split_wav_naive(signal, top_db=top_db)
32
+
33
+ np.random.shuffle(indices)
34
+
35
+ wav_spliced = remix_random_reverse(signal, indices, p_reverse=p_reverse)
36
+
37
+ return wav_spliced
38
+
39
+
40
+ def split_wav_naive(wav, top_db=12):
41
+
42
+ indices = librosa.effects.split(wav, top_db=top_db)
43
+
44
+ indices = np.array(indices)
45
+ # (re)add the silence-segments
46
+ indices = indices.repeat(2)[1:-1].reshape((-1, 2))
47
+ # add first segment
48
+ indices = np.vstack(((0, indices[0][0]), indices))
49
+ # add last segment
50
+ indices = np.vstack((indices, [indices[-1][-1], wav.shape[0]]))
51
+
52
+ return indices
53
+
54
+
55
+ def remix_random_reverse(wav, indices, p_reverse=0):
56
+
57
+ import random
58
+
59
+ wav_remix = []
60
+
61
+ for seg in indices:
62
+
63
+ start = seg[0]
64
+ end = seg[1]
65
+ wav_seg = wav[start:end]
66
+
67
+ if np.random.rand(1)[0] <= p_reverse:
68
+ wav_seg = wav_seg[::-1]
69
+
70
+ wav_remix.append(wav_seg)
71
+
72
+ wav_remix = np.hstack(wav_remix)
73
+
74
+ return wav_remix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nkululeko
3
- Version: 0.48.0
3
+ Version: 0.49.0
4
4
  Summary: Machine learning audio prediction experiments based on templates
5
5
  Home-page: https://github.com/felixbur/nkululeko
6
6
  Author: Felix Burkhardt
@@ -239,6 +239,14 @@ Nkululeko can be used under the [MIT license](https://choosealicense.com/license
239
239
  Changelog
240
240
  =========
241
241
 
242
+ Version 0.49.0
243
+ --------------
244
+ * added random-splicing
245
+
246
+ Version 0.48.1
247
+ --------------
248
+ * bugfix: database object was not loaded when dataframe was reused
249
+
242
250
  Version 0.48.0
243
251
  --------------
244
252
  * enabled specific feature selection for praat and opensmile features
@@ -1,15 +1,15 @@
1
1
  nkululeko/__init__.py,sha256=62f8HiEzJ8rG2QlTFJXUCMpvuH3fKI33DoJSj33mscc,63
2
- nkululeko/augment.py,sha256=J-HxHKU7u1xZdIiVw_abYVYWOUmZI84HMQNQpcoYk9s,1385
3
- nkululeko/augmenter.py,sha256=whDW3mnda33Wl9TUk2yG_My6507PFCqCzBgy0027Q2c,2399
2
+ nkululeko/augment.py,sha256=rl7oCNWSyg6CGTy0t5BAYayQebhRRSDX5etLwpNyFjo,1595
3
+ nkululeko/augmenter.py,sha256=Ut7bIHspL7OovmB3Zo81UarKZtYTUg2B68aMUEcmnjQ,2404
4
4
  nkululeko/balancer.py,sha256=64ftZN68sMDfkvuovCDHpAHmSJgCO6Kdk9bwmpSisec,12
5
5
  nkululeko/cacheddataset.py,sha256=bSJ_SDg7TxL89YL_pJXp-sFvdUXJtHuBTd5KSTE4AkQ,955
6
- nkululeko/constants.py,sha256=AnpegoMFbAq1OJWivUVuj3UsmEPMR5bGnwjnYbtvP8Q,18
7
- nkululeko/dataset.py,sha256=bsuW00zcLHU5xHpcFSwNT8FHM_2-8e34qsRjM6Jg-L8,21627
6
+ nkululeko/constants.py,sha256=1-g8LlrznB2-gkAcuxyB5d6ESYqVCNUpbjMnueTmqEE,18
7
+ nkululeko/dataset.py,sha256=ISnU4EuGC3Af2Z5F57d47e94_ZnI7aWqfwcYD7VlcVo,21705
8
8
  nkululeko/dataset_csv.py,sha256=2VTZizY5cXPFAUkRRkQSAz-RjoHtwM1OroJA9ZvhfUA,2042
9
9
  nkululeko/dataset_ravdess.py,sha256=pTt98sr4_egdUCv2fWepkZTlkQ6x3A2YshO_n302DNg,537
10
10
  nkululeko/demo.py,sha256=OwmliItSdzCvsjN2maC4_mFc-ZKzzjwwAiobKTWRizA,1815
11
11
  nkululeko/demo_predictor.py,sha256=hYuvvKyW-DxbORAq1Y63owqhRgq-Bl8qPOymVISvO7M,2286
12
- nkululeko/experiment.py,sha256=waTSajWp7yKSfWfJjMu__EHnL-uf-_JRCn-KukiXUCY,20319
12
+ nkululeko/experiment.py,sha256=Oj3xkKGUG0QIWwhophzwWmpJvNTWDs9ljf0n8MIy2RQ,21185
13
13
  nkululeko/explore.py,sha256=HfHrCPl5LbjgfbG7Z_SNRQKv36_m81QuTb8TWrrOXJ8,1960
14
14
  nkululeko/feats_analyser.py,sha256=RWR9-YK1bJ4f2OrA1aGu33nRxg4qLZ_xNqh7lC_zHh4,3821
15
15
  nkululeko/feats_audmodel.py,sha256=w-cV9Fgk_9wAV5u4ELzxvB9KM06IptPFneDenXXEmV0,2748
@@ -24,7 +24,7 @@ nkululeko/feats_trill.py,sha256=m_052ZPPjhrvt6LeXytJEpfCtDlxI5GywA2NfkIR-to,2975
24
24
  nkululeko/feats_wav2vec2.py,sha256=S63QmTiGlyEalO4HjacAh9KxOAVO80vZntG-Alk91WU,4005
25
25
  nkululeko/feature_extractor.py,sha256=_NZt0Cy407FFSx9H_oPzrMf_tdBogRafb9koOHmsizk,3456
26
26
  nkululeko/featureset.py,sha256=MoKrd7nx6IN6F3joi88BoQBx0vSiTjtWBT0JcGOn8IY,1319
27
- nkululeko/feinberg_praat.py,sha256=T3Wcd3cE2Ge5ytj2DyWFC100qPA82pT_x0AIkz33Y8U,19509
27
+ nkululeko/feinberg_praat.py,sha256=fUrdVo1aJNitdG1L0sZRfIvGMJJdQwG3BXoAV5xjh5o,19472
28
28
  nkululeko/filter_data.py,sha256=vzUT7b1sW-_d4kurFcd9_PYkpwdE7KUggDnO_jtEnxM,1821
29
29
  nkululeko/glob_conf.py,sha256=2Tl0NZQeVeydDO8T2tuJC2lCv99wvaTVRX9Dy1Mq_L4,237
30
30
  nkululeko/loss_ccc.py,sha256=BM2I6j_rjKlpua5gKbo81EAS3hhZK-ClBTqJHot9Ils,939
@@ -46,6 +46,8 @@ nkululeko/model_xgr.py,sha256=rOJ3QZjTLIpxHh6GqyCo-ewG9IUL35Fd-0jRDNuM_bk,242
46
46
  nkululeko/modelrunner.py,sha256=5Ix7lD5OqfRAzDutLZFKqv6v3WXe_u3KCODr7w2KhrU,5367
47
47
  nkululeko/nkululeko.py,sha256=XblSDCn2tzXydhOAavYYEnIR2cC1Z9ceOREGAoLmPYQ,1540
48
48
  nkululeko/plots.py,sha256=bRrBIUvX3On0VrcXkzvazjri736HNzDz_Ap9YpDz5io,6554
49
+ nkululeko/randomsplicer.py,sha256=GXp-H4OETrNdRRthmn_1KkkEsrM1alNB_6tEgpmyeTM,2659
50
+ nkululeko/randomsplicing.py,sha256=MOLwxFTM0omsVBmKAN82PmGkD4zNnxwDYoWS4WQnuVU,1867
49
51
  nkululeko/reporter.py,sha256=aI6bVgTkvHTrJGHMSzcQvFjDftI-VeOCXhqRS6qh-40,10167
50
52
  nkululeko/result.py,sha256=Ey5FPsAyfnQVtzO_J6_4hkOAZ191YWmF_vXxlgNjCdc,406
51
53
  nkululeko/runmanager.py,sha256=No6l8422bAI-GmPchA41KnTIFMFe4J3kdcBlj2tuaiU,6753
@@ -54,8 +56,8 @@ nkululeko/syllable_nuclei.py,sha256=vK9dj5deqRnyEmlZmhFtKPzqKVGNCgTnWaG8UDITKNg,
54
56
  nkululeko/test.py,sha256=yv-9Qh30CDsud3NwRJ8jS9RzGyKNKqM_UOvYSw_aPuQ,1366
55
57
  nkululeko/test_predictor.py,sha256=4XGFa9AsHNtOkGdY0X23RxPpESyAlICqoXqR-YidHXA,2315
56
58
  nkululeko/util.py,sha256=83YKkdDPyyK8L2WGyA64YcRXMweXmeuLSsbcVymfaMY,8967
57
- nkululeko-0.48.0.dist-info/LICENSE,sha256=0zGP5B_W35yAcGfHPS18Q2B8UhvLRY3dQq1MhpsJU_U,1076
58
- nkululeko-0.48.0.dist-info/METADATA,sha256=yryB8TKPki6H_zmKXxxXyIgUL6qJ2T0tbpKeyQE9MUQ,18769
59
- nkululeko-0.48.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
60
- nkululeko-0.48.0.dist-info/top_level.txt,sha256=DPFNNSHPjUeVKj44dVANAjuVGRCC3MusJ08lc2a8xFA,10
61
- nkululeko-0.48.0.dist-info/RECORD,,
59
+ nkululeko-0.49.0.dist-info/LICENSE,sha256=0zGP5B_W35yAcGfHPS18Q2B8UhvLRY3dQq1MhpsJU_U,1076
60
+ nkululeko-0.49.0.dist-info/METADATA,sha256=M9iRkSojEyaOL8Ej2DueKrZaREDUBkTZR0We_Oeq0ew,18922
61
+ nkululeko-0.49.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
62
+ nkululeko-0.49.0.dist-info/top_level.txt,sha256=DPFNNSHPjUeVKj44dVANAjuVGRCC3MusJ08lc2a8xFA,10
63
+ nkululeko-0.49.0.dist-info/RECORD,,