基于WEKWS模型的语音唤醒关键词识别

一、模型描述

1.1 论文解读

本文所使用的模型网络结构继承自论文《Compact Feedforward Sequential Memory Networks for Small-footprint Keyword Spotting》,文中研究了将低秩矩阵分解与传统FSMN相结合的紧凑型前馈顺序记忆网络(cFSMN)用于远场关键字检测任务。此外,文中还分析了其结构参数的影响,为了降低计算成本,将多帧预测(MFP)应用到 cFSMN中;为了进一步提高建模能力,尝试在输出层之前插入小 DNN 层,以实现高级 MFP。最后通过检测误差权衡(DET)曲线下面积(AUC)来衡量模型的性能。

论文中并没有使用 HMM 系统而是使用单词作为建模单元,这样就为预先定义的关键词指定了模型。然而,在论文中,除了主关键字外,系统还应具有添加新关键字的灵活性,因此,文中沿用了传统的关键词/背景 HMM 结构,并使用 Senones(绑定的麦克风状态)作为建模单元。解码图由关键词和背景路径组成,每个关键词路径由一个关键词的 HMM 序列组成,添加一个关键词需要在图中添加一个关键词路径。背景路径是为非关键词语音、噪音和静音建立的,解码图中的维特比搜索通过标记传递分别在竞争的关键词路径和背景路径上运行,一旦活动标记到达关键字路径的末端,就会提取假设语段的声音信息。当关键词和背景路径得分的正则化比率超过预设阈值时,系统就会触发。在搜索过程中,每一帧的得分都会由AM预测。AM 的输入是声学特征,输出是关键词和背景模型的 HMM 状态的后验分布。没有使用语言模型。[1]

图1 cFSMN示意图

       论文中研究了将低秩矩阵分解与传统FSMN相结合的紧凑型前馈顺序记忆网络(cFSMN)用于远场关键字检测任务。其主体为4层cFSMN结构,如下图所示,参数量约750K,适用于移动端设备运行。

论文中实验表明,与需要相同延迟和两倍计算成本的经过良好调谐的长短期记忆(LSTM)相比,cFSMN 在安静和嘈杂环境下记录的测试集上分别实现了 18.11% 和 29.21% 的 AUC 相对下降。应用高级 MFP 后,系统在安静和嘈杂测试集上的 AUC 相对于传统 cFSMN 分别降低了 0.48% 和 20.04%,而计算成本则相对降低了 46.58%。

1.2 模型详解

本文模型采用达摩院语音唤醒预训练模型,模型输入采用Fbank特征,训练阶段使用CTC-loss计算损失并更新参数,输出为基于char建模的中文全集token预测,token数共2599个。测试工具根据每一帧的预测数据进行后处理得到输入音频的实时检测结果。

模型训练采用"basetrain + finetune"的模式,basetrain过程使用大量内部移动端数据,在此基础上,使用1万条设备端录制安静场景“小云小云”数据进行微调,得到最终面向业务的模型。由于采用了中文char全量token建模,并使用充分数据进行basetrain,本模型支持基本的唤醒词/命令词自定义功能,但具体性能无法评估。

目前最新ModelScope版本已支持用户在basetrain模型基础上,使用其他关键词数据进行微调,得到新的语音唤醒模型。

二、WEKWS[2]模型基础

2.1 本地环境配置

环境要求相关包的版本如下:

pyyaml>=5.1

tensorboard

tensorboardX

matplotlib

onnxruntime

flake8==3.8.2

flake8-bugbear

flake8-comprehensions

flake8-executable

flake8-pyi==20.5.0

mccabe

pycodestyle==2.6.0

pyflakes==2.2.0

lmdb

scipy

tqdm

2.2 项目目录

执行项目之前要重新从github仓库下载新的可执行文件,防止出现在运行过程中与上次运行产生的文件发生冲突问题,项目运行前目录为图2所示。

图2 wekws训练前目录 

我们需要先根据上述2.1所述,对相关的依赖包进行安装,防止因未安装包,导致后期训练过于繁琐,conf是模型的参数文件,然后运行path.sh脚本,将环境变量写入当前系统,最后运行run.sh对模型进行训练,训练完成后,我们将得到如下图3目录。

图3 wekws训练后目录 

训练将会持续一百轮,一轮将会训练510次,每隔10次打印一次模型结果,每隔一轮再打印一次结果。最终得到每轮的运行日志保存在exp目录下,data文件是训练集文件。

