Android 適用的聲音和文字辨識

本教學課程說明如何搭配預先建構的機器學習模型使用 TensorFlow Lite,以便在 Android 應用程式中辨識聲音和口語字詞。音訊分類模型 (例如本教學課程中顯示的模型) 可用於偵測活動、識別動作或辨識語音指令。

音訊辨識動畫示範 本教學課程說明如何下載範例程式碼、將專案載入 Android Studio,並說明程式碼範例的主要部分,讓您可以開始將此功能新增至自己的應用程式。範例應用程式程式碼使用 TensorFlow Task Library for Audio,此程式庫會處理大部分的音訊資料錄製和前處理作業。如要進一步瞭解如何前處理音訊以搭配機器學習模型使用,請參閱音訊資料準備和擴增

搭配機器學習的音訊分類

本教學課程中的機器學習模型可辨識透過 Android 裝置上的麥克風錄製的音訊樣本中的聲音或字詞。本教學課程中的範例應用程式可讓您在 YAMNet/classifier (可辨識聲音的模型) 和可辨識特定口語字詞的模型之間切換,後者是使用 TensorFlow Lite Model Maker 工具訓練而成的。這些模型會針對音訊片段執行預測,這些片段每個都包含 15600 個個別樣本,長度約為 1 秒。

設定並執行範例

在本教學課程的第一部分中,您將從 GitHub 下載範例,並使用 Android Studio 執行。本教學課程的以下章節將探討範例的相關章節,方便您將這些章節套用至自己的 Android 應用程式。

系統需求

  • Android Studio 2021.1.1 (Bumblebee) 以上版本。
  • Android SDK 31 以上版本
  • Android 裝置,最低 OS 版本為 SDK 24 (Android 7.0 - Nougat),並已啟用開發人員模式。

取得範例程式碼

建立範例程式碼的本機副本。您將使用此程式碼在 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 中,依序選擇「File (檔案)」>「New (新增)」>「Import Project (匯入專案)」。
  3. 瀏覽至包含 build.gradle 檔案 (.../examples/lite/examples/audio_classification/android/build.gradle) 的範例程式碼目錄,然後選取該目錄。

如果您選取正確的目錄,Android Studio 就會建立新專案並建構專案。這個程序可能需要幾分鐘時間,具體取決於您的電腦速度,以及您是否曾將 Android Studio 用於其他專案。建構完成後,Android Studio 會在「Build Output (建構輸出)」狀態面板中顯示 BUILD SUCCESSFUL 訊息。

執行專案的方法

  1. 在 Android Studio 中,依序選取「Run (執行)」>「Run '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 中,依序選取「File (檔案)」>「Sync Project with Gradle Files (將專案與 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 應用程式中,您的程式碼會提供資料給模型以進行解讀,方法是將現有資料 (例如音訊片段) 轉換成 Tensor 資料格式,以便供您的模型處理。您傳遞至模型的 Tensor 中的資料必須具有特定的維度或形狀,才能與用於訓練模型的資料格式相符。

本程式碼範例中使用的 YAMNet/classifier 模型和自訂語音指令模型接受 Tensor 資料物件,這些物件代表以 16kHz 錄製的單聲道或單聲道音訊片段,每個片段長度為 0.975 秒 (15600 個樣本)。在新的音訊資料上執行預測時,您的應用程式必須將該音訊資料轉換成該大小和形狀的 Tensor 資料物件。TensorFlow Lite Task Library Audio 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://developer.android.com/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)
      ...
    }
    

停止預測處理

請確認您的應用程式程式碼在應用程式的音訊處理 Fragment 或 Activity 失去焦點時,停止執行音訊分類。持續執行機器學習模型會對 Android 裝置的電池續航力造成重大影響。使用與音訊分類相關聯的 Android Activity 或 Fragment 的 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 之間的預測分數 (以 Float 表示),代表預測的信賴度,其中 1 代表最高信賴度評級。一般而言,分數低於 50% (0.5) 的預測會被視為不明確。不過,如何處理低價值預測結果取決於您和您的應用程式需求。

一旦模型傳回一組預測結果,您的應用程式就可以根據這些預測採取行動,方法是向使用者呈現結果,或執行其他邏輯。就範例程式碼而言,應用程式會在應用程式使用者介面中列出已識別的聲音或字詞。

後續步驟

您可以在 TensorFlow Hub 和透過預先訓練模型指南頁面,找到適用於音訊處理的其他 TensorFlow Lite 模型。如要進一步瞭解如何使用 TensorFlow Lite 在行動應用程式中導入機器學習,請參閱TensorFlow Lite 開發人員指南