Android 音频和语音识别

本教程将向您展示如何使用 TensorFlow Lite 与预构建的机器学习模型在 Android 应用程序中识别声音和语音。本教程中所示的音频分类模型可用于检测活动、识别操作或识别语音命令。

音频识别动画演示 本教程将向您展示如何下载示例代码,将项目加载到 Android Studio 中,并解释代码示例的关键部分,以便您可以开始将此功能添加到自己的应用程序中。示例应用程序代码使用 TensorFlow 音频任务库,它处理大多数音频数据录制和预处理。有关如何对音频进行预处理以用于机器学习模型的更多信息,请参阅 音频数据准备和增强

使用机器学习进行音频分类

本教程中的机器学习模型识别 Android 设备麦克风记录的音频样本中的声音或语音。本教程中的示例应用程序允许您在 YAMNet/classifier(识别声音的模型)和识别特定语音词的模型之间切换,该模型使用 TensorFlow Lite 模型制作器 工具 训练。模型对包含 15600 个独立样本的音频片段进行预测,每个片段大约 1 秒长。

设置和运行示例

在本教程的第一部分,您将从 GitHub 下载示例并使用 Android Studio 运行它。本教程的后续部分将探讨示例的相关部分,以便您可以将它们应用于自己的 Android 应用程序。

系统要求

  • Android Studio 版本 2021.1.1(Bumblebee)或更高版本。
  • Android SDK 版本 31 或更高版本
  • Android 设备,最低操作系统版本为 SDK 24(Android 7.0 - 牛轧糖),并已启用开发者模式。

获取示例代码

创建示例代码的本地副本。您将使用此代码在 Android Studio 中创建项目并运行示例应用程序。

要克隆和设置示例代码,请执行以下操作

  1. 克隆 git 存储库
    git clone https://github.com/tensorflow/examples.git
    
  2. 可选:配置您的 git 实例以使用稀疏检出,以便您只有示例应用程序的文件

    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/audio_classification/android
    

导入和运行项目

从下载的示例代码创建项目,构建项目,然后运行它。

要导入和构建示例代码项目,请执行以下操作

  1. 启动 Android Studio
  2. 在 Android Studio 中,选择 **文件 > 新建 > 导入项目**。
  3. 导航到包含 build.gradle 文件的示例代码目录 (.../examples/lite/examples/audio_classification/android/build.gradle) 并选择该目录。

如果您选择了正确的目录,Android Studio 会创建一个新项目并构建它。此过程可能需要几分钟,具体取决于您的计算机速度以及您是否已将 Android Studio 用于其他项目。构建完成后,Android Studio 会在 **构建输出** 状态面板中显示 BUILD SUCCESSFUL 消息。

要运行项目

  1. 从 Android Studio 中,通过选择 **运行 > 运行 'app'** 来运行项目。
  2. 选择一个连接的带有麦克风的 Android 设备来测试应用程序。

接下来的部分将向您展示您需要对现有项目进行的修改,以便使用此示例应用程序作为参考点,将此功能添加到您自己的应用程序中。

添加项目依赖项

在您自己的应用程序中,您必须添加特定的项目依赖项才能运行 TensorFlow Lite 机器学习模型,并访问将标准数据格式(如音频)转换为张量数据格式的实用程序函数,该格式可以由您正在使用的模型处理。

示例应用程序使用以下 TensorFlow Lite 库

以下说明展示了如何将所需的项目依赖项添加到您自己的 Android 应用程序项目中。

要添加模块依赖项

  1. 在使用 TensorFlow Lite 的模块中,更新模块的 build.gradle 文件以包含以下依赖项。在示例代码中,此文件位于此处:.../examples/lite/examples/audio_classification/android/build.gradle

    dependencies {
    ...
        implementation 'org.tensorflow:tensorflow-lite-task-audio'
    }
    
  2. 在 Android Studio 中,通过选择:**文件 > 与 Gradle 文件同步项目** 来同步项目依赖项。

初始化 ML 模型

在您的 Android 应用程序中,您必须在使用模型运行预测之前,使用参数初始化 TensorFlow Lite 机器学习模型。这些初始化参数取决于模型,并且可以包括设置,例如预测的默认最小准确度阈值以及模型可以识别的单词或声音的标签。

TensorFlow Lite 模型包含一个 *.tflite 文件,其中包含模型。模型文件包含预测逻辑,通常包括有关如何解释预测结果的 元数据,例如预测类别名称。模型文件应存储在开发项目的 src/main/assets 目录中,如代码示例所示

  • <project>/src/main/assets/yamnet.tflite