2.3 脚本说明

脚本关键部分和功能的摘要如下:

2.3.1 下载和数据准备:

下载和提取数据集local/data_download.sh

[ -f ./path.sh ] && . ./path.sh

dl_dir=./data/local

. tools/parse_options.sh || exit 1;
data_dir=$dl_dir
file_name=speech_commands_v0.01.tar.gz
speech_command_dir=$data_dir/speech_commands_v1
audio_dir=$data_dir/speech_commands_v1/audio
url=http://download.tensorflow.org/data/$file_name
mkdir -p $data_dir
if [ ! -f $data_dir/$file_name ]; then
    echo "downloading $url..."
    wget -O $data_dir/$file_name $url
else
    echo "$file_name exist in $data_dir, skip download it"
fi

if [ ! -f $speech_command_dir/.extracted ]; then
    mkdir -p $audio_dir
    tar -xzvf $data_dir/$file_name -C $audio_dir
    touch $speech_command_dir/.extracted
else
    echo "$speech_command_dir/.exatracted exist in $speech_command_dir, skip exatraction"
fi

exit 0

拆分数据集local/split_dataset.py

我们定义了一个名为move_files的函数,用于将指定文件夹中的文件根据给定的文件列表移动到目标文件夹中。首先打开给定的文件列表,并逐行读取文件路径,然后,通过使用os.path.dirname函数获取每个文件路径的目录,并使用os.path.join函数将目录与目标文件夹合并得到目标文件夹的路径。如果目标文件夹不存在,则使用os.mkdir函数创建目标文件夹。最后,使用shutil.move函数将源文件夹中的文件移动到目标文件夹中。在源代码的最后,还通过argparse模块解析命令行参数,并使用move_files函数将音频文件夹中的文件移动到测试文件夹和验证文件夹中,并将音频文件夹重命名为训练文件夹。

def move_files(src_folder, to_folder, list_file):
    with open(list_file) as f:
        for line in f.readlines():
            line = line.rstrip()
            dirname = os.path.dirname(line)
            dest = os.path.join(to_folder, dirname)
            if not os.path.exists(dest):
                os.mkdir(dest)
            shutil.move(os.path.join(src_folder, line), dest)


if __name__ == '__main__':
    '''Splits the google speech commands into train, validation and test set'''
    parser = argparse.ArgumentParser(
        description='Split google command dataset.')
    parser.add_argument(
        'root',
        type=str,
        help='the path to the root folder of the google commands dataset')
    args = parser.parse_args()

    audio_folder = os.path.join(args.root, 'audio')
    validation_path = os.path.join(audio_folder, 'validation_list.txt')
    test_path = os.path.join(audio_folder, 'testing_list.txt')

    valid_folder = os.path.join(args.root, 'valid')
    test_folder = os.path.join(args.root, 'test')
    train_folder = os.path.join(args.root, 'train')

    os.mkdir(valid_folder)
    os.mkdir(test_folder)

    move_files(audio_folder, test_folder, test_path)
    move_files(audio_folder, valid_folder, validation_path)
    os.rename(audio_folder, train_folder)

2.3.2 Kaldi 格式文件准备:

准备用于训练、测试和验证集的 Kaldi 格式文件准备Kaldi格式文件,包括创建目录、生成wav.scp和utt2spk文本文件,wav.scputt2spktext用于计算 CMVN 并格式化数据集:

if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then
  echo "Download and extract all datasets"
  local/data_download.sh --dl_dir $download_dir
  python local/split_dataset.py $download_dir/speech_commands_v1
fi


if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then
  echo "Start preparing Kaldi format files"
  for x in train test valid;
  do
    data=data/$x
    mkdir -p $data
    # make wav.scp utt2spk text file
    find $speech_command_dir/$x -name *.wav | grep -v "_background_noise_" > $data/wav.list
    python local/prepare_speech_command.py --wav_list=$data/wav.list --data_dir=$data
  done
fi

2.3.3 计算CMVN

如果stage小于等于1且stop_stage大于等于1,则执行计算CMVN和格式化数据集的脚本。该脚本使用compute_cmvn_stats.py计算训练数据集的CMVN统计信息,并将结果保存在data/train/global_cmvn中。然后,脚本使用tools/wav_to_duration.sh将数据集的音频文件转换为持续时间,并使用tools/make_list.py生成数据列表。

