技术原理与算法设计

基于 wav2vec2 预训练模型的构音障碍语音识别系统

系统流程图

用户上传患者语音/视频
FFmpeg 提取音频 → 16kHz 单声道 WAV
wav2vec2-large-xlsr-53 提取 1024 维语音嵌入
余弦相似度匹配基线向量库
≥ 0.75 → 输出匹配词 < 0.75 → 提示未识别
输出标准中文 + 置信度 + Top-3 备选

软件基础设置信息

功能名称构音障碍语音识别系统
适用场景脑卒中构音障碍患者的个性化语音识别,将含糊不清的发音翻译为标准中文
开发语言Python 3.10+
核心依赖Flask, PyTorch, Transformers (HuggingFace), soundfile, NumPy, FFmpeg
AI 模型wav2vec2-large-xlsr-53-chinese-zh-cn,Transformer 架构中文语音预训练模型
匹配算法余弦相似度(Cosine Similarity),L2 归一化嵌入向量
部署方式Flask + systemd + nginx,Ubuntu 22.04,支持 HTTPS

软件系统设计

  1. 音频提取引擎:基于 FFmpeg,支持 MP4/WAV/M4A 等多格式输入,自动转换为 16kHz 单声道 PCM WAV,适配模型输入要求。
  2. 语音嵌入模型:使用 HuggingFace wav2vec2-large-xlsr-53 中文预训练模型,取 Transformer 最后一层 hidden state 的平均池化作为 1024 维语音嵌入向量,L2 归一化后存储。
  3. 基线向量库:JSON 格式存储每个词汇的多条嵌入向量及均值。支持同词多次录入,自动更新平均嵌入。患者录音独立存档。
  4. 相似度匹配器:查询嵌入与基线库中所有词的平均嵌入计算余弦相似度。相似度 ≥ 0.75 判定匹配成功,返回 Top-3 备选;低于阈值提示重新录入。
  5. 单人定制机制:每位患者拥有独立基线向量库,通过多次录入同词发音,逐步建立个性化语音特征模型。同一患者的含糊发音具有稳定的嵌入模式。
  6. Web 服务层:Flask 提供 RESTful API,支持文件上传识别(/api/recognize)和基线录入(/api/baseline/add),模型常驻内存避免重复加载。
  7. 前端交互:响应式 Web 设计,深色主题适配移动端。页面内嵌上传识别区,结果实时展示大字结果 + 置信度进度条 + 备选列表 + 一键朗读。

参数配置

字段说明
嵌入维度1024 维 float32 向量,L2 归一化后点积即余弦相似度
采样率16,000 Hz,单声道,FFmpeg 自动重采样转换
相似度阈值THRESHOLD = 0.75,低于此值判定为"未识别",高于则输出最佳匹配
模型名称jonatasgrosman/wav2vec2-large-xlsr-53-chinese-zh-cn
模型大小约 1.2 GB(首次自动下载至 ~/.cache/huggingface/)
推理速度单次嵌入提取 < 200ms(CPU),模型常驻内存
上传限制MAX_CONTENT_LENGTH = 128MB,支持 MP4/WAV/M4A 格式
音频格式PCM S16LE, 16kHz, Mono, FFmpeg 自动转换

语音嵌入提取模块

import torch, numpy as np, soundfile as sf
from transformers import Wav2Vec2Processor, Wav2Vec2Model

MODEL = "jonatasgrosman/wav2vec2-large-xlsr-53-chinese-zh-cn"
processor = Wav2Vec2Processor.from_pretrained(MODEL)
model = Wav2Vec2Model.from_pretrained(MODEL); model.eval()

def extract_embedding(audio_path):
    audio, _ = sf.read(audio_path, dtype="float32")
    inputs = processor(audio, sampling_rate=16000, return_tensors="pt")
    with torch.no_grad():
        outputs = model(**inputs)
    # 最后一层 hidden state 平均池化 -> 1024D embedding
    emb = outputs.last_hidden_state.mean(dim=1).squeeze().numpy()
    return emb / np.linalg.norm(emb)  # L2 归一化

余弦相似度匹配模块

def match_embedding(query_emb, threshold=0.75):
    baselines = load_baselines()   # 从 JSON 加载基线向量库
    scores = []
    for word, entry in baselines.items():
        mean_emb = np.array(entry["mean_embedding"])
        sim = np.dot(query_emb, mean_emb)  # L2 归一化后点积=余弦
        scores.append((word, float(sim)))
    scores.sort(key=lambda x: x[1], reverse=True)
    best_word, best_score = scores[0]
    if best_score < threshold:
        return {"result": None, "confidence": best_score}
    return {"result": best_word, "confidence": best_score,
            "candidates": scores[:3]}