# Audio
## Week 1F
----
## 前言
本來 Chatbot 寫得很開心
有一天主管突然跑來跟我說
「欸欸,你要不要接個 ASR 上去」
於是再度開啟我的語音處理之路
----
## 簡介
聲音是一種縱波
一般而言麥克風上有振膜
用來紀錄聲波的振幅
連續的振幅可以形成一個聲音
----
## Sample Rate
採樣率 Sample Rate
是在將聲音
從**類比訊號**轉為**數位訊號**的過程中
出現的概念
用來表示聲音訊號的取樣頻率
例如 48K 代表一秒取樣 48,000 次
----
## 實際應用
現在的麥克風多能錄製到 40K 以上
一般電話多為 8K 左右
但是語音辨識通常 8K 或 16K 就夠了
因此需要做 Downsampling
----
## 語音特徵
語音辨識通常會有取特徵的動作
一般透過[傅立葉轉換](https://w.wiki/3jUY)分析**音頻**
然後計算 [FBank](https://w.wiki/7U3T) 或 [MFCC](https://w.wiki/7U3L) 之類的特徵
取完特徵就能更輕鬆的做機器學習任務
----
## 使用單位
語音處理通常使用 Frame 作為單位
常見的單位是 10 ms 作為一個 Frame
也有 20 ms 或 30 ms 的
因此對 16K 的聲音訊號而言
一個 10 ms 的 Frame 會有 160 個樣本點
----
## 資料型態
通常使用 Bit Depth 來描述樣本點的資料型態
通常為 16 Bit 也就是 2 Bytes 整數
把樣本直接存起來的檔案也可稱為
Pulse-Code Modulation, PCM
常見的 Wave 檔 (.wav)
就是加了 44 Byte Header 的 PCM
----
## VAD
語音活性檢測 Voice Activity Detection, VAD
用來檢查現在有沒有人在講話
一般而言 VAD 的運算量比較小,而 ASR 運算量比較大
所以通常在 VAD 被觸發一段時間後才開始做 ASR
這樣可以節省計算資源
----
## EPD
端點偵測 End-Point Detection, EPD
與 VAD 不同的地方在於
VAD 只針對某個 Frame 是否為人聲
而 EPD 通常觀察一段連續的 VAD 狀態
用來決定是否啟動語音辨識
----
## ASR
Automatic Speech Recognition
也稱為 Speech-To-Text, STT
傳統 ASR 通常由
聲學模型 Acoustic Model, AM
語言模型 Language Model, LM
所組成
----
## 聲學模型
AM 主要的目的是辨識聲音訊號的音節
就好比在辨識我們講話的注音
其結果可能像是「ㄋㄧˊ ㄏㄠˇ ㄚ」
----
## 語言模型
LM 則用來看這些音節的順序
可能構成哪些合理的句子
以「ㄋㄧˊ ㄏㄠˇ ㄚ」為例
LM 就會算出「你好啊」的機率比較高
而不是「泥豪阿」
----
## KWS
關鍵詞偵測 Keyword Spotting, KWS
是一種形式比較單純的語音辨識
只辨識特定的關鍵字,來避免語音誤動
像是 Hey Siri 與 OK Google 就是 KWS
----
## Whisper
講了這麼多
其實 Whisper 也不是這種傳統做法
而是直接用 Transformers 訓練一個
Encoder-Decoder 模型
---
# 實做環節
----
## 安裝錄音套件
透過 PyAudio 套件錄音
Linux 上需要安裝以下套件
```bash
sudo apt install portaudio19-dev python3-pyaudio
```
----
## 從麥克風錄音
```python=
import pyaudio
recorder = pyaudio.PyAudio()
stream = recorder.open(
format=pyaudio.paInt16,
channels=1,
rate=16000,
input=True,
frames_per_buffer=160,
)
# 10ms = 1 Frame, 5s = 5000ms = 500 Frames
frames = [stream.read(160) for _ in range(500)]
```
----
## 存成音檔
透過 Python 內建的 `wave` 套件存成音檔
```python=
import wave
with wave.open("output.wav", "wb") as wf:
wf.setnchannels(1)
wf.setsampwidth(2) # 16 Bits = 2 Bytes
wf.setframerate(16000)
wf.writeframes(b"".join(frames))
```
----
## VAD 實做
透過 [webrtcvad](https://github.com/wiseman/py-webrtcvad) 套件可以輕鬆達成
每次輸入必須是一個完整的 Frame
```python=
import webrtcvad
vad = webrtcvad.Vad()
vad.set_mode(1)
sample_rate = 16000
frame = b"\x00\x00" * 160 # 2 Bit x 1 Frame
print(vad.is_speech(frame, sample_rate))
```
----
## ASR 實做
透過 [Faster Whisper](https://github.com/guillaumekln/faster-whisper) 輕鬆調用 ASR 模型
```python=
from faster_whisper import WhisperModel
model = WhisperModel(
"large-v2",
device="cuda",
compute_type="int8_float16", # 8-Bit Quantization
)
segments, info = model.transcribe("audio.mp3")
print(f"Language: {info.language}")
print(f"Lang Prob: {info.language_probability}")
for seg in segments:
print(f"[{seg.start:.2f}s -> {seg.end}s] {seg.text}")
```
----
## 實做 EPD
一般而言會需要一個 VAD Buffer
長度大概 80 到 120 個 Frames
當這個 Buffer 假設有 80% 都是觸發狀態
代表發現聲音的開始端點
----
## 聲音 Buffer
在進入 ASR 之前
通常會有一個 5 秒的 Buffer 用來存聲音訊號
在 EPD 觸發之後,把這個 Buffer 送入 ASR
避免在 EPD 之前有漏字的狀況
----
## EPD 狀態變換
進入 ASR 階段後持續計算 VAD Buffer
如果 Buffer 只剩 20% 是觸發狀態就結束 ASR
所以會有三個狀態:未觸發 > 觸發 > 完成
----
## Demo
完整程式碼放在 [GitHub](https://github.com/penut85420/WhisperDemo) 上
---
# Other
----
## ChatGPT & Mathjax
ChatGPT 解釋 Mathjax
[成功的例子](https://chat.openai.com/share/2e55b9e2-f058-41a2-a86e-4e3501e323ea) | [失敗的例子](https://chat.openai.com/share/774ebb9d-37f5-4237-8712-eb9ce80d020f)
ChatGPT 的 Mathjax 真的強
[Example 1](https://chat.openai.com/share/826a0a6c-81dd-4d2a-90ef-938aeed39771) | [Example 2](
https://chat.openai.com/share/49c67b19-689d-4bda-b58b-78f935ea3044)
----
## VSCode Math Plugin
使用 [Markdown+Math](https://marketplace.visualstudio.com/items?itemName=goessner.mdmath) 插件
可以在 VSCode 裡面渲染 Mathjax 語法
目的是將數學公式放入 [Slides](https://slides.com/) 所以需要設定小括號
```jsonld=
{
"mdmath.delimiters": "brackets"
}
```
----
## Qubby AI
[Qubby AI](https://liff.line.me/2000331789-JpGBrD7B)
蠻歡樂的應用
有山道猴子的 AI 虛擬形象
{"title":"Week 1F - Audio","slideOptions":"{\"transition\":\"slide\"}","description":"地獄貓旅行團第 31 週心得分享","contributors":"[{\"id\":\"c7cbb212-2c41-4dfa-8d85-f8e7fa769bf1\",\"add\":4849,\"del\":746}]"}