Kaldi 模型在 Android 端的运行

前文已经成功使用 kaldi 将模型训练好并解码测试,现在我们借助 vosk-api 来让模型在 Android 手机上跑起来吧!

所用项目

kaldi-android-demo,一个 kaldi 模型在 android 运行的 demo,作者还提供了些预训练的模型,如果不需要使用自己训练的模型的话,或者没有太多修改的话,借鉴这个 demo 足以使大多 kaldi 模型在 android 上运行测试起来。

由于我们需要使用自己训练的模型,所以我们必须对 aar 做些定制化,也就需要修改 vosk-api 项目,它会帮助我们将 kaldi 编译成 aar 使之能在 arm 平台上运行。

使用

首先将 vosk-api 项目 pull 下来,对于 android 平台 aar 的生成,只需要进入项目 android 目录然后使用 gradle 编译即可。

1
2
cd android
gradle build

如果有缺少 ANDROID_SDK_HOMEANDROID_NDK_HOME 环境之类的报错,还请根据报错信息配置后再重试。

这个编译过程会非常的耗时,因为编译命令首先会执行 android/build-kaldi.sh 脚本,而这个脚本会把整个 kaldi 下载下来并编译。每次编译 aar 都会重复相同步骤,未免浪费资源,可以将 android/build-kaldi.sh 脚本中每个步骤做分割,按 kaldi 项目的风格,增加 stage 控制,之后再编译时,先手动修改 stage, 越过不需要执行的步骤。如果后面修改了 kaldi 源码,也一般只需要额外编译所属模块即可。像这样:

1
2
3
4
5
6
7
8
9
10
11
if [ $stage -le 7 ]; then
cd $WORKDIR/kaldi/src

CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --use-cuda=no \
--mathlib=OPENBLAS --shared \
--android-incdir=${ANDROID_TOOLCHAIN_PATH}/sysroot/usr/include \
--host=$HOST --openblas-root=${WORKDIR}/local \
--fst-root=${WORKDIR}/local --fst-version=${OPENFST_VERSION}

make -j $nj nnet3;
fi

build-kaldi.sh 执行完后,gradle 会执行 task swig,使用 swig 工具将 src 目录下的文件转为 java 并生成 JNI。所以,如果要想对模型和逻辑做些定制化,就要从 src 目录下的这几个文件入手:

1
json.h  kaldi_recognizer.cc  kaldi_recognizer.h  model.cc  model.h  spk_model.cc  spk_model.h  vosk.i

这里我只是稍微改了下 model.cc,修改 feature_info_.use_ivectors 使之能够运行没有 ivector 特征的模型。

kaldi-android-demo所提供的模型 fst 是 LookAhead decoding fst ,其实代码里也支持普通的 HCLG.fst:

1
2
3
hclg_fst_rxfilename_ = model_path_str + "/HCLG.fst";
hcl_fst_rxfilename_ = model_path_str + "/HCLr.fst";
g_fst_rxfilename_ = model_path_str + "/Gr.fst";

其他琐碎经验:

  • 如果你像我一样不需要使用项目中的 SpeechRecognizer 而是想要完全定制 AudioRecord 输入源,可以将 build.gradle 中, java.srcDirs 部分的 src/main/java 注释掉。

解码测试

在你的项目中加入编译生成的 aar 以及之前的模型文件(哪些模型文件是必要的可以参考 src/model.cc 代码中 各个 _rxfilename后缀变量),使用整个模型文件的目录构建 org.kaldi.Modelorg.kaldi.KaldiRecognizer ,然后就可以不断向 KaldiRecognizer 喂音频数据并得到结果了,具体实现参考 vosk-api 项目中的 android\src\main\java\org\kaldi\SpeechRecognizer.java 以及 kaldi-android-demo 的实现细节。