if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then
  echo "Compute CMVN and Format datasets"
  tools/compute_cmvn_stats.py --num_workers 16 --train_config $config \
    --in_scp data/train/wav.scp \
    --out_cmvn data/train/global_cmvn

  for x in train valid test; do
    tools/wav_to_duration.sh --nj 8 data/$x/wav.scp data/$x/wav.dur
    tools/make_list.py data/$x/wav.scp data/$x/text \
      data/$x/wav.dur data/$x/data.list
  done
fi

2.3.4 训练关键字检测模型

使用torchrun执行wekws/bin/train.py脚本,传递以下参数: --gpus $gpus:使用哪些GPU进行训练 --config $config:配置文件的路径 --train_data data/train/data.list:训练数据的路径 --cv_data data/valid/data.list:验证数据的路径 --model_dir $dir:模型保存的目录 --num_workers 8:用于训练的数据并行性 --num_keywords $num_keywords:关键词的数量--min_duration 50:音频文件的最小持续时间(单位:毫秒) $cmvn_opts:包含CMVN选项的字符串 ${checkpoint:+--checkpoint $checkpoint}:可选的检查点路径参数 最终结果是开始训练。

if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then
  echo "Start training ..."
  mkdir -p $dir
  cmvn_opts=
  $norm_mean && cmvn_opts="--cmvn_file data/train/global_cmvn"
  $norm_var && cmvn_opts="$cmvn_opts --norm_var"
  num_gpus=$(echo $gpus | awk -F ',' '{print NF}')
  torchrun --standalone --nnodes=1 --nproc_per_node=$num_gpus \
   wekws/bin/train.py --gpus $gpus \
    --config $config \
    --train_data data/train/data.list \
    --cv_data data/valid/data.list \
    --model_dir $dir \
    --num_workers 8 \
    --num_keywords $num_keywords \
    --min_duration 50 \
    $cmvn_opts \
    ${checkpoint:+--checkpoint $checkpoint}
fi

2.3.5 模型评估

调用average_model.py脚本将得分检查点、目录和平均数作为参数传递给它,并指定使用val_best作为源路径。然后,创建结果目录,调用compute_accuracy.py脚本进行测试。

if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then
  # Do model average
  python wekws/bin/average_model.py \
    --dst_model $score_checkpoint \
    --src_path $dir  \
    --num ${num_average} \
    --val_best
  # Testing
  result_dir=$dir/test_$(basename $score_checkpoint)
  mkdir -p $result_dir
  python wekws/bin/compute_accuracy.py --gpu 3 \
    --config $dir/config.yaml \
    --test_data data/test/data.list \
    --batch_size 256 \
    --num_workers 8 \
    --checkpoint $score_checkpoint
fi

2.3.6 模型保存

执行以下操作:将score_checkpoint的后缀从".pt"替换为".zip",并将结果赋给jit_model变量;将score_checkpoint的后缀从".pt"替换为".onnx",并将结果赋给onnx_model变量。然后,调用export_jit.py脚本,传递相应的参数,将结果保存在dir/$jit_model文件中。接着,调用export_onnx.py脚本,传递相应的参数,将结果保存在dir/$onnx_model文件中。

if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then
  jit_model=$(basename $score_checkpoint | sed -e 's:.pt$:.zip:g')
  onnx_model=$(basename $score_checkpoint | sed -e 's:.pt$:.onnx:g')
  python wekws/bin/export_jit.py \
    --config $dir/config.yaml \
    --checkpoint $score_checkpoint \
    --jit_model $dir/$jit_model

  python wekws/bin/export_onnx.py \
    --config $dir/config.yaml \
    --checkpoint $score_checkpoint \
    --onnx_model $dir/$onnx_model
fi

2.4 模型评价结果

我们通过绘制准确率和损失率曲线来进一步更加直观的观察模型的训练效果,得到第2轮的训练结果如下。

图4 准确率、损失率曲线

三、服务器环境配置

3.1 使用方式和范围

3.1.1运行环境

现阶段模型只能在Linux-x86_64系统上运行,不支持Mac和Windows系统,模型训练需要用户服务器配置GPU卡,CPU训练暂不支持,本文因本地GPU显存太小,将模型布置在服务器上进行训练。

3.1.2 工具介绍

