目录
本篇文章记录了paddlespeech的学习历程,有问题或不足之处请评论区指出。
什么是PaddleSpeech
PaddleSpeech是一个基于飞桨PaddlePaddle的语音技术工具集,它支持语音识别、语音翻译、语音合成等多种语音和音频处理任务。
安装PaddleSpeech
参考我之前的博客PaddleSpeech安装及环境测试-CSDN博客
语音识别部分(ASR)代码拆解
main.py
from pathlib import Path
from paddlespeech.cli.asr.infer import ASRExecutor
# 初始化ASRExecutor(可能需要添加其他配置参数)
asr = ASRExecutor()
# 使用pathlib.Path来包装字符串路径
audio_path = Path("zh.wav")
# 使用ASRExecutor处理音频文件
result = asr(audio_file=audio_path)
# 输出识别结果
print(result)
设置断点进入result。ASRExecutor是PaddleSpeech中的一个类。
utils.py
装饰器stats_wrapper
装饰器stats_wrapper 的作用是为一个类的方法添加一个额外的功能:接受一个方法 executor_func 作为参数,并返回一个新的函数 _wrapper。**kwargs接受到字典{'audio_file': zh.wav}。通过_parse_args_解析参数,再进入_note_one_stat()。
def stats_wrapper(executor_func):
def _warpper(self, *args, **kwargs):
try:
_note_one_stat(
type(self).__name__, _parse_args(executor_func, *args,
**kwargs))
except Exception:
pass
return executor_func(self, *args, **kwargs)
return _warpper
_parse_args_
def _parse_args(func, *args, **kwargs):
# FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)
argspec = inspect.getfullargspec(func)
keys = argspec[0]
if keys[0] == 'self': # Remove self pointer.
keys = keys[1:]
default_values = argspec[3]
values = [None] * (len(keys) - len(default_values))
values.extend(list(default_values))
params = dict(zip(keys, values))
for idx, v in enumerate(args):
params[keys[idx]] = v
for k, v in kwargs.items():
params[k] = v
return params
该函数通过inspect获取完整的签名信息,并对参数进行处理。
![]()
_note_one_stat
该函数主要判断这次调用PaddleSpeech是为了执行哪种任务。paddlespeech可以执行的任务有:
-
'asr': 自动语音识别(Automatic Speech Recognition) -
'st': 语音翻译(Speech Translation) -
'tts': 文本到语音(Text-to-Speech) -
'cls': 分类任务(Classification) -
'text': 文本处理任务。恢复文本标点
还可以传入其他参数进行任务细分。这部份可以查看paddlespeech的使用教程。
由于我使用的是asr任务,在标红色该行会进入soudfile.py文件,调用了soundfile库,这部分的逻辑主要就是文件的处理与参数传递,不多赘述。对zh.wav文件进行采样。_为采样后数据,sr为采样率。

