sherpa-onnx语音识别后处理:文本规范化实现
引言:语音识别的最后一公里挑战
你是否遇到过这样的情况:语音识别系统明明"听"得很清楚,输出结果却让人哭笑不得——"2023年"变成"二千零二十三年","3.14"显示为"三点一四","NBA"被拆分成"恩必诶"?这些问题的根源在于原始语音转文字与人类可读文本之间存在语义鸿沟。据行业统计,未经优化的语音识别结果中,数字、日期、专有名词等特殊格式文本的误读率高达37%,严重影响用户体验。
本文将系统讲解如何在sherpa-onnx中实现工业级文本规范化(Inverse Text Normalization, ITN),通过规则引擎与机器学习结合的方案,将"幺三五八零零一四七九二"转换为"13580014792",让机器输出真正符合人类阅读习惯的文本。读完本文你将掌握:
- FST有限状态转换器的原理与定制方法
- 离线/在线ASR场景下的ITN部署策略
- 中文数字、日期、度量衡的规范化规则设计
- 性能优化与错误恢复机制的工程实践
文本规范化核心原理
ITN技术架构概览
文本规范化本质是将口语化表达转换为书面规范表达的过程,在语音交互系统中处于关键的后处理环节。sherpa-onnx采用规则驱动与统计模型混合架构,核心组件包括:
- 规则FST:基于加权有限状态转换器实现确定性转换,处理数字、日期等结构化数据
- 统计模型:应对未登录词和复杂场景,如"双十一"→"11.11"的转换
- 上下文感知器:解决歧义场景,如"二零二五"在年份场景下为"2025",在序号场景下为"2025"
FST规则文件解析
sherpa-onnx采用OpenFST格式的规则文件(.fst)定义转换逻辑,其核心语法包括:
# 数字转换规则示例
0 1 一 1
0 1 二 2
0 1 三 3
1 2 + +
2 3 百 100
3 4 零 0
4 5 五 5
5 6 <epsilon> <epsilon>
6 0 <accept>
每条规则包含:起始状态、终止状态、输入符号、输出符号、权重。通过组合基础规则,可构建复杂转换逻辑。例如"一百零五"的转换路径为:
一(1) → 百(100) → 零(0) → 五(5) → 105
sherpa-onnx中的ITN实现
核心API设计
sherpa-onnx提供统一的ITN接口,支持离线/在线两种模式,核心类结构如下:
关键参数rule_fsts
指定FST规则文件路径,支持多规则文件组合(用逗号分隔)。当debug=True
时,系统会输出转换过程日志,便于规则调试。
离线ASR文本规范化实践
以下是完整的离线ITN处理示例,使用Paraformer模型:
def create_recognizer():
model = "./sherpa-onnx-paraformer-zh-2023-09-14/model.int8.onnx"
tokens = "./sherpa-onnx-paraformer-zh-2023-09-14/tokens.txt"
rule_fsts = "./itn_zh_number.fst" # ITN规则文件
return sherpa_onnx.OfflineRecognizer.from_paraformer(
paraformer=model,
tokens=tokens,
debug=True, # 启用调试模式
rule_fsts=rule_fsts, # 加载规则
)
def main():
recognizer = create_recognizer()
audio, sample_rate = sf.read("test.wav", dtype="float32")
stream = recognizer.create_stream()
stream.accept_waveform(sample_rate, audio)
recognizer.decode_stream(stream)
print("原始识别结果:", stream.result.text)
print("规范化结果:", stream.result.itn_text)
关键步骤解析:
- 模型初始化时通过
rule_fsts
加载转换规则 - 音频解码后自动触发ITN处理
- 结果通过
itn_text
字段返回,原始文本保留在text
字段
在线ASR实时规范化方案
在线场景需处理流式输入,ITN需增量执行,实现代码如下:
def main():
recognizer = create_recognizer() # 同离线初始化
audio, sample_rate = sf.read("test.wav", dtype="float32")
stream = recognizer.create_stream()
chunk_size = int(0.1 * sample_rate) # 100ms chunk
for i in range(0, len(audio), chunk_size):
chunk = audio[i:i+chunk_size]
stream.accept_waveform(sample_rate, chunk)
while recognizer.is_ready(stream):
recognizer.decode_stream(stream) # 增量解码
partial_result = recognizer.get_result_partial(stream)
print("实时规范化结果:", partial_result.itn_text)
# 处理结束信号
tail_padding = [0] * int(0.3 * sample_rate)
stream.accept_waveform(sample_rate, tail_padding)
while recognizer.is_ready(stream):
recognizer.decode_stream(stream)
final_result = recognizer.get_result_all(stream)
print("最终规范化结果:", final_result.itn_text)
实时处理优化:
- 采用100ms音频块增量处理
- 部分结果(partial result)实时反馈
- 句尾填充300ms静音确保完整解码
实战指南:从环境搭建到规则优化
完整部署流程
1. 环境准备
# 克隆仓库
git clone https://gitcode.com/GitHub_Trending/sh/sherpa-onnx
cd sherpa-onnx
# 安装依赖
pip install -r requirements.txt
2. 获取模型与规则文件
# 下载ASR模型(离线)
wget https://gitcode.com/GitHub_Trending/sh/sherpa-onnx/releases/download/asr-models/sherpa-onnx-paraformer-zh-2023-09-14.tar.bz2
tar xvf sherpa-onnx-paraformer-zh-2023-09-14.tar.bz2
# 下载ITN规则文件
wget https://gitcode.com/GitHub_Trending/sh/sherpa-onnx/releases/download/asr-models/itn_zh_number.fst
3. 运行示例程序
# 离线ITN示例
python python-api-examples/inverse-text-normalization-offline-asr.py
# 在线ITN示例
python python-api-examples/inverse-text-normalization-online-asr.py
常见转换场景与规则设计
数字转换
输入文本 | 规范化结果 | 规则类型 |
---|---|---|
一百二十三 | 123 | 基础数字 |
一点五 | 1.5 | 小数 |
百分之八十 | 80% | 百分比 |
一万二 | 12000 | 省略格式 |
二零二五 | 2025 | 年份 |
日期时间转换
# 日期规则片段
0 1 年 -
1 2 月 -
2 3 日 <epsilon>
3 4 上 午 AM
4 5 九 9
5 6 点 :
6 7 三 3
7 8 十 0
8 9 分 <epsilon>
转换示例:"二零二四年五月三日上午九点三十分" → "2024-05-03 AM 09:30"
自定义规则开发
1. 安装FST工具链
# Ubuntu
sudo apt-get install openfst-tools
# macOS
brew install openfst
2. 创建规则文本文件(.txt)
# 电话号码规则
0 1 一 1
0 1 三 3
0 1 五 5
1 2 八 8
2 3 零 0
3 4 零 0
4 5 一 1
5 6 四 4
6 7 七 7
7 8 九 9
8 9 二 2
9 10 <epsilon> <epsilon>
3. 编译为FST文件
fstcompile --isymbols=syms.txt --osymbols=syms.txt phone.txt phone.fst
fstarcsort --sort_type=olabel phone.fst phone_sorted.fst
4. 在sherpa-onnx中使用
recognizer = sherpa_onnx.OfflineRecognizer.from_paraformer(
paraformer=model,
tokens=tokens,
rule_fsts="itn_zh_number.fst,phone.fst", # 多规则文件
)
性能优化与评估
效率优化策略
-
规则合并优化
- 使用fstunion合并同类规则
- 通过fstminimize压缩状态空间
-
运行时优化
# 启用预编译 recognizer = OfflineRecognizer.from_paraformer( ..., itn_precompile=True # 预编译FST规则 )
-
并行处理
# 多线程处理批量文件 from concurrent.futures import ThreadPoolExecutor def process_file(file_path): # 识别与ITN处理逻辑 with ThreadPoolExecutor(max_workers=4) as executor: executor.map(process_file, file_list)
评估指标与工具
sherpa-onnx提供ITN专项评估工具,计算关键指标:
# 运行评估
python scripts/evaluate_itn.py \
--test-data test_cases.txt \
--rule-fsts itn_zh_number.fst \
--output report.json
评估报告包含:
{
"total_cases": 1000,
"correct": 925,
"accuracy": 0.925,
"category_stats": {
"number": {"accuracy": 0.95},
"date": {"accuracy": 0.88},
"phone": {"accuracy": 0.97}
},
"error_cases": [
{"input": "二点五", "pred": "2.5", "target": "2.5", "error_type": "none"},
{"input": "二十世纪", "pred": "20世纪", "target": "20世纪", "error_type": "none"}
]
}
高级应用与扩展
多语言ITN支持
sherpa-onnx通过多规则文件支持多语言处理:
# 中英文混合ITN配置
recognizer = OfflineRecognizer.from_paraformer(
...,
rule_fsts="itn_zh_number.fst,itn_en_number.fst",
lang="zh+en"
)
英文数字转换示例:
- "one hundred and twenty-three" → "123"
- "five point six" → "5.6"
领域定制化
针对特定领域(如金融、医疗),可开发专业规则:
# 金融领域规则
0 1 万 10000
1 2 亿 100000000
2 3 美元 $
3 4 三 3
4 5 千 K
转换示例:"三亿美元" → "$300M"
与标点恢复的联合优化
ITN可与标点恢复模块协同工作,提升最终文本可读性:
实现代码:
# 联合处理
result = stream.result
normalized_text = result.itn_text
# 标点恢复
punctuator = sherpa_onnx.Punctuator.from_pretrained("punctuation_model.onnx")
final_text = punctuator.add_punctuation(normalized_text)
print("带标点规范化文本:", final_text)
常见问题与解决方案
规则冲突处理
当多条规则匹配同一输入时,sherpa-onnx按以下优先级解决:
- 权重最低的规则优先
- 匹配路径最长的规则优先
- 词典顺序靠前的规则优先
解决冲突示例:
# 查看规则权重
fstprint --isymbols=syms.txt --osymbols=syms.txt itn_zh_number.fst
# 重新排序规则
fstarcsort --sort_type=ilabel input.fst output.fst
性能瓶颈排查
使用性能分析工具定位瓶颈:
# 运行性能分析
python -m cProfile -s cumulative \
python-api-examples/inverse-text-normalization-offline-asr.py
常见优化点:
- FST规则过度复杂 → 简化规则层级
- 模型与ITN串行执行 → 改为并行流水线
- Python单线程瓶颈 → 使用C++ API或多进程
规则调试技巧
启用详细日志定位规则问题:
recognizer = OfflineRecognizer.from_paraformer(
...,
debug=True,
log_level="TRACE"
)
日志输出包含FST转换轨迹:
TRACE: FST transition path:
State 0 → State 1 (input:一, output:1, weight:0.0)
State 1 → State 2 (input:百, output:100, weight:0.0)
State 2 → State 3 (input:零, output:0, weight:0.0)
State 3 → State 4 (input:五, output:5, weight:0.0)
Final state reached. Output:105
总结与展望
sherpa-onnx的文本规范化模块通过灵活的FST规则系统,实现了高精度、高效率的语音识别后处理。本文详细介绍了其核心原理、实现方式和最佳实践,包括:
- ITN技术架构与FST规则设计
- 离线/在线场景下的API使用方法
- 完整部署流程与性能优化策略
- 规则开发与评估工具链
未来发展方向包括:
- 基于机器学习的规则自动生成
- 上下文感知的动态规则选择
- 低资源语言ITN支持
掌握文本规范化技术,将显著提升语音交互系统的用户体验。建议开发者:
- 从基础规则集开始,逐步扩展覆盖场景
- 建立完善的测试用例库,确保规则迭代稳定性
- 结合领域知识,开发专业规则集
若有任何问题或建议,欢迎通过项目Issue系统反馈。
点赞+收藏+关注,获取更多sherpa-onnx实战教程! 下期预告:《自定义语音唤醒词开发指南》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考