本文使用附带的kwsbp工具(Linux-x86_64)集进行直接推理,分别测试正样本及负样本集合,综合选取最优工作点。

3.1.3使用范围

移动端设备,Android/iOS型号、版本均不限,使用环境不限,数据集采集音频为16K单通道。

3.2 依赖包安装

依次执行下述命令,在服务器上安装模型的依赖包,配置所需的环境。

!pip install modelscope 
!pip install SentencePiece
!pip install --upgrade pip
!sudo apt-get install build-essential
!sudo apt-get install build-essential
!sudo apt-get install libffi-dev
!sudo apt-get install python3-dev
!pip install tokenizers --no-build-isolation
!pip install --upgrade setuptools wheel
!sudo apt-get update
!pip install transformers
!pip install kwsbp -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html
!sudo apt-get install kwsbp -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html

四、模型测试与演示[3]

4.1 模型推理

from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks

kwsbp_16k_pipline = pipeline(
    task=Tasks.keyword_spotting,
    model='damo/speech_charctc_kws_phone-xiaoyun')

kws_result = kwsbp_16k_pipline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/KWS/pos_testset/kws_xiaoyunxiaoyun.wav')
print(kws_result)

上述代码运行结果如下:

{'kws_type': 'pcm', 'kws_list': [{'keyword': '小云小云', 'offset': 1.89, 'length': 0.51, 'confidence': 0.995018, 'type': 'wakeup'}], 'wav_count': 1}

2023-12-13 07:10:28,218 - modelscope - INFO - PyTorch version 2.1.0+cu118 Found.

2023-12-13 07:10:28,223 - modelscope - INFO - TensorFlow version 2.14.0 Found.

2023-12-13 07:10:28,225 - modelscope - INFO - Loading ast index from /root/.cache/modelscope/ast_indexer

2023-12-13 07:10:28,227 - modelscope - INFO - No valid ast index found from /root/.cache/modelscope/ast_indexer, generating ast index from prebuilt!

2023-12-13 07:10:28,294 - modelscope - INFO - Loading done! Current index file version is 1.10.0, with md5 26bcfc6fb89b2a0a03e3bb75a9f00e95 and a total number of 946 components indexed

2023-12-13 07:10:36,186 - modelscope - WARNING - Model revision not specified, use revision: v1.1.3

Downloading: 100%|██████████| 172k/172k [00:00<00:00, 906kB/s]

Downloading: 100%|██████████| 175k/175k [00:00<00:00, 903kB/s]

为了解释上述输出内容,对各参数的描述如下表:

参数

描述

数值

kws_type

录音格式

pcm

kws_list

关键词列表

{…}

keyword

关键词

小云小云

offset

偏移量

1.89

length

长度

0.51

confidence

置信度

0.995018

type

录音类型

wakeup

wav_count

音频数量

1

表1 各参数描述表

从上述得到的结果我们可以看到,关键词“小云小云”的置信度为0.995018,表示该识别结果非常可靠。

4.2 模型分词能力测试

       为了测试此预训练模型的分词能力,我们使用下述语句“今天天气不错,适合出去游玩”对模型进行测试,测试代码如下:

from modelscope.pipelines import pipeline
word_segmentation = pipeline('word-segmentation',model='damo/nlp_structbert_word-segmentation_chinese-base')
word_segmentation('今天天气不错,适合出去游玩')

输出结果如下:

{'output': ['今天', '天气', '不错', ',', '适合', '出去', '游玩']}

根据上述分词结果,可以看出模型的分词能力比较准确,能够正确地将输入的文本分成一个个的词语,接下来本文将对预训练模型进行训练。

五、模型训练

5.1 训练环境配置

首先根据环境安装文档,新建conda环境并安装Python、深度学习框架以及modelscope语音领域依赖包:

$ conda create -n modelscope python=3.7
$ conda activate modelscope
$ pip install torch torchvision torchaudio
$ pip install "modelscope[audio]" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html
$ pip install tensorboardX
!pip install kaldiio
!pip install modelscope

5.2 加载数据集

5.1.2 kaldi列表

kaldi列表如下所示:

(1)音频列表为“索引+路径”,中间以Tab分隔。

(2)标注列表为“索引+标注”,中间以Tab分隔,标注是否分词均可。

应注意音频数据集要求采集音频为16K单通道,

音频与标注的索引顺序无关联,但集合应当一致,训练时会自动丢弃无法同时索引到路径和标注的数据,各个文件内容如下所示。