为了方便和代码可读性,示例声明了一个伴随对象,该对象定义了模型的设置。

要在您的应用程序中初始化模型

  1. 创建一个伴随对象来定义模型的设置

    companion object {
      const val DISPLAY_THRESHOLD = 0.3f
      const val DEFAULT_NUM_OF_RESULTS = 2
      const val DEFAULT_OVERLAP_VALUE = 0.5f
      const val YAMNET_MODEL = "yamnet.tflite"
      const val SPEECH_COMMAND_MODEL = "speech.tflite"
    }
    
  2. 通过构建一个 AudioClassifier.AudioClassifierOptions 对象来创建模型的设置

    val options = AudioClassifier.AudioClassifierOptions.builder()
      .setScoreThreshold(classificationThreshold)
      .setMaxResults(numOfResults)
      .setBaseOptions(baseOptionsBuilder.build())
      .build()
    
  3. 使用此设置对象来构造一个 TensorFlow Lite AudioClassifier 对象,其中包含模型

    classifier = AudioClassifier.createFromFileAndOptions(context, "yamnet.tflite", options)
    

启用硬件加速

在您的应用程序中初始化 TensorFlow Lite 模型时,您应该考虑使用硬件加速功能来加快模型的预测计算。TensorFlow Lite 委托 是软件模块,它们使用移动设备上的专用处理硬件(例如图形处理单元 (GPU) 或张量处理单元 (TPU))来加速机器学习模型的执行。代码示例使用 NNAPI 委托来处理模型执行的硬件加速

val baseOptionsBuilder = BaseOptions.builder()
   .setNumThreads(numThreads)
...
when (currentDelegate) {
   DELEGATE_CPU -> {
       // Default
   }
   DELEGATE_NNAPI -> {
       baseOptionsBuilder.useNnapi()
   }
}

建议使用委托来运行 TensorFlow Lite 模型,但不是必需的。有关使用 TensorFlow Lite 委托的更多信息,请参阅 TensorFlow Lite 委托

准备模型的数据

在您的 Android 应用程序中,您的代码通过将现有数据(如音频剪辑)转换为可以由您的模型处理的 张量 数据格式来为模型提供数据。您传递给模型的张量中的数据必须具有与用于训练模型的数据格式匹配的特定维度或形状。

YAMNet/分类器模型 和此代码示例中使用的自定义 语音命令 模型接受表示以 16kHz 录制、时长为 0.975 秒的单声道或单声道音频剪辑的张量数据对象(15600 个样本)。在新的音频数据上运行预测时,您的应用程序必须将该音频数据转换为该大小和形状的张量数据对象。TensorFlow Lite 任务库 音频 API 为您处理数据转换。

在示例代码 AudioClassificationHelper 类中,应用程序使用 Android AudioRecord 对象从设备麦克风录制实时音频。代码使用 AudioClassifier 来构建和配置该对象,以便以适合模型的采样率录制音频。代码还使用 AudioClassifier 来构建一个 TensorAudio 对象来存储转换后的音频数据。然后将 TensorAudio 对象传递给模型进行分析。

