iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Mobile Development

Flutter :30天打造念佛App,跨平台應用從Mobile到VR,讓極樂世界在眼前實現!系列 第 16

[ Day 16 ] Flutter 語音辨識 深入應用篇— 生活在地球的勇者啊,阿彌陀佛怎麼念呀?(1)

  • 分享至 

  • xImage
  •  

2025 iThome鐵人賽
「 Flutter :30天打造念佛App,跨平台從Mobile到VR,讓極樂世界在眼前實現 ! 」
Day 16
「 Flutter 語音辨識 深入應用篇 — 生活在地球的勇者啊,阿彌陀佛怎麼念呀?(1)


前言

昨天我們已經知道如何在flutter使用sherpa_onnx實作離線語音轉文字,
今天我們要來深入語音辨識,從App開發的角度來認識以下內容:
音訊要先怎麼處理?」、
如何設定模型?」、
語音轉文字背後的完整流程」。

Day16 文章目錄:
一、音訊處理
二、設定模型
三、語音轉文字流程總覽


一、音訊處理

麥克風錄音是採用16 kHz、單聲道、PCM16,
模型要的是16 kHz、單聲道、 Float32的連續波形(約 -1.0~+1.0) ,
所以我們必須先把 PCM16(Int16)→ Float32 並做正規化後再餵進模型

PCM16
常見的未壓縮數位音訊格式(原始音訊),指每個取樣用 16 位元(bits)表示,
通常以整數 Int16(-32768~32767)儲存。

正規化
將 Int16 振幅等比例縮放到 Float32的 -1.0~+1.0 範圍,例如float = int16 / 32768.0。
相較於整數Int,使用浮點數Float,能表示更細緻的能量變化,也符合後續特徵計算與模型推論需求。

Float32List convertBytesToFloat32(Uint8List bytes, [endian = Endian.little]) {
  final values = Float32List(bytes.length ~/ 2);

  final data = ByteData.view(bytes.buffer);

  for (var i = 0; i < bytes.length; i += 2) {
    int short = data.getInt16(i, endian);
    values[i ~/ 2] = short / 32768.0;
  }

  return values;
}

二、模型設定

  • sherpa-onnx 離線語言模型:

Flutter sherpa_onnx ASR模型一覽
(1) 點選下載 中、英雙語模型
(2) 點選下載 純中文模型
建議:使用者第一次啟動時才下載模型,App體積會比較小

  • encoder(聲學編碼器)、decoder/Prediction(預測器)、joiner(融合器)

模型資料夾內部檔案,要在OnlineModelConfig 填入對應的項目名稱
備註:OnlineModel的Online 是指即時串連的語音轉文字模式,與是否網路連線無關

encoder:將語音特徵轉換成向量的聲學表徵

decoder:根據已輸出的 token 序列,預測下一個 token 是什麼。

Joiner:
把 encoder 的聲學表徵 與 decoder 的語言上下文表徵 融合,
為詞彙表中每個候選 token 輸出一個分數,供後續解碼挑選。

備註:
語言模型不是直接讀人類的中英文字詞,而是先將人類的字詞拆分成一個個小token,
透過token映射的對應ID編號進行查找。

token : 模型處理的最小單位。
token 序列 : 一段文字拆解後,轉換成一連串的 token。

模型設定流程:
createOnlineRecognizer → getModelConfigByModelName → sherpa_onnx.OnlineModelConfig

Future<sherpa_onnx.OnlineRecognizer> createOnlineRecognizer(
    String modelName) async {
  final type = 0;
  final localModelConfig =
      await getModelConfigByModelName(modelName: modelName);
  final config = sherpa_onnx.OnlineRecognizerConfig(
    model: localModelConfig,
    ruleFsts: '',
  );

  return sherpa_onnx.OnlineRecognizer(config);
}
----
Future<sherpa_onnx.OnlineModelConfig> getModelConfigByModelName(
    {required String modelName}) async {
  final Directory directory = await getApplicationDocumentsDirectory();
  final modulePath = join(directory.path, modelName);
  switch (modelName) {
    case "sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20":
      final modelDir = modulePath;
      return sherpa_onnx.OnlineModelConfig(
        transducer: sherpa_onnx.OnlineTransducerModelConfig(
          encoder: '$modelDir/encoder-epoch-99-avg-1.int8.onnx',//聲學編碼
          decoder: '$modelDir/decoder-epoch-99-avg-1.onnx',//預測器
          joiner: '$modelDir/joiner-epoch-99-avg-1.onnx',//融合器
        ),
        tokens: '$modelDir/tokens.txt',
        modelType: 'zipformer',
      );
    default:
      throw ArgumentError('Unsupported modelName: $modelName');
  }
}