|--example_kws

|---wav             # 存放.wav格式音频数据集的文件夹

|---cv_wav.scp       # 存储测试集音频文件路径和标签的文本文件

|---merge_trans.txt    # 存储音频文件的文本转录结果的文本文件

|---merge_wav.scp    # 存储待合并音频文件路径的文本文件

|---test_wav.scp      # 存储测试集音频文件路径的文本文件

|---train_wav.scp     # 存储训练集音频文件路径的文本文件

部分脚本文件内容如下:

$ cat wav.scp

kws_pos_example1   /home/admin/data/test/audios/kws_pos_example1.wav

kws_pos_example2   /home/admin/data/test/audios/kws_pos_example2.wav

...

kws_neg_example1   /home/admin/data/test/audios/kws_neg_example1.wav

kws_neg_example2   /home/admin/data/test/audios/kws_neg_example2.wav

...

$ cat trans.txt

kws_pos_example1   小 云 小 云

kws_pos_example2   小 云 小 云

...

kws_neg_example1   帮 我 导航 一下 回 临江 路 一百零八 还要 几个 小时

kws_neg_example2   明天 的 天气 怎么样

...

由于我们的建模方式及算法的局限性,需要中文的训练音频及全内容标注,与训练中文ASR模型应相同。训练数据需包含一定数量对应关键词和非关键词样本,我们建议关键词数据在25小时以上,混合负样本比例在1:2到1:10之间,实际性能与训练数据量、数据质量、场景匹配度、正负样本比例等诸多因素有关,需要具体分析和调整。

5.3 训练流程

1、手动创建一个本地工作目录,然后配置到work_dir,用于保存所有训练过程产生的文件

2、获取小云模型库中的配置文件,包含训练参数信息,模型ID确保为“damo/speech_charctc_kws_phone-xiaoyun”

3、初始化一个近场唤醒训练器,trainer tag为“speech_kws_fsmn_char_ctc_nearfield”

4、配置准备好的训练数据列表(kaldi风格),音频列表分为train/cv,标注合为一个文件,然后启动训练。

5、配置唤醒词,多个请使用英文“,”分隔;配置测试目录和测试数据列表(kaldi风格),然后启动测试,最终在测试目录生成测试结果文件——score.txt

5.4 模型训练

训练代码保存文件,如example_kws.py,通过命令行启动训练:

! PYTHONPATH=. torchrun --standalone --nnodes=1 --nproc_per_node=2 example_kws.py
# coding = utf-8

import os
from modelscope.utils.hub import read_config
from modelscope.utils.hub import snapshot_download
from modelscope.metainfo import Trainers
from modelscope.trainers import build_trainer

enable_training = True  # 是否启用训练
enable_testing = True  # 是否启用测试

enable_training = True  # 是否启用训练
enable_testing = True  # 是否启用测试

# s1
work_dir = './test_kws_training' # 工作目录

# s2
# 模型ID
model_id = 'damo/speech_charctc_kws_phone-xiaoyun'
# 下载模型快照到的工作目录
model_dir = snapshot_download(model_id)

# 读取模型元数据
configs = read_config(model_id)  # 读取配置文件
# 更新一些配置
configs.train.max_epochs = 10  # 训练的最大轮数
configs.preprocessor.batch_conf.batch_size = 256  # 批大小
configs.train.dataloader.workers_per_gpu = 4  # 每个GPU的训练数据加载器的工作进程数
configs.evaluation.dataloader.workers_per_gpu = 4  # 每个GPU的测试数据加载器的工作进程数

# 将配置保存到文件中
config_file = os.path.join(work_dir, 'config.json')  # 配置文件路径
configs.dump(config_file)  # 将配置保存到文件

# s3
# 构建训练器
kwargs = dict(
    model=model_id,  # 模型ID
    work_dir=work_dir,  # 工作目录
    cfg_file=config_file,  # 配置文件路径
    seed=666,  # 随机种子
)
trainer = build_trainer(
    Trainers.speech_kws_fsmn_char_ctc_nearfield, default_args=kwargs) # 构建训练器

