Conversão de fala em texto em lote com Whisper

Use Whisper large-v3-turbo da OpenAI para transcrever um lote de gravações de voz em inglês em um A10 AI Runtime conectado. Este caderno mostra como:

  • Carregue o modelo Whisper large-v3-turbo usando o pipeline do Transformers.
  • Construa um lote de amostras de áudio a partir do conjunto de testes LibriSpeech.
  • Visualize a forma de onda e o espectrograma de cada amostra.
  • Execute a transcrição em lote e compare sua taxa de processamento com a inferência sequencial.

Note

Este exemplo requer o ambiente de IA Databricks versão 6 ou superior.

Conectar-se à computação de GPU sem servidor

  1. No seletor de computação do notebook, selecione GPU Serverless.
  2. No painel Ambiente , selecione o acelerador A10 e o ambiente AI v6 .
  3. Clique em Aplicar, depois confirme o ambiente.

O modelo Whisper e o conjunto de dados de exemplo LibriSpeech são públicos e não exigem autenticação da Hugging Face.

Importar bibliotecas

O ambiente de IA inclui os pacotes PyTorch, Transformers e Hugging Face Datasets usados neste notebook, portanto não é necessária a instalação de pacotes. Essa célula os importa e confirma que uma 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

Carregue o modelo Whisper

Carregue openai/whisper-large-v3-turbo, um modelo destilado com 809 milhões de parâmetros que oferece precisão próxima ao estado da arte com maior velocidade de inferência. O pipeline do Transformers lida com extração de características, tokenização e decodificação em uma única chamada.

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

Carregue e explore amostras de áudio

Carregue o conjunto de teste LibriSpeech ASR , uma coleção de gravações limpas de fala em inglês com transcrições de referência, e reproduza a primeira amostra.

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:

Visualize as formas de onda do áudio

Plote a forma de onda e o espectrograma de cada amostra lado a lado. A forma de onda mostra amplitude ao longo do tempo, e o espectrograma mostra o conteúdo de frequência, onde a energia da voz se concentra na faixa de fala 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()

Transcreva uma única amostra

Transcreva uma amostra para verificar o pipeline e depois compare a previsão com o texto de referência.

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

Execute inferência em lote

Transcreva todas as amostras com um batch_size configurável. O batching permite que a GPU processe múltiplos clipes de áudio em paralelo, o que melhora a taxa de transferência em relação à inferência sequencial. Essa célula também cronometra uma linha de base sequencial para comparação.

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

Resumo

Este caderno demonstrou:

  • Inferência de GPU sem necessidade de configuração: o ambiente de execução de IA vem com torch, transformers e datasets pré-instalados; sem necessidade de %pip install
  • Reprodução de áudio embutida: ouça amostras diretamente no notebook com IPython.display.Audio
  • Visualização de formas de onda e espectrograma: renderizada com matplotlib, também pré-instalada
  • Inferência em lotes eficiente: usando o parâmetro batch_size para transcrição paralela na GPU
  • Whisper large-v3-turbo: um modelo rápido e preciso para transcrição de fala para texto em nível de produção

Para adaptar isso aos seus próprios dados, substitua o conjunto de dados HuggingFace por arquivos de áudio de um Volume do Catálogo Unity ou do caminho de armazenamento em nuvem.

Notebook de exemplo

Transcrição em lote de fala para texto com Whisper

Obter laptop