Whisperによるバッチ音声テキスト変換

接続されたA10 AI Runtime上で、OpenAI Whisper large-v3-turbo を使用して英語の音声録音を一括で文字起こしします。 このノートは以下の方法を示しています:

  • Whisperの大型v3ターボモデルにトランスフォーマーパイプラインをロードします。
  • LibriSpeechテストセットから音声サンプルを一括で作成します。
  • 各サンプルの波形とスペクトログラムを可視化します。
  • バッチで転写を実行し、そのスループットと逐次推論を比較します。

Note

この例はDatabricks AI環境バージョン6以上が必要です。

サーバーレス GPU コンピューティングに接続する

  1. ノートブックのコンピュートセレクターから「 Serverless GPU」を選択してください。
  2. 環境パネルでA10アクセラレータとAI v6環境を選択します。
  3. 「 適用」をクリックし、環境を確認してください。

WhisperモデルとLibriSpeechサンプルデータセットは公開されており、Hugging Face認証は不要です。

ライブラリをインポートする

AI環境には、このノートブックで使用されるPyTorch、Transformers、Hugging Face Datasetパッケージが含まれているため、パッケージのインストールは不要です。 このセルがそれらをインポートし、GPUが接続されていることを確認します。

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

Whisperモデルを読み込む

Load openai/whisper-large-v3-turboは、より高速な推論速度で最先端の精度を追求する、809Mパラメータの精細モデルです。 Transformersパイプラインは、特徴抽出、トークン化、デコードを1回の呼び出しで処理します。

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

音声サンプルの読み込みと探索

LibriSpeech ASRテストセットを読み込みます。これはクリーンな英語音声録音と参照文字起こしのコレクションで、最初のサンプルを再生します。

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:

音声波形を視覚化してください

各サンプルの波形とスペクトログラムを並べてプロットします。 波形は時間とともに振幅を示し、スペクトログラムは周波数成分を示し、音声エネルギーが100〜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()

単一のサンプルを書き起こします

パイプラインを検証するために1サンプルを文字起こしし、その後、予測と参照テキストを比較します。

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

バッチ推論を実行する

すべてのサンプルを設定可能な batch_sizeで書き起こします。 バッチ処理により、GPUは複数の音声クリップを並列処理できるため、逐次推論よりもスループットが向上します。 このセルは比較のために連続した基準線も計測します。

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

まとめ

このノートは以下のことを示していました:

  • ゼロセットアップGPU推論:AIランタイム環境は torch、 transformers、 datasets がプリインストールされており、 %pip install は不要です
  • インラインオーディオ再生:ノートブックで直接サンプルを聴くことができます。 IPython.display.Audio
  • 波形およびスペクトログラムの可視化: matplotlibでレンダリングされ、こちらも事前インストール済みです
  • 効率的なバッチ推論:GPU並列転写のための batch_size パラメータの利用
  • Whisper large-v3-turbo: 本番環境向けの高速かつ高精度な音声認識モデル

自分のデータに適用するには、HuggingFaceのデータセットを Unityカタログボリューム やクラウドストレージパスの音声ファイルに置き換えてください。

ノートブックの例

Whisperによるバッチ音声テキスト変換

ノートブックを入手