# s4
# 训练数据路径
train_scp = '/content/drive/MyDrive/Colab_Notebooks/ModelScope/example_kws/train_wav.scp'
# 交叉验证数据路径
cv_scp = '/content/drive/MyDrive/Colab_Notebooks/ModelScope/example_kws/cv_wav.scp'
# 测试数据路径
test_scp = '/content/drive/MyDrive/Colab_Notebooks/ModelScope/example_kws/test_wav.scp'
# 标签文件路径
trans_file = '/content/drive/MyDrive/Colab_Notebooks/ModelScope/example_kws/merge_trans.txt'

# 训练检查点路径
train_checkpoint = ''
# 测试检查点路径
test_checkpoint = ''

if enable_training:  # 如果启用训练
    kwargs = dict(
        train_data=train_scp,  # 训练数据文件路径
        cv_data=cv_scp,  # 交叉验证数据文件路径
        trans_data=trans_file,  # 转录文件路径
        checkpoint=train_checkpoint,  # 检查点路径
        tensorboard_dir='tb_test',  # TensorBoard日志目录
        need_dump=True,  # 是否需要保存模型
    )

try:
    # 训练模型
    trainer.train(**kwargs) # 训练模型
except Exception as e:
    print(f"Error during training: {e}")

rank = int(os.environ['RANK']) # 进程排名
world_size = int(os.environ['WORLD_SIZE']) # 总进程数
if world_size > 1 and rank != 0:# 如果总进程数大于1且排名不为0
    enable_testing = False# 禁用测试

# s5
if enable_testing:# 如果启用测试
    # 关键词
    keywords = '小云小云'
    # 测试结果保存目录
    test_dir = os.path.join(work_dir, 'test_dir')

    # 测试配置
    kwargs = dict(
        test_dir=test_dir,  # 测试结果目录
        test_data=test_scp,  # 测试数据文件路径
        trans_data=trans_file,  # 转录文件路径
        average_num=10,  # 平均次数
        gpu=0,  # GPU ID
        keywords=keywords,  # 关键词
        batch_size=256,  # 批大小
    )
    # 评估模型
    #print(f"test_checkpoint: {test_checkpoint}")
    #print(f"kwargs: {kwargs}")
    trainer.evaluate(test_checkpoint, None, **kwargs)
    print(f"Test results are saved in {test_dir}/score.txt")
world_size = int(os.environ['WORLD_SIZE']) # 总进程数
if world_size > 1 and rank != 0:# 如果总进程数大于1且排名不为0
    enable_testing = False# 禁用测试

# s5
if enable_testing:# 如果启用测试
    # 关键词
    keywords = '小云小云'
    # 测试结果保存目录
    test_dir = os.path.join(work_dir, 'test_dir')

    # 测试配置
    kwargs = dict(
        test_dir=test_dir,  # 测试结果目录
        test_data=test_scp,  # 测试数据文件路径
        trans_data=trans_file,  # 转录文件路径
        average_num=10,  # 平均次数
        gpu=0,  # GPU ID
        keywords=keywords,  # 关键词
        batch_size=256,  # 批大小
    )
    # 评估模型
    #print(f"test_checkpoint: {test_checkpoint}")
    #print(f"kwargs: {kwargs}")
    trainer.evaluate(test_checkpoint, None, **kwargs)
print(f"Test results are saved in {test_dir}/score.txt")

5.5 模型评价

查看运行输出的日志文件score.txt文件如下:

20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_50 detected 小云小云 0.935
20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_38 detected 小云小云 0.992
fd59df10517f4a92ab9b1d31cd94c0b9_362d4ab870bf4722962fa4d087d8062f rejected
20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_48 detected 小云小云 0.841
20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_6 detected 小云小云 0.991
fd59df10517f4a92ab9b1d31cd94c0b9_ad1f518a7bdc4f57b355fb1aaddcd9c6 rejected
20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_37 detected 小云小云 0.982
20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_41 detected 小云小云 0.988
fd59df10517f4a92ab9b1d31cd94c0b9_e5c46479973a41a8b3ba04010a69d4c6 rejected
20200707_spk57db_storenoise52db_40cm_xiaoyun_sox_30 detected 小云小云 0.819
fd59df10517f4a92ab9b1d31cd94c0b9_0b448e3108604646a9828403fa722dc1 rejected

我们通过上述文件进一步统计并画出Det曲线如下图5。

图5 Det曲线

六、总结

