Visualisering og transformering af data
- 15 minutter
Når du har forstået den rå bølgeform, er næste skridt at omdanne lyden til en repræsentation, der er nyttig til klassifikation.
En bølgeform viser amplitude over tid. Et spektrogram viser frekvensindhold over tid. For at skabe et spektrogram beregner du den korttids Fourier-transformation (STFT) over små overlappende vinduer af bølgeformen. TensorFlow sørger tf.signal.stft for denne operation.
I ældre versioner af denne arbejdsgang blev spektrogrammer gemt som PNG-filer og derefter indlæst som billeder. Den opdaterede tilgang beholder spektrogrammer som tensorer. Dette undgår ekstra fil-I/O, undgår artefakter i billedstørrelse og matcher det nuværende TensorFlow-lydtutorialmønster.
Forbered det binære lyddatasæt
Start med den samme mini Speech Commands-download fra den forrige enhed. Følgende kode downloader datasættet, hvis det ikke allerede er til stede, validerer arkivhashen, finder den udpakkede mappe for både Keras 2- og Keras 3-layouts og kopierer kun no og-mapperne yes til en mindre binær datasætmappe.
import pathlib
import shutil
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
SOURCE_DATASET_PATH = pathlib.Path("data/mini_speech_commands")
ALT_SOURCE_DATASET_PATH = pathlib.Path("data/mini_speech_commands_extracted/mini_speech_commands")
BINARY_DATASET_PATH = pathlib.Path("data/speech_commands_yes_no")
MINI_SPEECH_COMMANDS_SHA256 = "49650f2341b26d886b46b3f4fb8fed59e30300b17550f1ee4a768b3106cf93a0"
if not SOURCE_DATASET_PATH.exists() and not ALT_SOURCE_DATASET_PATH.exists():
tf.keras.utils.get_file(
"mini_speech_commands.zip",
origin="https://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip",
file_hash=MINI_SPEECH_COMMANDS_SHA256,
hash_algorithm="sha256",
extract=True,
cache_dir=".",
cache_subdir="data",
)
if ALT_SOURCE_DATASET_PATH.exists():
SOURCE_DATASET_PATH = ALT_SOURCE_DATASET_PATH
for label in ("no", "yes"):
target_dir = BINARY_DATASET_PATH / label
target_dir.mkdir(parents=True, exist_ok=True)
for source_file in (SOURCE_DATASET_PATH / label).glob("*.wav"):
target_file = target_dir / source_file.name
if not target_file.exists():
shutil.copy2(source_file, target_file)
Forventet output: Denne opsætningskode udskriver ikke output. Den opretter en data/speech_commands_yes_no mappe med én undermappe for no og én for yes. TensorFlow 2.16 og senere bruger Keras 3, som udpakker arkivet til en <archive>_extracted undermappe; hjælperen håndterer begge layouts, så resten af enheden fungerer på enhver understøttet TensorFlow-version.
Indlæs lydfiler som TensorFlow-datasæt
Brug tf.keras.utils.audio_dataset_from_directory til at oprette TensorFlow-datasæt ud fra mappestrukturen. Mini Speech Commands-filerne samples ved 16 kHz, så output_sequence_length=16000 der vælges et fast vindue på 16.000 samples pr. klip, hvilket er præcis ét sekunds lyd ved den samplerate. Filer kortere end 16.000 prøver er fyldt med nuller, og filer længere end 16.000 prøver er afkortet. Argumentet output_sequence_length gensampler ikke lyd optaget med en anden samplerate; resampling betyder at ændre, hvor mange samples der repræsenterer hvert sekund af lyden. Hvis du tilpasser denne arbejdsgang til filer optaget med en anden samplerate, så resample dem til 16 kHz før indlæsning, eller brug loaderens sampling_rate mulighed med tensorflow-io og verificer, at de resulterende tensorformer stadig matcher modelinputtet.
Koden sætter label_mode="int" eksplicit, fordi modellen bruger heltalsklasselabels med sparsom kategorisk krydsentropi i den næste enhed. Klassenavnene udledes fra mappenavnene i alfanumerisk rækkefølge.
SEED = 42
BATCH_SIZE = 64
tf.random.set_seed(SEED)
np.random.seed(SEED)
train_ds, validation_ds = tf.keras.utils.audio_dataset_from_directory(
directory=BINARY_DATASET_PATH,
label_mode="int",
batch_size=BATCH_SIZE,
validation_split=0.2,
subset="both",
seed=SEED,
output_sequence_length=16000,
)
label_names = np.array(train_ds.class_names)
print("Label names:", label_names)
Forventet output: Loaderen finder omkring 2.000 WAV-filer på tværs af no klasserne yes . Med en valideringsfordeling på 20 procent bruges omkring 1.600 eksempler til træning og cirka 400 til validering.
Found 2000 files belonging to 2 classes.
Using 1600 files for training.
Using 400 files for validation.
Label names: ['no' 'yes']
Hold et testsæt adskilt fra valideringssættet. Loaderen opretter ikke en separat testopdeling, så den følgende kode udpakker holdout-dataene og splitter de enkelte klip i en valideringsshard og en testshard. Unbatch før sharding, så splittelsen sker på clip-niveau i stedet for batch-niveau. Cache holdout-dataene, så validerings- og testfragmenterne ikke gentagne gange dekrypterer de samme WAV-filer.
holdout_ds = validation_ds.unbatch().cache()
val_ds = holdout_ds.shard(num_shards=2, index=0).batch(BATCH_SIZE)
test_ds = holdout_ds.shard(num_shards=2, index=1).batch(BATCH_SIZE)
Forventet output: Denne kode udskriver ikke output. Modellen bruges train_ds til træning, val_ds til justering under træning og test_ds til endelig evaluering.
Bemærkning
Dataset.shard Vælger elementer fra datasættet. Fordi denne kode kalder unbatch() før shard(), er shard-elementerne individuelle lydklip i stedet for hele batches. Med omkring 400 holdout-klip, val_ds og test_ds hver indeholder cirka 200 klip efter batching.
Bemærkning
Dette modul følger et kompakt split-mønster, der er tilpasset fra TensorFlow-tutorialen, så eksemplet forbliver lille. For grundig evaluering med hele Speech Commands-datasættet, brug train, validation, og test splits fra TensorFlow Datasets, eller split efter speaker ID, så klip fra samme speaker ikke optræder i hverken trænings- eller evalueringsdata.
Datasættet returnerer lydtensorer med en kanaldimension. Da disse filer er mono, skal du fjerne den ekstra kanaldimension, før du opretter spektrogrammer.
def squeeze(audio, labels):
audio = tf.squeeze(audio, axis=-1)
return audio, labels
train_ds = train_ds.map(squeeze, num_parallel_calls=tf.data.AUTOTUNE)
val_ds = val_ds.map(squeeze, num_parallel_calls=tf.data.AUTOTUNE)
test_ds = test_ds.map(squeeze, num_parallel_calls=tf.data.AUTOTUNE)
for example_audio, example_labels in train_ds.take(1):
print("Audio batch shape:", example_audio.shape)
print("Label batch shape:", example_labels.shape)
Forventet output: Hver lydbatch indeholder op til 64 et-sekunders bølgeformer.
Audio batch shape: (64, 16000)
Label batch shape: (64,)
Visualiser en bølgeform
Følgende kode plotter én bølgeform fra en træningsbatch.
example_waveform = example_audio[0]
example_label = label_names[example_labels[0].numpy()]
plt.figure(figsize=(12, 4))
plt.plot(example_waveform.numpy())
plt.title(f"Waveform for '{example_label}'")
plt.xlabel("Sample")
plt.ylabel("Amplitude")
plt.xlim([0, 16000])
plt.show()
Forventet output: Plottet viser amplitude over 16.000 samples for ét no eller yes lydklip.
Opret spektrogrammer
STFT'en konverterer bølgeformen fra tidsdomænet til en tids-frekvens repræsentation. Modellen bruger kun størrelsen af STFT-værdierne, så koden gælder tf.abs for det komplekse STFT-resultat. Den sidste linje tilføjer en kanaldimension, så konvolutionelle lag kan behandle spektrogrammet som billedlignende input.
def get_spectrogram(waveform):
spectrogram = tf.signal.stft(
waveform,
frame_length=255,
frame_step=128,
)
spectrogram = tf.abs(spectrogram)
spectrogram = spectrogram[..., tf.newaxis]
return spectrogram
example_spectrogram = get_spectrogram(example_waveform)
print("Spectrogram shape:", example_spectrogram.shape)
Forventet output: Med ét sekunds lyd (16.000 samples), en billedlængde på 255 og et billedtrin på 128 er spektrogrammets form (124, 129, 1). Den første dimension er antallet af tidsrammer: floor((16000 - 255) / 128) + 1 = 124. Denne formel gælder, fordi tf.signal.stft den lader pad_end den være sat til False som standard, så den tilføjer ikke en ekstra delvis frame til sidst. Den anden dimension er antallet af frekvensbins: tf.signal.stft nul-pads hver frame til næste potens af to for FFT (256 i dette tilfælde), og returnerer fft_length / 2 + 1 = 129 derefter ikke-redundante bins. Den endelige dimension er kanalaksen, der tilføjes til konvolutionsmodellen.
Spectrogram shape: (124, 129, 1)
Visualiser et spektrogram
Brug en logaritmisk skala til visning, så de mere stille frekvenskomponenter er lettere at se. Tilføj en lille epsilon før kald, np.log så nulværdier ikke bliver negativ uendelig.
def plot_spectrogram(spectrogram, ax):
if len(spectrogram.shape) > 2:
spectrogram = np.squeeze(spectrogram, axis=-1)
log_spec = np.log(spectrogram.T + np.finfo(float).eps)
height = log_spec.shape[0]
width = log_spec.shape[1]
time_steps = np.arange(width)
frequency_bins = np.arange(height)
ax.pcolormesh(time_steps, frequency_bins, log_spec)
ax.set_xlabel("Time frame")
ax.set_ylabel("Frequency bin")
fig, axes = plt.subplots(2, figsize=(12, 8))
axes[0].plot(example_waveform.numpy())
axes[0].set_title("Waveform")
axes[0].set_xlim([0, 16000])
plot_spectrogram(example_spectrogram.numpy(), axes[1])
axes[1].set_title("Spectrogram")
plt.suptitle(example_label.title())
plt.show()
Forventet output: Det første diagram viser bølgeformen. Det andet diagram viser spektrogrammet med tidsrammer på den horisontale akse, frekvensbins på den lodrette akse og farveintensitet som repræsenterer magnitude.
Opret spektrogramdatasæt
Kortlæg bølgeformdatasættene til spektrogramdatasæt. Cache og prehent datasættene for at reducere inputpipeline-latensen under træning.
def make_spectrogram_dataset(dataset):
return dataset.map(
map_func=lambda audio, label: (get_spectrogram(audio), label),
num_parallel_calls=tf.data.AUTOTUNE,
)
train_spectrogram_ds = make_spectrogram_dataset(train_ds)
val_spectrogram_ds = make_spectrogram_dataset(val_ds)
test_spectrogram_ds = make_spectrogram_dataset(test_ds)
train_spectrogram_ds = train_spectrogram_ds.cache().shuffle(1000, seed=SEED).prefetch(tf.data.AUTOTUNE)
val_spectrogram_ds = val_spectrogram_ds.cache().prefetch(tf.data.AUTOTUNE)
test_spectrogram_ds = test_spectrogram_ds.cache().prefetch(tf.data.AUTOTUNE)
for spectrograms, labels in train_spectrogram_ds.take(1):
print("Spectrogram batch shape:", spectrograms.shape)
print("Label batch shape:", labels.shape)
Forventet output: Det modelklare datasæt indeholder batches af spektrogramtensorer og heltalsetiketter.
Spectrogram batch shape: (64, 124, 129, 1)
Label batch shape: (64,)
Tjek din viden
Feedback
Var denne side nyttig?
No
Har du brug for hjælp til dette emne?
Vil du prøve at bruge Ask Learn til at tydeliggøre eller guide dig gennem dette emne?