Conversión de voz a texto por lotes con Whisper

Utiliza OpenAI Whisper large-v3-turbo para transcribir un lote de grabaciones de voz en inglés en un entorno de ejecución de IA A10 conectado. Este cuaderno muestra cómo:

  • Carga el modelo Whisper de gran turbo v3 con la tubería Transformers.
  • Crea un lote de muestras de audio a partir del conjunto de pruebas LibriSpeech.
  • Visualiza la forma de onda y el espectrograma de cada muestra.
  • Ejecuta transcripción por lotes y compara su rendimiento con inferencia secuencial.

Note

Este ejemplo requiere el entorno de IA de Databricks versión 6 o superior.

Conectar al cómputo de GPU sin servidor

  1. Desde el selector de cómputo del portátil, selecciona GPU sin servidor.
  2. En el panel de Entorno , selecciona el acelerador A10 y el entorno AI v6 .
  3. Haz clic en Aplicar y luego confirma el entorno.

El modelo Whisper y el conjunto de datos de muestra LibriSpeech son públicos y no requieren autenticación de Hugging Face.

Importar bibliotecas

El entorno de IA incluye los paquetes PyTorch, Transformers y Hugging Face Datasets usados en este portátil, por lo que no se requiere instalación de paquetes. Esta celda los importa y confirma que una GPU está conectada.

import torch
import transformers
import datasets

print(f"Environment")
print(f"   PyTorch:      {torch.__version__}")
print(f"   Transformers: {transformers.__version__}")
print(f"   Datasets:     {datasets.__version__}")
print(f"\nGPU")
print(f"   Available:    {torch.cuda.is_available()}")
if torch.cuda.is_available():
    print(f"   Device:       {torch.cuda.get_device_name(0)}")
    mem_gb = torch.cuda.get_device_properties(0).total_memory / 1e9
    print(f"   Memory:       {mem_gb:.1f} GB")
Environment
   PyTorch:      2.11.0+cu130
   Transformers: 5.8.1
   Datasets:     4.8.5

GPU
   Available:    True
   Device:       NVIDIA A10G
   Memory:       23.7 GB

Carga el modelo de Whisper

Cargue openai/whisper-large-v3-turbo, un modelo destilado de 809 millones de parámetros que ofrece una precisión cercana al estado de la técnica con una velocidad de inferencia más rápida. La pipeline de Transformers gestiona la extracción de características, la tokenización y la decodificación en una sola llamada.

from transformers import pipeline
import torch

whisper_pipe = pipeline(
    "automatic-speech-recognition",
    model="openai/whisper-large-v3-turbo",
    torch_dtype=torch.float16,
    device="cuda",
)
print(f"Model loaded on {whisper_pipe.device}")
Model loaded on cuda

Carga y explora muestras de audio

Carga el set de pruebas LibriSpeech ASR , una colección de grabaciones limpias de voz en inglés con transcripciones de referencia, y reproduce la primera muestra.

from datasets import load_dataset, Audio as AudioFeature
from IPython.display import display, Audio
import numpy as np
import soundfile as sf
import io

# Load the LibriSpeech test samples (decode=False to avoid torchcodec/FFmpeg dependency)
ds = load_dataset(
    "hf-internal-testing/librispeech_asr_dummy", "clean", split="validation"
)
ds = ds.cast_column("audio", AudioFeature(decode=False))
print(f"Loaded {len(ds)} audio samples\n")

def decode_audio(raw):
    """Decode raw audio bytes with soundfile."""
    arr, sr = sf.read(io.BytesIO(raw["bytes"]))
    return {"array": arr, "sampling_rate": sr}

# Show metadata for first few samples
for i in range(5):
    audio = decode_audio(ds[i]["audio"])
    duration = len(audio["array"]) / audio["sampling_rate"]
    text_preview = ds[i]["text"][:80]
    print(f"  Sample {i+1}:  {duration:.2f}s  |  {audio['sampling_rate']} Hz  |  \"{text_preview}...\"")

# Play the first sample inline
print("\n>> Playing Sample 1:")
audio_0 = decode_audio(ds[0]["audio"])
display(Audio(audio_0["array"], rate=audio_0["sampling_rate"]))
Loaded 73 audio samples

  Sample 1:  5.86s  |  16000 Hz  |  "MISTER QUILTER IS THE APOSTLE OF THE MIDDLE CLASSES AND WE ARE GLAD TO WELCOME H..."
  Sample 2:  4.82s  |  16000 Hz  |  "NOR IS MISTER QUILTER'S MANNER LESS INTERESTING THAN HIS MATTER..."
  Sample 3:  12.48s  |  16000 Hz  |  "HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAS AND ROAST BEE..."
  Sample 4:  9.90s  |  16000 Hz  |  "HE HAS GRAVE DOUBTS WHETHER SIR FREDERICK LEIGHTON'S WORK IS REALLY GREEK AFTER ..."
  Sample 5:  29.40s  |  16000 Hz  |  "LINNELL'S PICTURES ARE A SORT OF UP GUARDS AND AT EM PAINTINGS AND MASON'S EXQUI..."

>> Playing Sample 1:

Visualiza las formas de onda de audio

Grafica la forma de onda y el espectrograma de cada muestra lado a lado. La forma de onda muestra la amplitud a lo largo del tiempo, y el espectrograma muestra el contenido de frecuencia, donde la energía vocal se concentra en la banda de 100 a 4.000 Hz.

import matplotlib.pyplot as plt
import numpy as np