综上所述,本文最终通过wekws模型和百度的预训练模型对论文Compact Feedforward Sequential Memory Networks for Small-footprint Keyword Spotting进行了复现,并且在其基础上尝试更换新的数据集的操作,最终根据开源数据集,basetrain使用内部移动端ASR数据5000+小时;finetune使用1万条众包安静场景"小云小云"数据以及约20万条移动端ASR数据进行训练。最终得到的结果为:模型在自建9个场景各50句的正样本集(共450条)测试,唤醒率为93.11%;在自建的移动端负样本集上测试,误唤醒为40小时0次。但是考虑到正负样本测试集覆盖场景不够全面,可能有特定场合/特定人群唤醒率偏低或误唤醒偏高问题。

参考文献:

[1]Chen, M., Zhang, S., Lei, M., Liu, Y., Yao, H., Gao, J. (2018) Compact Feedforward Sequential Memory Networks for Small-footprint Keyword Spotting. Proc. Interspeech 2018, 2663-2667.

[2]wenet-e2e/wekws: Production First and Production Ready End-to-End Keyword Spotting Toolkit (github.com)

[3]CTC语音唤醒-移动端-单麦-16k-小云小云 · 模型库 (modelscope.cn) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/331959.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中北数据结构2023真题

雪雾: 设计一个算法&#xff0c;将一个节点值为自然数的单列表拆分成两个单列表&#xff0c;原表中值为偶数的节点保留&#xff0c;而值为奇数的节点&#xff0c;按他们在原表的相对次序组成一个新的单列表 #include <stdio.h> #include <stdlib.h>typedef struct…

一文教你V3+TS(保姆级教程)

TS 与 JS 的区别 基础类型 ts 的常用类型 ts 的常用基础类型分为两种&#xff1a; js 已有类型 原始类型&#xff1a;number/string/boolean/null/undefined/symbol 对象类型&#xff1a;object&#xff08;包括&#xff0c;数组、对象、函数等对象&#xff09; 每次编写前…

oracle11g的闪回技术-闪回表-时间戳

--数据库闪回表 --1创建表&#xff08;登录模式system&#xff09; CREATE table dept2 as select * from dept;--此语句如果加上where条件可用于工作中数据的临时备份 select * from dept2;--查询新建表信息 --进入sql>set time on 通过时间点闪回 记录弹出的时间点&#…

软件测试|使用Python生成PDF文件

简介 PDF&#xff08;Portable Document Format&#xff09;是一种常用的文档格式&#xff0c;具有跨平台兼容性、保真性、安全性和交互性等特点。我们日常生活工作中的合同、报告、论文等通常都采用PDF格式&#xff0c;以确保文档在不同的操作系统&#xff08;例如 Windows、…

腾讯云轻量化应用服务器_轻量化应用服务器_轻量化私有云

腾讯云轻量应用服务器开箱即用、运维简单的轻量级云服务器&#xff0c;CPU内存带宽配置高并且价格特别便宜&#xff0c;大带宽&#xff0c;但是限制月流量&#xff0c;轻量2核2G3M带宽62元一年、2核2G4M优惠价118元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c…

【不用找素材】ECS 游戏Demo制作教程(1) 1.15

一、项目设置 版本&#xff1a;2022.2.0f1 &#xff08;版本太低的话会安装不了ECS插件&#xff09; 模板选择3D URP 进来后移除URP&#xff08;因为并不是真的需要&#xff0c;但也不是完全不需要&#xff09; Name: com.unity.entities.graphics Version: 1.0.0-exp.8 点击…

推荐 10 个基于 Stable Diffusion 的 AI 绘画网站

在当今快速发展的人工智能领域&#xff0c;AI 绘画已经成为一个不可忽视的趋势。特别是基于 Stable Diffusion 技术的 AI 绘画工具&#xff0c;以其强大的图像生成能力和丰富的创意潜力吸引了众多艺术家和设计师的目光。对于那些热爱艺术创作&#xff0c;但又缺乏专业绘画技巧的…

三、MySQL实例初始化、设置、服务启动关闭、环境变量配置、客户端登入(一篇足以从白走到黑)

目录 1、选择安装的电脑类型、设置端口号 2、选择mysql账号密码加密规则 3、设置root账户密码 4、设置mysql服务名和服务启动策略 5、执行设置&#xff08;初始化mysql实例&#xff09; 6、完成设置 7、MySQL数据库服务的启动和停止 方式一&#xff1a;图形化方式 方式…

《Python数据分析技术栈》第01章 03 Python基础(Python Basics)

