Files
2026-05-16 17:16:51 +08:00

13 KiB
Raw Permalink Blame History

Whisper语音识别

概述

Whisper是OpenAI于2022年发布的开源自动语音识别ASR系统采用了基于Transformer的编解码器架构能够进行多语言识别并具有较强的泛化能力。Whisper的核心创新在于使用弱监督训练方法通过大规模互联网音频数据学习语音识别能力。

1. Whisper架构详解

1.1 编解码器架构

Whisper采用标准的Transformer编码器-解码器架构:

class Whisper(nn.Module):
    def __init__(self, config):
        # 编码器
        self.encoder = TransformerEncoder(
            num_layers=config.num_layers,
            d_model=config.d_model,  # 1280
            num_heads=config.num_heads,  # 16
            d_ff=config.d_ff,  # 5120
            dropout=0.1
        )
        
        # 解码器
        self.decoder = TransformerDecoder(
            num_layers=config.num_layers,
            d_model=config.d_model,
            num_heads=config.num_heads,
            d_ff=config.d_ff,
            dropout=0.1,
            vocab_size=config.vocab_size  # 51865
        )
        
        # 音频嵌入层
        self.audio_embed = nn.Conv2d(
            in_channels=80,  # Mel频谱通道数
            out_channels=config.d_model,
            kernel_size=3,
            stride=2
        )
        
        # 文本嵌入层
        self.text_embed = nn.Embedding(
            num_embeddings=config.vocab_size,
            embedding_dim=config.d_model
        )

1.2 音频特征处理

def process_audio(audio, sample_rate=16000):
    """
    音频预处理转换为Mel频谱
    """
    # 1. 重采样到16kHz
    audio = resample(audio, target_sr=16000)
    
    # 2. 短时傅里叶变换 (STFT)
    stft = librosa.stft(audio, n_fft=400, hop_length=160)
    
    # 3. 计算幅度谱
    magnitude = np.abs(stft)
    
    # 4. Mel滤波器组变换
    mel_spec = librosa.feature.melspectrogram(
        S=magnitude,
        n_mels=80,
        n_fft=400,
        hop_length=160,
        fmin=0,
        fmax=8000
    )
    
    # 5. 对数压缩
    log_mel = np.log(mel_spec + 1e-9)
    
    # 6. 归一化
    log_mel = (log_mel - log_mel.mean()) / log_mel.std()
    
    return log_mel  # [80, T] 其中T=audio_duration/0.01

1.3 编码器结构

class WhisperEncoder(nn.Module):
    def __init__(self, d_model=1280, num_layers=32):
        # 输入卷积层
        self.conv1 = nn.Conv1d(80, d_model, kernel_size=3, padding=1)
        self.conv2 = nn.Conv1d(d_model, d_model, kernel_size=3, stride=2, padding=1)
        
        # Transformer块
        self.blocks = nn.ModuleList([
            ResidualAttentionBlock(d_model, num_heads=16)
            for _ in range(num_layers)
        ])
        
        # 层归一化
        self.ln = LayerNorm(d_model)
    
    def forward(self, x):
        # x: [B, 80, T]
        
        # 初始卷积下采样
        x = self.conv1(x)
        x = nn.functional.gelu(x)
        x = self.conv2(x)
        x = nn.functional.gelu(x)
        
        # Transformer处理
        for block in self.blocks:
            x = block(x, self_attn_mask=None)
        
        # 最终归一化
        x = self.ln(x)
        
        return x  # [B, D, T']

1.4 解码器结构

class WhisperDecoder(nn.Module):
    def __init__(self, d_model=1280, num_layers=32, vocab_size=51865):
        # 文本嵌入
        self.token_embedding = nn.Embedding(vocab_size, d_model)
        
        # 位置编码
        self.positional_embedding = nn.Embedding(5000, d_model)
        
        # Transformer块
        self.blocks = nn.ModuleList([
            ResidualAttentionBlock(d_model, num_heads=16, use_cross_attention=True)
            for _ in range(num_layers)
        ])
        
        # 输出层
        self.ln = LayerNorm(d_model)
        self.proj = nn.Linear(d_model, vocab_size)
    
    def forward(self, x, encoder_output):
        # x: [B, seq_len] token IDs
        # encoder_output: [B, D, T'] 编码器输出
        
        # 文本嵌入 + 位置编码
        x = self.token_embedding(x) + self.positional_embedding(
            torch.arange(x.shape[1], device=x.device)
        )
        
        # 自注意力掩码causal
        seq_len = x.shape[1]
        mask = torch.triu(
            torch.ones(seq_len, seq_len, device=x.device),
            diagonal=1
        ).bool()
        
        # Transformer块
        for block in self.blocks:
            x = block(x, encoder_output, self_attn_mask=mask)
        
        # 输出投影
        x = self.ln(x)
        logits = self.proj(x)
        
        return logits  # [B, seq_len, vocab_size]