三、語音轉文字流程總覽

[麥克風輸入]
  └─ 16 kHz / Mono / PCM16
      │
      ├─ Int16 → Float32 
      │
   [前端特徵/訊號處理](加窗、梅爾頻譜…)
      │
   [Encoder 聲學編碼器]  →  產生高階表徵
      │
      │   ┌───────────────────────────┐
      └──▶│ Joiner 融合器 │───▶ 輸出分數 logits → 搜尋/解碼 → token  → 文字
          └───────────────────────────┘
                    ▲
                    │
          [Prediction/Decoder 預測網路/預測器](只看已輸出 token)

1. 取樣:聲波的連續聲壓,由麥克風轉為連續電壓後,以固定頻率量測電壓(次/秒)。

例如:電話(8000 Hz )每秒量測8000次、CD音訊(44100 Hz)每秒量測44100次
我們進行語音轉文字的錄音,16kHz,就是每秒量測16000次

2. 量化:將類比聲音的波形轉換成數位。

量測到的連續幅度,會壓成有限位階(bit depth)。
例如:常見的量化位元數是16 bit ,也就是 PCM16(16位元整數)。
位元數會影響量化的精度,也就是會不會出現失真的狀況。

備註:
單聲道、雙聲道(立體聲),指的是該語音產生幾個波形。
單聲道產生一個波形,雙聲道產生兩個波形。
多數的語言模型是使用單聲道。

3. 前端特徵處理

加窗:可以將連續音訊切成一塊塊短時間片段,
讓每個片段更穩定、好分析,有助於即時串流語音辨識。

梅爾濾波器組:把線性頻率映射到更貼近人耳感受的梅爾尺度。
因為人耳對低頻更敏感、能分得更細,高頻則較不敏感。

4. 編碼Encoder、預測Decoder、融合Joiner

特徵丟進 Encoder,得到聲學表徵。
Decoder 看已輸出的 token 序列(歷史),產生語言上下文表徵。
Joiner 融合 聲學表徵 + 語言上下文表徵 ,對模型詞彙表tokens輸出分數。

5. 搜尋/解碼

解碼流程會依據各 token 的分數搜尋最可能的序列,常見策略:
Greedy:每一步挑分數最大的 token,速度快,但較容易錯過全局最佳解。
Beam search:同時保留多條高分路徑,結果較穩定但速度較慢(相較Greedy)。

找到最有可能的序列後,會將它們從編號ID→token→文字,
做必要的後處理(例如移除特殊符號)→輸出結果。

6. 端點偵測與最終結果

即時串流辨識會先產生即時的暫時結果(partial),讓畫面先更新;
當偵測到端點(停頓或語音活動結束),就把當前片段標記為最終結果(final)
並重置stream,開始下一句。


Day16 重點回顧

重點 內容
音訊處理 轉Float32餵模型
模型設定 Encoder、Decoder、Joiner
語音轉文字流程總覽 基礎原理與流程

上一篇
[ Day 15 ] Flutter 語音辨識 實戰應用篇— 生活在地球的勇者啊,你聽過阿彌陀佛嗎(6) #地端語音轉文字 #sherpa_onnx
下一篇
[ Day 17 ] Flutter 語音辨識 深入應用篇— 生活在地球的勇者啊,阿彌陀佛怎麼念呀(2) #KWS keyword spotting #關鍵字偵測
系列文
Flutter :30天打造念佛App,跨平台應用從Mobile到VR,讓極樂世界在眼前實現!21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言