make_noiser.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """This module inmplements some methods to artificialy noise the data
  2. """
  3. from typing import List, Dict
  4. from random import choices, sample, shuffle
  5. import copy
  6. import random
  7. random.seed(80)
  8. class Noise :
  9. """
  10. This class simulate noise in the data. Crucially, noise can be made on three points :\
  11. (1) The noise of phonemes order of a given sequence by making the order of the sequence more aribitrary,\
  12. (2) Replacement of some phonemes of a given sequence by arbitrary sampled phonemes from a vocabulary and\
  13. (3) By arbitrary interverting some sequences of two different speakers.
  14. Atributes
  15. ---------
  16. - phonemes_order_noise :
  17. Parameter for controling the degree of noise at the level of phonemes order. See the point 1 mentioned above.
  18. - speakers_noise :
  19. Parameters for controling the degree of noise at the level of speakers. See the point 3 mentioned above.
  20. - phonemes_noise :
  21. Parameter for controling the degree of noise at the level of phonemes. See the point 2 mentioned above.
  22. """
  23. def __init__(self,
  24. most_probable_phonemes: list,
  25. phonemes_order_noise=0.3,
  26. speakers_noise=(0.5, 0.5),
  27. phonemes_noise=0.5) :
  28. self.most_probable_phonemes = most_probable_phonemes
  29. self.phonemes_order_noise = phonemes_order_noise
  30. self.speakers_noise = speakers_noise
  31. self.phonemes_noise = phonemes_noise
  32. def _order_noise(self, sequence: List[str]) -> str :
  33. """
  34. Making noise the order of the phonemes in a given sequence
  35. Parameters
  36. ----------
  37. - sequence : list
  38. The sequence for which the phonemes order must be noised.
  39. Returns
  40. -------
  41. - str :
  42. The sequence with the order of phonemes noised.
  43. """
  44. # number of phonemes to noise in the sequence = len(sequence) / nb_phonemes_to_noise
  45. phonemes_to_noise = round(len(sequence) * self.phonemes_order_noise)
  46. # sample nb_phonemes_to_noise positions in the sequence
  47. positions_sampled = list(sample(range(len(sequence)), k=phonemes_to_noise))
  48. copied_positions = copy.deepcopy(positions_sampled)
  49. shuffle(copied_positions)
  50. # change the positions of the sampled phonemes
  51. for original_position, new_position in zip(positions_sampled, copied_positions):
  52. sequence[original_position] = sequence[new_position]
  53. return " ".join(sequence)
  54. def _phonemes_noise(self, sequence: List[str]) -> str :
  55. """
  56. Makinng noise the phonemes of the sequence by replacing\
  57. some phonemes of the sequence by arbitrary sampled phonemes\
  58. from the vocabulary.
  59. Parameters
  60. ----------
  61. - sequence : list
  62. The sequence for which the phonemes must be noised.
  63. Returns
  64. -------
  65. - str :
  66. The sequence with noised phonemes.
  67. """
  68. phonemes_to_noise = round(len(sequence) * self.phonemes_noise)
  69. indexes = choices(range(len(sequence)), k=phonemes_to_noise)
  70. # choose new phonemes only from the most probable phonemes.
  71. phonemes = choices(self.most_probable_phonemes, k=phonemes_to_noise)
  72. # and replace some indices of the sequence by those choosen phonemes
  73. for idx, phonemes in zip(indexes, phonemes) :
  74. sequence[idx] = phonemes
  75. return " ".join(sequence)
  76. def _speakers_noise(self, speakers_sequences: Dict[str, set]) -> Dict[str, set] :
  77. """
  78. Making noise in the speaker's statements.
  79. Parameters
  80. ----------
  81. - speakers_sequences : dict
  82. Dictionary containing the utterances for each speaker.
  83. Returns
  84. -------
  85. - dict :
  86. The dictionary containing the few statements interchanged between the two speakers.
  87. """
  88. first_speaker, second_speaker = "Target_Child", "Adult"
  89. noise_first_speaker, noise_second_speaker = self.speakers_noise
  90. speakers_sequences[second_speaker] = set(speakers_sequences[second_speaker])
  91. speakers_sequences[first_speaker] = set(speakers_sequences[first_speaker])
  92. # sample some percentage of utterances from each speaker
  93. sequences_to_noise_second_speaker = round(len(speakers_sequences[second_speaker]) * noise_second_speaker)
  94. sequences_to_noise_first_speaker = round(len(speakers_sequences[first_speaker]) * noise_first_speaker)
  95. sequences_noise_second_speaker = sample(list(speakers_sequences[second_speaker]), k=sequences_to_noise_second_speaker)
  96. sequences_noise_first_speaker = sample(list(speakers_sequences[first_speaker]), k=sequences_to_noise_first_speaker)
  97. # noise by interchanging sampled utterances
  98. speakers_sequences[second_speaker] -= set(sequences_noise_second_speaker)
  99. speakers_sequences[first_speaker] -= set(sequences_noise_first_speaker)
  100. speakers_sequences[second_speaker] |= set(sequences_noise_first_speaker)
  101. speakers_sequences[first_speaker] |= set(sequences_noise_second_speaker)
  102. # set to list
  103. speakers_sequences[first_speaker] = list(speakers_sequences[first_speaker])
  104. speakers_sequences[second_speaker] = list(speakers_sequences[second_speaker])
  105. return speakers_sequences
  106. def __call__(self, loaded_dataset: dict) -> dict:
  107. """
  108. Apply the three types of noise.
  109. Parameters
  110. ----------
  111. loaded_dataset : dict
  112. The dictionary containing the utterances for each family, at each and for each speaker.
  113. Returns
  114. -------
  115. dict :
  116. The noised data.
  117. """
  118. for family in loaded_dataset :
  119. for age in loaded_dataset[family] :
  120. if "Adult" in loaded_dataset[family][age] :
  121. for idx, utterance in enumerate(loaded_dataset[family][age]["Adult"]) :
  122. splitted_utterance = utterance.split(" ")
  123. loaded_dataset[family][age]["Adult"][idx] = self._order_noise(splitted_utterance)
  124. loaded_dataset[family][age]["Adult"][idx] = self._phonemes_noise(splitted_utterance)
  125. if "Target_Child" in loaded_dataset[family][age] :
  126. for idx, utterance in enumerate(loaded_dataset[family][age]["Target_Child"]) :
  127. splitted_utterance = utterance.split(" ")
  128. loaded_dataset[family][age]["Target_Child"][idx] = self._order_noise(splitted_utterance)
  129. loaded_dataset[family][age]["Target_Child"][idx] = self._phonemes_noise(splitted_utterance)
  130. if "Target_Child" in loaded_dataset[family][age] and "Adult" in loaded_dataset[family][age] and all(self.speakers_noise):
  131. noised_speaker = self._speakers_noise(loaded_dataset[family][age])
  132. loaded_dataset[family][age]["Target_Child"] = noised_speaker["Target_Child"]
  133. loaded_dataset[family][age]["Adult"] = noised_speaker["Adult"]
  134. return loaded_dataset