2. 多语言识别能力

2.1 支持的语言

Whisper能够识别99种语言

LANGUAGES = {
    'en': 'english',
    'zh': 'chinese',
    'es': 'spanish',
    'fr': 'french',
    'de': 'german',
    'ja': 'japanese',
    'ko': 'korean',
    'ar': 'arabic',
    'ru': 'russian',
    # ... 共99种语言
}

2.2 语言检测与自动切换

def detect_language_and_transcribe(audio, model):
    """
    自动检测语言并转录
    """
    # 1. 音频特征提取
    mel = process_audio(audio)
    
    # 2. 语言检测(使用一小段音频)
    lang_mel = mel[:, :3000]  # 前30秒
    lang_logits = model.detect_language(lang_mel)
    detected_lang = LANGUAGES[lang_logits.argmax().item()]
    
    # 3. 完整转录(指定语言)
    if detected_lang != 'english':
        # 使用语言特定的解码器
        transcription = model.transcribe(
            audio, 
            language=detected_lang,
            task='transcribe'
        )
    else:
        transcription = model.transcribe(audio)
    
    return transcription

2.3 多语言训练数据

# Whisper训练数据集分布
dataset_distribution = {
    'english': 0.35,      # 最大比例
    'spanish': 0.10,
    'chinese': 0.08,
    'french': 0.07,
    'german': 0.06,
    'russian': 0.05,
    'other': 0.29        # 其他语言混合
}

3. 弱监督训练方法

3.1 弱监督定义

弱监督Weak Supervision 使用互联网上有噪声但数量庞大的音频-文本配对数据进行训练,相比使用人工标注的高质量数据,规模更大但标注质量较低。

# 传统监督 vs 弱监督
traditional_supervision = {
    'data_source': '人工标注',
    'quality': '高',
    'quantity': '低(数千到数万小时)',
    'cost': '昂贵',
    'annotation': '精确时间对齐'
}

weak_supervision = {
    'data_source': '互联网音频YouTube等',
    'quality': '中等(有噪声)',
    'quantity': '大(数百万小时)',
    'cost': '低',
    'annotation': '不保证时间对齐'
}

3.2 训练数据收集

def collect_weak_supervision_data():
    """
    收集弱监督训练数据
    """
    data_sources = [
        'YouTube videos',
        'Podcasts',
        'Audiobooks',
        'Public speaking recordings',
        'Movie trailers',
        'News broadcasts',
        'Educational content'
    ]
    
    collection_pipeline = {
        'step1': '从公开源收集音频',
        'step2': '原始转录文本获取CC subtitles, transcripts',
        'step3': '质量过滤(长度、语言、清晰度)',
        'step4': '音频-文本配对构建',
        'step5': '去重(去除重复内容)'
    }
    
    return collected_data  # Whisper使用约68万小时

3.3 数据预处理

def preprocess_audio_text_pair(audio_path, text):
    """
    预处理音频-文本对
    """
    # 1. 音频清理
    audio = load_audio(audio_path)
    audio = remove_silence(audio)
    audio = normalize_volume(audio)
    
    # 2. 文本清理
    text = clean_transcript(text)
    text = remove_filler_words(text)  # 可选
    text = standardize_punctuation(text)
    
    # 3. 时长过滤
    if len(audio) < 0.5 or len(audio) > 30:
        return None
    
    # 4. 语言验证
    detected_lang = detect_language(text)
    if not is_supported_language(detected_lang):
        return None
    
    return {'audio': audio, 'text': text, 'language': detected_lang}

3.4 损失函数与训练