03 Python基础&#xff08;Python Basics&#xff09; 《Python数据分析技术栈》第01章 03 Python基础&#xff08;Python Basics&#xff09; In this section, we get familiar with the syntax of Python, commenting, conditional statements, loops, and functions. 在…

LRU Cache

文章目录 1. 什么是LRU Cache2. LRU Cache的实现3. LRU Cache的OJ题目分析AC代码 1. 什么是LRU Cache LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用&#xff0c;它是一种Cache替换算法。 什么是Cache&#xff1f; 狭义的Cache指的是位于CPU和主存间的快速RAM…

linux 更新镜像源

打开终端&#xff0c;备份一下旧的 源 文件&#xff0c;以防万一 cd /etc/apt/ ls sudo cp sources.list sources.list.bak ls然后打开清华大学开源软件镜像站 搜索一下你的linux发行版本&#xff0c;我这里是ubuntu发行版本 点击这个上面图中的问号 查看一下自己的版本号&a…

【控制篇 / 分流】(7.4) ❀ 03. 对国内和国际IP网段访问进行分流 ❀ FortiGate 防火墙

【简介】公司有两条宽带用来上网&#xff0c;一条电信&#xff0c;一条IPLS国际专线&#xff0c;由于IPLS仅有2M&#xff0c;且价格昂贵&#xff0c;领导要求&#xff0c;访问国内IP走电信&#xff0c;国际IP走IPLS&#xff0c;那么应该怎么做&#xff1f; 国内IP地址组 我们已…

KubeSphere 开源社区 2023 年度回顾与致谢

2023 年结束了&#xff0c;让我们再一次一起回顾一下 KubeSphere 开源社区在过去一年的变化。更重要的是&#xff0c;本篇文章将会对 2023 年所有参与过 KubeSphere 社区贡献的成员致以最诚挚的感谢&#xff0c;快来看看有没有你&#xff01; 开源项目发展情况 2023 年&#…

黑马 Javaweb - MySQL 精华篇

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 知…

查询数据库表字段具有某些特征的表

目录 引言举例总结 引言 当我们把一个项目做完以后&#xff0c;客户要求我们把系统中所有的电话&#xff0c;证件号等进行加密处理时&#xff0c;我们难道要一个表一表去查看那些字段是电话和证件号码吗&#xff1f; 这种办法有点费劲&#xff0c;下面我们来探索如何找到想要的…

mybatis分页、延迟加载、立即加载、一级缓存、二级缓存

mybatis分页、延迟加载、立即加载、一级缓存、二级缓存 分页延迟加载和立即加载缓存一级缓存二级缓存 分页 分类&#xff1a; 使用Limit&#xff0c;来进行分页&#xff1b;物理分页使用RowBounds集合来保存分页需要数据&#xff0c;来进行分页;逻辑分页&#xff1b;本质是全…

Air780E开发板开发环境搭建

开发板原理图 开发软件 下载网站 https://luatos.com/luatools/download/last 使用教程 烧录教程 - LuatOS 文档 开发流程 首先下载最新版本的Luatools 然后新建一个Luatools文件夹&#xff0c;将下载的exe文件放入其中后&#xff0c;再打开exe文件&#xff08;会生成目…

《WebKit 技术内幕》之四(2): 资源加载和网络栈

2.Chromium 多进程资源加载 2,1 多进程 资源的实际加载在各个WebKit移植中有不同的实现。Chromium采用的多进程的资源加载机制。 ResourceHandle 类之下的部分是不同移植对获取资源的不同实现&#xff0c;Chromium 中是 多进程资源加载 。主要是多个Renderer进程和Browser进程…

SystemVerilog验证测试平台

2.2定宽数组 相比于 Verilog1995中的一维定宽数组, System verilog提供了更加多样的数组类型,功能上也大大增强。 2.2.1定宽数组的声明和初始化 Verilog要求在声明中必须给出数组的上下界。因为几乎所有数组都使用0作为索引下界,所以 System verilog允许只给出数组宽度的便捷声…

华为DHCP配置

1. 全局地址池和接口地址池的应用场景有什么不同呢&#xff1f; 答&#xff1a;接口地址池适用于当前接口只给DHCP client分配与接口同一网段的IP地址的场景。 全局地址池可以给DHCP Client分配与接口同网段的IP地址&#xff0c;也可以分配不同网段的IP地址&#xff08;DHCP中…