NUM_SAMPLES = 4
fig, axes = plt.subplots(NUM_SAMPLES, 2, figsize=(16, 3 * NUM_SAMPLES))
fig.suptitle(
    "Waveform & Spectrogram Profiles", fontsize=16, fontweight="bold", y=1.01
)

for i in range(NUM_SAMPLES):
    audio = decode_audio(ds[i]["audio"])
    samples = audio["array"]
    sr = audio["sampling_rate"]
    t = np.arange(len(samples)) / sr

    # --- Waveform ---
    ax_wave = axes[i, 0]
    ax_wave.plot(t, samples, linewidth=0.4, color="#1f77b4", alpha=0.8)
    ax_wave.fill_between(t, samples, alpha=0.15, color="#1f77b4")
    ax_wave.set_ylabel("Amplitude", fontsize=9)
    ax_wave.set_title(f"Sample {i+1} — Waveform ({len(samples)/sr:.1f}s)", fontsize=10)
    ax_wave.set_xlim(0, t[-1])
    ax_wave.grid(True, alpha=0.3)
    if i == NUM_SAMPLES - 1:
        ax_wave.set_xlabel("Time (seconds)", fontsize=9)

    # --- Spectrogram ---
    ax_spec = axes[i, 1]
    ax_spec.specgram(samples, Fs=sr, NFFT=1024, noverlap=512, cmap="magma")
    ax_spec.set_ylabel("Frequency (Hz)", fontsize=9)
    ax_spec.set_title(f"Sample {i+1} — Spectrogram", fontsize=10)
    ax_spec.set_ylim(0, 8000)  # Focus on speech frequencies
    if i == NUM_SAMPLES - 1:
        ax_spec.set_xlabel("Time (seconds)", fontsize=9)

plt.tight_layout()
plt.show()

Transcribir una sola muestra

Transcribe una muestra para verificar la canalización y luego compara la predicción con el texto de referencia.

import time

audio_input = decode_audio(ds[0]["audio"])

start = time.perf_counter()
result = whisper_pipe(
    audio_input["array"],
    generate_kwargs={"language": "en"},
)
elapsed = time.perf_counter() - start

duration = len(audio_input["array"]) / audio_input["sampling_rate"]

print(f"Inference time:   {elapsed:.2f}s for {duration:.1f}s audio ({duration/elapsed:.1f}x realtime)")
print(f"\nPredicted:  {result['text'].strip()}")
print(f"Reference:  {ds[0]['text']}")
Inference time:   12.23s for 5.9s audio (0.5x realtime)

Predicted:  Mr. Quilter is the apostle of the middle classes, and we are glad to welcome his gospel.
Reference:  MISTER QUILTER IS THE APOSTLE OF THE MIDDLE CLASSES AND WE ARE GLAD TO WELCOME HIS GOSPEL

Ejecutar inferencia en lote

Transcribe todas las muestras con un batch_size configurable. El procesamiento por lotes permite a la GPU procesar varios clips de audio en paralelo, lo que mejora el rendimiento respecto a la inferencia secuencial. Esta celda también cronometra una línea de base secuencial para la comparación.

import time
import pandas as pd

_decoded = [decode_audio(ds[i]["audio"]) for i in range(len(ds))]
audio_inputs = [d["array"] for d in _decoded]
_sr = _decoded[0]["sampling_rate"]

# --- Sequential baseline ---
start = time.perf_counter()
seq_results = [
    whisper_pipe(a, generate_kwargs={"language": "en"}) for a in audio_inputs
]
seq_time = time.perf_counter() - start

# --- Batched inference ---
start = time.perf_counter()
batch_results = whisper_pipe(
    audio_inputs, batch_size=8, generate_kwargs={"language": "en"}
)
batch_time = time.perf_counter() - start

total_audio_sec = sum(
    len(a) / _sr for a in audio_inputs
)

print(f"Performance Comparison ({len(audio_inputs)} samples, {total_audio_sec:.1f}s total audio)")
print(f"   Sequential:  {seq_time:.2f}s  ({total_audio_sec/seq_time:.1f}x realtime)")
print(f"   Batched (8): {batch_time:.2f}s  ({total_audio_sec/batch_time:.1f}x realtime)")
print(f"   Speedup:     {seq_time/batch_time:.2f}x\n")

# --- Results table ---
rows = []
for i, res in enumerate(batch_results):
    duration = len(audio_inputs[i]) / _sr
    rows.append({
        "Sample": i + 1,
        "Duration (s)": round(duration, 1),
        "Transcription": res["text"].strip(),
        "Reference": ds[i]["text"],
    })

df = pd.DataFrame(rows)
display(df)
Performance Comparison (73 samples, 481.0s total audio)
   Sequential:  16.02s  (30.0x realtime)
   Batched (8): 9.56s  (50.3x realtime)
   Speedup:     1.68x

Resumen

Este cuaderno demostraba:

  • Inferencia de GPU sin configuración: el entorno de ejecución de IA viene con torch, transformers, y datasets preinstalado; no %pip install es necesario
  • Reproducción de audio integrada: escucha muestras de audio directamente en el cuaderno con IPython.display.Audio
  • Visualización de formas de onda y espectrograma: generados con matplotlib, que también viene preinstalado
  • Inferencia por lotes eficiente: uso del batch_size parámetro para la transcripción paralela GPU
  • Whisper large-v3-turbo: un modelo rápido y preciso para transcripción de voz a texto para producción

Para adaptar esto a tus propios datos, sustituye el conjunto de datos HuggingFace por archivos de audio de un Unity Catalog Volume o de una ruta de almacenamiento en la nube.

Cuaderno de ejemplo

Conversión de voz a texto por lotes con Whisper

Obtención del cuaderno