上述流程运行完后,终于到了return executor_func(self, *args, **kwargs),进入infer.py文件
infer.py
__call__
装饰器stats_wrapper调用被修饰的函数__call__,这是ASRExecutor类中的函数
- 转换
audio_file为绝对路径。 - 设置 PaddlePaddle 的设备。(该设备上为CPU)
- 使用给定的参数从路径初始化模型和其他相关设置(
_init_from_path)。 - 检查音频文件是否符合要求(如采样率是否匹配),如果不满足且
force_yes为 False,则退出程序。 - 对音频进行预处理(
preprocess)。 - 执行音频识别(
infer)。 - 后处理识别的结果并返回(
postprocess)。 - 如果
rtf为 True,则记录结束时间和音频的持续时间。
@stats_wrapper
def __call__(self,
audio_file: os.PathLike,
model: str='conformer_wenetspeech',
lang: str='zh',
sample_rate: int=16000,
config: os.PathLike=None,
ckpt_path: os.PathLike=None,
decode_method: str='attention_rescoring',
num_decoding_left_chunks: int=-1,
force_yes: bool=False,
rtf: bool=False,
device=paddle.get_device()):
"""
Python API to call an executor.
"""
audio_file = os.path.abspath(audio_file)
paddle.set_device(device)
self._init_from_path(model, lang, sample_rate, config, decode_method,
num_decoding_left_chunks, ckpt_path)
if not self._check(audio_file, sample_rate, force_yes):
sys.exit(-1)
if rtf:
k = self.__class__.__name__
CLI_TIMER[k]['start'].append(time.time())
self.preprocess(model, audio_file)
self.infer(model)
res = self.postprocess() # Retrieve result of asr.
if rtf:
CLI_TIMER[k]['end'].append(time.time())
audio, audio_sample_rate = soundfile.read(
audio_file, dtype="int16", always_2d=True)
CLI_TIMER[k]['extra'].append(audio.shape[0] / audio_sample_rate)
return res
_init_from_path
省略该函数中路径处理部分。该部分为模型初始化。
*创建一个新的 `CfgNode` 对象,该对象通常用于配置管理,并允许在运行时添加新的配置参数(因为 `new_allowed=True`)。 使用 `merge_from_file` 方法从指定的配置文件路径 `self.cfg_path` 中加载配置。
*如果 `spm_model_prefix` 存在,则更新其路径以包含 `self.res_path`。 * 创建一个 `TextFeaturizer` 对象,该对象使用从配置中读取的参数进行初始化。
选择模型:
根据 `model_type`(如 "deepspeech2"、"conformer" 或 "transformer"),执行不同的配置更新操作。
对于 "deepspeech2",更新语言模型路径,并可能下载相应的语言模型文件。
对于 "conformer" 或 "transformer",设置解码方法和可能的解码左块数量。
如果 `model_type` 不匹配任何已知的类型,则引发异常。
#Init body.
self.config = CfgNode(new_allowed=True)
self.config.merge_from_file(self.cfg_path)
with UpdateConfig(self.config):
if self.config.spm_model_prefix:
self.config.spm_model_prefix = os.path.join(
self.res_path, self.config.spm_model_prefix)
self.text_feature = TextFeaturizer(
unit_type=self.config.unit_type,
vocab=self.config.vocab_filepath,
spm_model_prefix=self.config.spm_model_prefix)
if "deepspeech2" in model_type:
self.config.decode.lang_model_path = os.path.join(
MODEL_HOME, 'language_model',
self.config.decode.lang_model_path)
lm_url = self.task_resource.res_dict['lm_url']
lm_md5 = self.task_resource.res_dict['lm_md5']
self.download_lm(
lm_url,
os.path.dirname(self.config.decode.lang_model_path), lm_md5)
elif "conformer" in model_type or "transformer" in model_type:
self.config.decode.decoding_method = decode_method
if num_decoding_left_chunks:
assert num_decoding_left_chunks == -1 or num_decoding_left_chunks >= 0, "num_decoding_left_chunks should be -1 or >=0"
self.config.num_decoding_left_chunks = num_decoding_left_chunks
else:
raise Exception("wrong type")
从代码中可以得出,本次采用的为comformer模型,为paddlespeech中的U2Model,训练用数据集为wenetspeech。还有batchsize等参数,可以查看model_conf变量。
使用任务资源(`self.task_resource`)获取与模型名称对应的模型类。
* 创建一个模型实例,该实例使用之前加载和更新的配置进行初始化。
* 将模型设置为评估模式(`self.model.eval()`),这意味着模型将处于不执行任何训练或权重更新的状态,而是准备进行推理或评估。
model_name = model_type[:model_type.rindex(
'_')] # model_type: {model_name}_{dataset}
model_class = self.task_resource.get_model_class(model_name)
model_conf = self.config
model = model_class.from_config(model_conf)
self.model = model
self.model.eval()

1215

被折叠的 条评论
为什么被折叠?