def compute_loss(logits, targets, pad_token_id=50257):
    """
    计算交叉熵损失
    忽略padding token
    """
    # logits: [B, seq_len, vocab_size]
    # targets: [B, seq_len]
    
    # 移位解码器预测下一个token
    shift_logits = logits[:, :-1, :].contiguous()
    shift_targets = targets[:, 1:].contiguous()
    
    # 计算交叉熵
    loss = nn.functional.cross_entropy(
        shift_logits.view(-1, shift_logits.size(-1)),
        shift_targets.view(-1),
        ignore_index=pad_token_id,
        reduction='mean'
    )
    
    return loss

3.5 多任务训练

Whisper使用多任务学习框架

class MultiTaskWhisper(nn.Module):
    def forward(self, audio, targets=None, task='transcribe', language='en'):
        # 编码音频
        encoder_output = self.encoder(audio)
        
        # 构建任务提示
        if task == 'transcribe':
            task_tokens = [TO_TRANSCRIBE, LANG_TOKEN[language]]
        elif task == 'translate':
            task_tokens = [TO_TRANSLATE, LANG_TOKEN[language]]
        elif task == 'detect_language':
            task_tokens = [TO_DETECT_LANGUAGE]
        
        # 解码
        decoder_input = task_tokens + (targets or [])
        decoder_output = self.decoder(decoder_input, encoder_output)
        
        return decoder_output

4. 模型变体

4.1 Whisper模型系列

模型 参数量 English WER 多语言 WER
Tiny 39M ~8% ~15%
Base 74M ~6% ~12%
Small 244M ~4% ~8%
Medium 769M ~3% ~6%
Large-v2 1550M ~2.5% ~5%
Large-v3 1550M ~2% ~4%

4.2 性能对比

# Whisper vs 其他ASR系统
performance_comparison = {
    'Whisper-Large-v3': {'WER': '2-3%', 'languages': 99, 'robustness': 'high'},
    'Wav2Vec2': {'WER': '4-5%', 'languages': 50+', 'robustness': 'medium'},
    'Google Speech-to-Text': {'WER': '3-4%', 'languages': 125+, 'robustness': 'high'},
    'DeepSpeech': {'WER': '8-10%', 'languages': 5', 'robustness': 'low'}
}

5. 使用方法

5.1 基本推理

import whisper

# 加载模型
model = whisper.load_model("base")

# 转录
result = model.transcribe("audio.mp3", language='zh')

# 打印结果
print(result["text"])
print(result["segments"])

5.2 多语言识别

# 加载模型
model = whisper.load_model("medium")

# 方法1自动检测语言
result = model.transcribe("unknown_language_audio.mp3")

# 方法2指定语言
result = model.transcribe(
    "japanese_audio.mp3",
    language="ja",
    task="transcribe"  # 或 'translate'
)

# 方法3翻译
result = model.transcribe(
    "chinese_audio.mp3",
    language="zh",
    task="translate"  # 翻译为英语
)

5.3 批量处理

def batch_transcribe(audio_files, model, language=None):
    """
    批量转录多个音频文件
    """
    results = []
    
    for audio_path in audio_files:
        print(f"Processing: {audio_path}")
        
        result = model.transcribe(
            audio_path,
            language=language,
            verbose=False
        )
        
        results.append({
            'file': audio_path,
            'text': result['text'],
            'language': result['language']
        })
    
    return results

6. 核心优势

优势 说明
多语言支持 99种语言无需微调
弱监督训练 68万小时规模大
鲁棒性 抗噪声能力强
开源 可本地部署
零样本能力 未经训练的语言也能识别

7. 局限性与改进

7.1 当前局限

限制 描述
实时性 推理延迟较高
专有名词 人名、地名识别准确率低
方言口音 某些方言识别困难
标点符号 自动标点不够准确

7.2 改进方向

# Whisper的潜在改进
improvements = {
    'speed': '优化推理速度,支持实时',
    'accuracy': '提升专有名词识别',
    'punctuation': '改进标点生成',
    'dialect': '增加方言支持',
    'speaker': '加入说话人分离'
}

8. 总结

Whisper的核心技术贡献

技术 贡献 影响
Transformer编解码器 统一的多语言ASR 简化模型架构
弱监督训练 大规模互联网数据 降低数据成本
多语言泛化 99种语言零样本 广泛适用性
开源模型 可本地部署 推动社区发展

Whisper证明了弱监督训练在语音识别领域的有效性为后续多语言语音模型的发展提供了重要参考。