要向 ML 模型提供音频数据

  • 使用 AudioClassifier 对象来创建一个 TensorAudio 对象和一个 AudioRecord 对象

    fun initClassifier() {
    ...
      try {
        classifier = AudioClassifier.createFromFileAndOptions(context, currentModel, options)
        // create audio input objects
        tensorAudio = classifier.createInputTensorAudio()
        recorder = classifier.createAudioRecord()
      }
    

运行预测

在您的 Android 应用程序中,一旦您将 AudioRecord 对象和 TensorAudio 对象连接到 AudioClassifier 对象,您就可以对该数据运行模型以生成预测或推断。本教程的示例代码以特定速率对来自实时录制音频输入流的剪辑运行预测。

模型执行会消耗大量资源,因此在单独的后台线程上运行 ML 模型预测非常重要。示例应用程序使用一个 [ScheduledThreadPoolExecutor](https://android-docs.cn/reference/java/util/concurrent/ScheduledThreadPoolExecutor) 对象来将模型处理与应用程序的其他功能隔离开来。

识别具有明确开始和结束的声音(例如单词)的音频分类模型可以通过分析重叠的音频剪辑来在传入的音频流上生成更准确的预测。这种方法有助于模型避免错过在剪辑末尾被切断的单词的预测。在示例应用程序中,每次您运行预测时,代码都会从音频录制缓冲区中获取最新的 0.975 秒剪辑并对其进行分析。您可以通过将模型分析线程执行池的 interval 值设置为短于正在分析的剪辑长度的值来使模型分析重叠的音频剪辑。例如,如果您的模型分析 1 秒剪辑,并且您将间隔设置为 500 毫秒,则模型每次将分析上一个剪辑的后半部分和 500 毫秒的新音频数据,从而创建 50% 的剪辑分析重叠。

要开始对音频数据运行预测

  1. 使用 AudioClassificationHelper.startAudioClassification() 方法来启动模型的音频录制

    fun startAudioClassification() {
      if (recorder.recordingState == AudioRecord.RECORDSTATE_RECORDING) {
        return
      }
      recorder.startRecording()
    }
    
  2. 通过在 ScheduledThreadPoolExecutor 对象中设置固定速率 interval 来设置模型从音频剪辑生成推断的频率

    executor = ScheduledThreadPoolExecutor(1)
    executor.scheduleAtFixedRate(
      classifyRunnable,
      0,
      interval,
      TimeUnit.MILLISECONDS)
    
  3. 上面的代码中的 classifyRunnable 对象执行 AudioClassificationHelper.classifyAudio() 方法,该方法从记录器加载最新的可用音频数据并执行预测

    private fun classifyAudio() {
      tensorAudio.load(recorder)
      val output = classifier.classify(tensorAudio)
      ...
    }
    

停止预测处理

确保您的应用程序代码在应用程序的音频处理片段或活动失去焦点时停止进行音频分类。持续运行机器学习模型会对 Android 设备的电池寿命产生重大影响。使用与音频分类相关的 Android 活动或片段的 onPause() 方法来停止音频录制和预测处理。

要停止音频录制和分类

  • 使用 AudioClassificationHelper.stopAudioClassification() 方法来停止录制和模型执行,如下面的 AudioFragment 类中所示

    override fun onPause() {
      super.onPause()
      if (::audioHelper.isInitialized ) {
        audioHelper.stopAudioClassification()
      }
    }
    

处理模型输出

在您的 Android 应用程序中,在您处理音频剪辑后,模型会生成一个预测列表,您的应用程序代码必须通过执行其他业务逻辑、向用户显示结果或采取其他操作来处理这些预测。任何给定 TensorFlow Lite 模型的输出在它生成的预测数量(一个或多个)和每个预测的描述性信息方面有所不同。在示例应用程序的模型情况下,预测是识别的声音或单词列表。代码示例中使用的 AudioClassifier 选项对象允许您使用 setMaxResults() 方法设置最大预测数量,如 初始化 ML 模型 部分所示。

要从模型获取预测结果

  1. 获取 AudioClassifier 对象的 classify() 方法的结果并将它们传递给侦听器对象(代码参考)

    private fun classifyAudio() {
      ...
      val output = classifier.classify(tensorAudio)
      listener.onResult(output[0].categories, inferenceTime)
    }
    
  2. 使用侦听器的 onResult() 函数通过执行业务逻辑或向用户显示结果来处理输出

    private val audioClassificationListener = object : AudioClassificationListener {
      override fun onResult(results: List<Category>, inferenceTime: Long) {
        requireActivity().runOnUiThread {
          adapter.categoryList = results
          adapter.notifyDataSetChanged()
          fragmentAudioBinding.bottomSheetLayout.inferenceTimeVal.text =
            String.format("%d ms", inferenceTime)
        }
      }
    

此示例中使用的模型生成一个带有分类声音或单词标签的预测列表,以及一个介于 0 和 1 之间的预测分数,表示预测的置信度,其中 1 是最高置信度评级。通常,分数低于 50%(0.5)的预测被认为是不确定的。但是,您如何处理低价值预测结果取决于您和您的应用程序的需求。

模型返回一组预测结果后,您的应用程序可以通过向用户呈现结果或执行其他逻辑来对这些预测采取行动。在示例代码的情况下,应用程序在应用程序用户界面中列出识别的声音或单词。

后续步骤

您可以在 TensorFlow Hub预训练模型指南 页面上找到用于音频处理的其他 TensorFlow Lite 模型。有关使用 TensorFlow Lite 在移动应用程序中实现机器学习的更多信息,请参阅 TensorFlow Lite 开发人员指南