MMS-MSG est un cadre hautement modulaire et flexible pour la génération de mélanges vocaux. Il étend la base de code de la base de données SMS-WSJ pour la génération de signaux de mélange afin de pouvoir générer à la fois des mélanges vocaux de style de réunion et des signaux de mélange correspondant à des bases de données de mélange de parole classiques.
La réunion des données décrit un paramètre très dynamique. L'environnement avec MMS-MSG, nous ne visons pas à fournir une seule base de données.
Au lieu de cela, nous voulons fournir un cadre adaptable qui permet le prototypage et l'évaluation de la réunion du système de procession et de transcription dans autant d'environnements que possible.
L'aspect principal de MMS-MSG est la génération de données de style de rencontre. Les réunions sont générées de manière modulaire. Les paramètres réglables sont:
Le processus d'échantillonnage est modularisé, de sorte que de nombreux scénarios peuvent être créés en modifiant légèrement le pipeline d'échantillonnage. Nous fournissons des exemples de classes pour montrer comment les modules uniques sont utilisés. Si un scénario n'est pas pris en charge, de nouveaux modules d'échantillonnage peuvent être facilement mis en œuvre pour adapter MMS-MSG à vos exigences.
Le processus de simulation de données de MMS-MSG est divisé en échantillonnage des paramètres et en génération réelle de données. Grâce à cela, nous prenons en charge la génération de données à la demande. De cette façon, seules les données source et les paramètres de réunion doivent être enregistrées, permettant la simulation de divers scénarios de réunion tout en minimisant l'espace disque requis. Cependant, nous soutenons également la génération hors ligne de données de réunion si les enregistrer sur le disque dur sont nécessaires pour votre flux de travail.
Nous fournissons du code pour générer des mélanges vocaux en fonction des spécifications des bases de données de séparation des sources actuellement utilisées, où des énoncés uniques de plusieurs haut-parleurs sont partiellement ou complètement chevauchés les uns avec les autres. En utilisant MMS-MSG pour générer des données de formation pour ces bases de données, nous offrons un support natif du mélange dynamique.
Bases de données de mélange vocal prises en charge:
Prévu:
Le générateur de mélange utilise Lazy_dataset. Bien que la fonctionnalité principale de MMS_MSG puisse être utilisée sans Lazy_Dataset, certaines fonctionnalités (comme le mélange dynamique et l'abstraction de la base de données) ne sont pas alors disponibles.
from mms_msg . databases . classical . full_overlap import WSJ2Mix
from mms_msg . sampling . utils import collate_fn
db = WSJ2Mix ()
# Get a train dataset with dynamic mixing
# This dataset only emits the metadata of the mixtures, it doesn't load
# the data yet
ds = db . get_dataset ( 'train_si284_rng' )
# The data can be loaded by mapping a database's load_example function
ds = ds . map ( db . load_example )
# Other dataset modifications (see lazy_dataset doc)
ds = ds . shuffle ( reshuffle = True )
ds = ds . batch ( batch_size = 8 ). map ( collate_fn )
# ...
# Parallelize data loading with lazy_dataset
ds = ds . prefetch ( num_workers = 8 , buffer_size = 16 )
# The dataset can now be used in any training loop
for example in ds :
# ... do fancy stuff with the example.
# The loaded audio data is in example['audio_data']
print ( example )
Toutes autres routines de modification des données peuvent être mappées sur ds
directement après le chargement de l'exemple.
Un lazy_dataset.Dataset
peut être branché sur une torch.utils.data.DataLoader
:
from mms_msg . databases . classical . full_overlap import WSJ2Mix
db = WSJ2Mix ()
ds = db . get_dataset ( 'train_si284_rng' ). map ( db . load_example )
# Parallelize data loading with torch.utils.data.DataLoader
from torch . utils . data import DataLoader
loader = DataLoader ( ds , batch_size = 8 , shuffle = True , num_workers = 8 )
for example in loader :
print ( example )
Les exemples d'entrée devraient avoir cette structure:
example = {
'audio_path' : {
'observation' : 'single_speaker_recording.wav'
},
'speaker_id' : 'A' ,
'num_samples' : 1234 , # Number of samples of the observation file
# 'num_samples': {'observation': 1234} # Alernative, if other audios are present
'dataset' : 'test' , # The input dataset name
'example_id' : 'asdf1234' , # Unique ID of this example. Optional if the input data is passes as a dict
'scenario' : 'cafe-asdf1234' , # (Optional) If provided, mms_msg makes sure that all examples of the same speaker in a mixture share the same scenario
# ... (any additional keys)
}
Après avoir sélectionné des énoncés pour un mélange, ces exemples d'énoncés sont normalisés et "rassemblés", ce qui se traduit par une structure similaire à celle:
example = {
'audio_path' : {
'original_source' : [
'source1.wav' ,
'source2.wav' ,
],
},
'speaker_id' : [
'A' , 'B'
],
'num_samples' : { # The structure under some keys mirrors the structure in 'audio_path'
'original_source' : [
1234 , 4321
]
},
'source_id' : [ # Reference to the source examples this mixture was created from
'asdf1234' , 'asdf1235'
],
...
}
À partir d'une telle structure, des modules d'échantillonnage peuvent être appliqués pour remplir l'exemple avec plus d'informations, par exemple, des compensations ou une mise à l'échelle des énoncés.
Des classes de base de données ou des définitions sont fournies pour quelques scénarios communs dans mms_msg.databases
. Chaque classe de base de données doit définir deux méthodes:
get_mixture_dataset
, qui résume l'étape "d'échantillonnage" et construit un pipeline de modules d'échantillonnage, etload_example
, qui fournit l'étape "Simulation", c'est-à-dire le chargement et le mélange des données audio.Une base de données de base (sans paramètre) ressemblerait à ceci:
from mms_msg . databases . database import MMSMSGDatabase
from lazy_dataset . database import JsonDatabase
import mms_msg
class MyDatabase ( JsonDatabase , MMSMSGDatabase ):
def get_mixture_dataset ( self , name , rng ):
ds = mms_msg . sampling . source_composition . get_composition_dataset (
input_dataset = super (). get_dataset ( name ),
num_speakers = 2 ,
rng = rng ,
)
ds = ds . map ( mms_msg . sampling . pattern . classical . ConstantOffsetSampler ( 8000 ))
ds = ds . map ( mms_msg . sampling . environment . scaling . ConstantScalingSampler ( 0 ))
return ds
def load_example ( self , example ):
return mms_msg . simulation . anechoic . anechoic_scenario_map_fn ( example )
et peut être instancié avec
db = MyDatabase ( 'path/to/source/database.json' )
La structure du pipeline d'échantillonnage de l'ensemble de données est décrite dans la section suivante.
Ceci est un exemple d'un pipeline d'échantillonnage simple pour un seul ensemble de données:
import mms_msg
input_ds = ... # Get source utterance examples from somewhere
# Compute a composition of base examples. This makes sure that the speaker distribution
# in the mixtures is equal to the speaker distribution in the original database.
ds = mms_msg . sampling . source_composition . get_composition_dataset ( input_dataset = input_ds , num_speakers = 2 )
# If required: Offset the utterances
ds = ds . map ( mms_msg . sampling . pattern . classical . ConstantOffsetSampler ( 0 ))
# If required: Add log_weights to simulate volume differences
ds = ds . map ( mms_msg . sampling . environment . scaling . UniformScalingSampler ( max_weight = 5 ))
Le processus d'échantillonnage commence toujours par la création d'une "composition source", c'est-à-dire des énoncés d'échantillonnage (de base) pour chaque mélange. Cela se fait dans get_composition_dataset
, qui met en œuvre un algorithme d'échantillonnage similaire à SMS-WSJ qui utilise chaque énoncé de la base de données source également.
Après cela, des modules d'échantillonnage peuvent être appliqués pour simuler différents modèles ou environnements de parole. L'exemple ci-dessus définit tous les décalages sur zéro (c'est-à-dire, toutes les énoncés commencent au début du mélange) avec le ConstantOffsetSampler
et échantillonnent une échelle aléatoire avec un maximum de 5 dB avec l' UniformScalingSampler
.
De nombreux autres modules d'échantillonnage sont disponibles, dont un qui simule les modèles de parole de style de rencontre. Des exemples pour cela peuvent être trouvés dans ce cahier.
Les mélanges dans mms_msg
sont créés en appliquant des modules d'échantillonnage individuels à un exemple de l'autre. Chaque module d'échantillonnage est entièrement déterministe, c'est-à-dire que sa sortie dépend uniquement de ses hyperparamètres et de l'exemple d'entrée, mais n'est pas autorisé à maintenir un état mutable. Il s'agit d'assurer la reproductibilité: l'échantillonnage ne dépend pas de l'ordre dans lequel les mélanges sont générés, le nombre ou l'ordre dans lequel les modules sont appliqués.
Un module d'échantillonnage est un créable qui reçoit un mélange (intermédiaire) en tant que dictionnaire, le modifie et le renvoie. Un module d'échantillonnage de base, implémenté en fonction sans hyperparamètres, pourrait ressembler à ceci:
import mms_msg
def my_sampling_module ( example : dict ) -> dict :
# Get a deterministic random number generator based on the input example
# and an additional seed string. The seed string ensures that the RNGs
# differ between different sampling modules
rng = mms_msg . sampling . utils . rng . get_rng_example ( example , 'my_sampler' )
# Sample whatever based on RNG and possibly the contents of example
example [ 'my_random_number' ] = rng . random ()
return example
Une partie importante est la fonction mms_msg.sampling.utils.rng.get_rng_example
. Il renvoie un objet np.random.Generator
qui est initialisé avec une graine calculée à partir d'informations de base à partir de l'exemple de dictionnaire (exemple-ID et ensemble de données) et une chaîne de semence supplémentaire. Cela signifie que les nombres aléatoires générés dans un module sont égaux chaque fois que le module est appliqué au même exemple d'entrée.
Si votre module d'échantillonnage a des hyperparamètres, nous recommandons une classe de données gelée pour assurer l'immuabilité:
import mms_msg
from dataclasses import dataclass
@ dataclass ( frozen = True )
class MySamplingModule :
size : int = 42
def __call__ ( self , example ):
rng = mms_msg . sampling . utils . rng . get_rng_example ( example , 'my_sampler' )
# Sample whatever based on RNG and possibly the contents of example
example [ 'my_random_number' ] = rng . random ( self . size )
return example
Un exemple plus pratique est donné dans ce cahier.
MMS-MSG a été proposé dans la publication suivante:
@inproceedings { cordlandwehr2022mms_msg ,
title = { MMS-MSG: A Multi-purpose Multi-Speaker Mixture Signal Generator } ,
author = { Tobias Cord-Landwehr and Thilo von Neumann and Christoph Boeddeker and Reinhold Haeb-Umbach } ,
year = { 2022 } ,
booktitle = { International Workshop on Acoustic Signal Enhancement (IWAENC) } ,
publisher = { {IEEE} } ,
} ```