2020年1月13日

DeepLearning常見名詞

Deep Learning 神經網路模型的發展大約歷經四個時期:

  1. 1950~1960 基本的感知器,目前公認鼻祖是 1957 年提出 Perceptron 演算法的 Rosenblatt
  2. 1970~1980 發現 multilayer perceptron 多層感知器,有高度非線性函數的能力,甚至有神經網路能解決所有問題的論點
  3. 1990~2000 傳統神經網路沈寂,kernel 方法大行其道,主因是機器運算能力不足,資料量太大,網際網路尚未普及。
  4. 2006年以後,有些技術進步,促成深度學習的神經網路模型的大量應用。廉價平行計算 GPU 出現,網際網路普及,更容易取得大規模的資料。

通常深度學習適合處理資料量大、具備某些資料規則,但決策函數高度非線性的問題。例如圖形辨識、語音辨識、文字產生、自然語言分析、手寫數字辨識等等。

神經網路的四類函數

  1. 組合函數 combination function 輸入層後面的網路中,每一個神經元的功能都是將上一層產生的向量,透過本身的函數產生一個標量值,此標量就是下一個神經元輸入變數。這種在網路中間,將向量映射為標量的函數,就稱為組合函數。常見的組合函數包含線性組合函數與基於歐幾里德距離的函數。

  2. 啟動函數 activation function 大部分的神經元都將一維向量的網路輸入變數,透過某個函數映射為另一個一維向量的數值,這個函數稱為啟動函數,產生的值就稱為啟動狀態。

    除了輸出層以外,啟動狀態的值透過神經的連結,輸入到下一層的一個或多個神經元中。因啟動函數通常是將一個實數域的值映射到有限域,也稱為塌陷函數。

    ex: tanh, logistic 都是將實數域映射到 (-1,1) 或 (0,1) 之間

    啟動函數的主要作用是給隱含層引入非線性。一個只有線性關係隱含層的多層神經網路,不會比一般只包含輸入層與輸出層的兩層神經網路更強大。但加入非線性後,多層神經網路的預測能力就提高很多。

    對反向傳播演算法來說,啟動函數必須可微分,如果該函數是在有限域,效果更好,例如 logistic, tanh, 高斯函數,這些函數又稱為 sigmoid 函數。tanh, arctan 這種包含正負值域的函數,通常收斂速度較快,這是因為 conditioning number 更好。

    隱藏層的啟動函數歷經 sigmoid 到 threshold 的轉變,反映了 deep learning 技術和理論的發展。

    早期認為sigmoid 比 threhold 函數好,因為 threshold 函數的誤差函數是 stepwise constant,一階導數為不存在或是 0,導致無法進行有效的反向傳播演算法計算。sigmoid 是連續可微分的函數,參數一點變化,就會帶來輸出的變化,有助於判斷參數變動是否有利於最終函數的最佳化。而 threshold 的參數微小變化,不影響輸出,所以演算法收斂速度較慢。

    但 1991年 Sepp Hochreiter 發現,sigmoid 有 gradient vanishing 的問題。梯度消失就是梯度(誤差的訊號)隨著隱藏層數的增加,會指數減少。因反向傳播演算法的梯度計算採用鏈式法則,第 n 層需要乘以前面各層的梯度,但由於 sigmoid 的值域在 (-1,1) 或 (0,1) 之間,很多個很小的數相乘後,第n層的梯度就會趨近於 0,造成模型訓練的問題。而 threshold 啟動函數的值域不是 (-1,1),因此沒有這個問題,ex: reLU 的值域是 (0, +inf)。

    另外 Hard Max 這個 threshold 啟動函數: max(0,x) 可在隱藏層加入稀疏性 sparsity,有助於模型的訓練。

    對於輸出層,應該盡量選擇適合變數分佈的啟動函數

    • 對只有 0, 1 取值的雙值因變數,可使用 logistic 函數
    • 對有多個取值的離散因變數,例如 0~9 數字辨識,可使用 softmax (logistic 的自然衍生函數)
    • 對有限值域的連續因變數,可使用 logistic 或 tanh 啟動函數,但需要將因變數的值域伸縮到 logistic/tanh 對應的值域中
    • 如果因變數取值為正,但沒有上限,可使用指數函數
    • 如果因變數沒有有限值域,或雖是有限值域但邊界未知,可使用線性函數

    輸出層的啟動函數,選擇方法跟統計學模型的應用類似,就是統計學廣義線性模型的連結函數 link function 功能。

  3. 誤差函數 error function 監督學習的神經網路都需要一個函數,量測模型輸出值 p 跟真實因變數值 y 的差異,一般稱為誤差。但這個值不能直接用來衡量模型的品質。

    如果有一個完美的模型,其誤差為 0,但一般誤差為偏離0 的絕對值。誤差越趨近 0 越好。誤差函數也稱為損失函數 loss function。

    常用的 loss function:

    • 均方誤差(MSE):\( \frac{1}{n} \sum_{i=1}^{n} ( y^{(i)} - f_𝜃(x^{(i)} ) )^2 \) 通常用在實數值域連續變數的迴歸問題,對於誤差較大的情況給予更多權重。

    • 平均絕對誤差(MAE):\( \frac{1}{n} \sum_{i=1}^{n} | y^{(i)} - p^{i} | \) 應用在迴歸問題,或是時間序列預測問題。每個誤差對總體誤差的貢獻,與其誤差的絕對值成線性比例,MSE 沒有這個特性。

    • 交叉熵損失(cross entropy):也稱為對數損失函數,是針對分類模型的效能比較,依照分類模型是二分類或是多分類,還可分為二分類交叉熵與多分類交叉熵兩種。 \( \sum_{c=1}^{C} \sum_{i=1}^{N} -y_{c,i} log_2(p_{c,i}) \)

      C是類別數,N 是所有的資料數。\( y_{c,i} \) 是binary indicator (0 or 1) from one hot encode (第i筆資料屬於第c類真實類別)。\( p_{c,i} \)是第i筆資料屬於第c類預測出來的機率。

      cross-entropy 就是映射到最可能類別機率的對數,當預測值的分佈跟實際因變數的分佈一致時,交叉熵最小。

  4. 目標函數 object function 在訓練階段直接最小化的函數。神經網路的訓練結果,是在最小化訓練資料的預測值與真實值的誤差。結果可能會發生 overfitting 的狀況。例如模型在訓練資料上表現很好,但在測試資料或真實應用時,表現較差。也就是模型普適化不好。

    一般會用正規化,減少 overfitting 的狀況。這時目標函數為誤差函數與正規函數的和。例如採用 weight decay 方法時,正規函數是權重的平方和,這跟一般 ridge regression 的技巧一樣。如果使用貝氏定理,也可以將權重先驗分佈的對數,作為正則項。如果不使用正則項,目標函數就和總體或平均誤差函數一樣。

批量 Batch

有兩種

  1. 對應到模型訓練方法,就是將所有資料處理完後,一次性更新權重或參數的估計值

  2. 對應到模型訓練中的資料,是指一次輸入模型計算的資料量

批量概念的模型訓練,一般是以下步驟:

  1. 初始化參數
  2. 重複以下步驟 2.1 處理所有資料 2.2 更新參數

遞增演算法的步驟

  1. 初始化參數
  2. 重複以下步驟 2.1 處理一個或一組資料點 2.2 更新參數

差別是批量演算法一次處理所有資料,遞增演算法,處理一或多個資料,就要更新一次參數。

反向傳播演算法中,「處理」 就是計算損失函數的梯度變化曲線。 批量驗算法中,「處理」 是計算平均或總體損失函數的梯度變化曲線 遞增演算法中,損失函數僅計算對應於該觀測值或數個觀測值的梯度變化曲線。

「更新」 是從既有的參數值,減去梯度變化率和學習速率的乘積。

online/offline learning

online learning 的觀測值,處理後就會被丟棄,同時更新參數。永遠是一種遞增演算法。

offline learning 的資料可重複取得,有以下優點

  1. 對任何固定個數的參數,可直接計算出目標函數,很容易驗證模型訓練是否往所需方向前進
  2. 計算精度可達到任意合理的程度
  3. 可使用各種不同的演算法,避免局部最佳化的情況
  4. 可採用訓練、驗證、測試三分法,針對模型的普適化進行驗證
  5. 可計算預測值及其信賴區間

online learning 不儲存資料,無法重複取得資料,因此無法在訓練集上計算 loss function,無法在驗證集上計算誤差。所以online learning 演算法比較不穩定。

bias 偏移值

通常在計算網路輸入時,會加入一個 bias 偏移值。如果是線性輸出神經元,bias 就是線性迴歸中的截距。

跟截距的作用類似,bias 視為一個由特殊神經元引出的連結權重,這是因為它通常連結到一個固定單位值的偏移神經元。例如在多層感知器 MLP 神經網路中,某一個神經元的輸入參數為 N 維,這個神經元在高維空間根據參數畫出一個超平面,一邊是正值,一邊是負值。參數決定了超平面在輸入空間的相對位置,如果沒有 bias,超平面就需要通過原點,這就限制了平面的位置。

每個隱藏層和輸出層的神經元都有自己的 bias,但如果輸入資料已經等比例轉換到一個有限值域,例如 [0,1]區間,那麼第一個隱藏層的神經元設定 bias 後,後面任何層內跟這個神經原有連結的其他神經元,就不需要再設定 bias 了。

標準化資料

有三種常見的標準化

  1. rescaling 加上一個向量,或減去一個常數,再乘上或除以一個常數。例如將華氏溫度轉換為攝氏溫度。

  2. normalization 將一個向量除以其範數,例如採用歐幾里得距離,則使用向量的變異量數作為範數來正規化向量。deep learning 通常用全距作為範數,也就是向量減去最小值,然後除以全距,可讓數值落於 0~1 之間

  3. standardization 將一個向量移除其位置與規模的度量。例如遵循常態分佈的向量,可減去平均值,除以變異數,來標準化資料。可得到一個遵守標準常態分佈的向量。

在 deep learning 要視情況決定要不要做標準化,一般來說,如果啟動函數的值域在 0~1 之間,那麼正規化資料到 [0,1] 比較合理,另外正規化資料,能讓計算過程穩定,特別是資料值域範圍有較大差別的時候。

梯度下降演算法

最佳化決策函數時,通常是針對一個誤差的度量(例如誤差的平方),求得一系列參數,然後最小化這個誤差度量的值來進行。目前一般採用 gradient descent method 梯度下降演算法。

該方法類似遊客在不知名的高山要儘快安全到達谷底,他必須在東西、南北兩個軸向進行選擇,以確保下山路徑又快又安全。如果把軸向想成目標函數的兩個維度,那麼該怎麼取得最佳路徑呢?

因為在山頂不知道路況,有可能因為初始化參數不佳,造成只能得到局部最佳解的狀況。梯度下降法是一種短是的方法,只靠一個傾斜角,看那個方向比較陡,就往該方向下滑一段距離。

通常會用隨機梯度下降法 stochastic gradient descent,這是針對每個觀測值執行梯度下降的最佳化演算,原本的方法稱為 batch 或 offline 演算法,新的方法稱為 incremental 或 online 演算法,因為參數估計值會隨著觀測值的變化而更新。

目前常見是使用一階導函數的梯度下降法,也有基於二階導函數的演算法,稱為牛頓法。這種方法相當於遊客帶了一個高度計,滑下去後,就可查閱結果,如果比原來高,就退回原來的地方,重新跳一小步。

假設有一個函數 f 有兩個變數 \(x_0, x_1\) ,則 f 的梯度法就是

\( x_0' = x_0 - 𝜂 \frac{𝜕f}{𝜕x_0} \)

\( x_1' = x_1 - 𝜂 \frac{𝜕f}{𝜕x_1} \)

其中 𝜂 是學習率,就是一次學習中,要往前增加多少步進值,在訓練前,要先決定 𝜂 是 0.1 或 0.001 或某一個數值,這個值太大,可能會發生找不到最佳解的狀況,太小,則會發生學習速度太慢 (loss rate 下降太慢)的狀況。

因此 𝜂 學習率這種參數稱為 hyperparameter,這跟 weight 權重、bias 不同,這是一個根據經驗設定與調整出來的一個人工設定的參數。

誤差反向傳播演算法

如果神經網路只有一層,只要反覆運用這個方法到 loss function,就可依照公式更新參數,直到收斂就好了。權重參數的 loss function 梯度,可以根據數值微分計算而來。微分的計算很簡單,但計算量大比較花時間。

但如果輸入層跟輸出層之間,有很多隱含層,就需要一個高效率的演算法,減少計算量。為了快速估計深度神經網路的權重值,backpropagation 就是這種演算法,可有效率地計算微分。以 computational graph 來理解這個演算法。

ref: Computational Graph

ref: DL3-Computational Graph & Backpropagation

ref: computational graph 李弘毅

node: 代表 variable (scalar, vector, tensor)

edge: 代表 operation (function)

\( y=f(g(h(x))) \) 可拆解為三個合成函數 \( u=h(x), v=g(u), y=f(v) \)

如果某個節點有兩個 input,可寫成 \( a=f(b,c) \),就是 b,c 兩個 node 都指向 a


這是 Computational Graph 的一個例子,要由下往上看


因為 computational graph 的概念就是合成函數,而合成函數在計算微分,可以用 chain rule。

case 1 的 \( \frac{dz}{dx} = \frac{dz}{dy}*\frac{dy}{dx} \) note: \( z=h(y) z=h(g(x)) \)

根據 \( \frac{𝜕e}{𝜕b}\) 的公式,\(c=a+b, d=b+1, e=c*d\),利用 computational graph,由下往上,計算每一個箭頭的偏微分,在合併用在原本的公式中

舉例 a=3, b=2,套用在剛剛的計算過程中

如果由 b=1 開始,往上計算可得到 \( \frac{𝜕e}{𝜕b}=8\) 。 可發現跟剛剛一樣,有用到 \( \frac{𝜕e}{𝜕c}=3, \frac{𝜕e}{𝜕d}=5, \frac{𝜕c}{𝜕a}=1, \frac{𝜕c}{𝜕b}=1, \frac{𝜕d}{𝜕b}=1\) 這些偏微分的結果

如果由 a=1 開始,往上計算可得到 \( \frac{𝜕e}{𝜕a}=3\) \( \frac{𝜕e}{𝜕b}=8\) ,跟剛剛一樣,有用到 \( \frac{𝜕e}{𝜕c}=3, \frac{𝜕e}{𝜕d}=5, \frac{𝜕c}{𝜕a}=1, \frac{𝜕c}{𝜕b}=1, \frac{𝜕d}{𝜕b}=1\) 這些偏微分的結果

\(c=a+b, d=b+1, e=c*d\),一樣使用 跟剛剛一樣,有用到 \( \frac{𝜕e}{𝜕c}=3, \frac{𝜕e}{𝜕d}=5, \frac{𝜕c}{𝜕a}=1, \frac{𝜕c}{𝜕b}=1, \frac{𝜕d}{𝜕b}=1\) 這些偏微分的結果, 反方向填寫,得到 \( \frac{𝜕e}{𝜕a}=3, \frac{𝜕e}{𝜕b}=8\)

ref: https://web.cs.hacettepe.edu.tr/~aykut/classes/spring2016/bbm406/slides/l12-backpropagation.pdf

首先有一個合成函數 \(f(x,y,z)\),當 \( x=-2, y=5, z=-4 \) 時,我們想要得到 \( \frac{𝜕f}{𝜕x}, \frac{𝜕f}{𝜕y}, \frac{𝜕f}{𝜕z} \) 的結果。一開始,就先用 computational graph 描述題目

在最右邊,寫上 \(\frac{𝜕f}{𝜕f}=1\)

因為 \( f=qz \),而 \( \frac{𝜕f}{𝜕z} = q\),因此就等於 3

因為 \( f=qz \),而 \( \frac{𝜕f}{𝜕q} = z\),因此就等於 -4

因為 \( q=x+y \),而 \( \frac{𝜕f}{𝜕y} = \frac{𝜕f}{𝜕q} \frac{𝜕q}{𝜕y} = -4 * 1 = -4 \),因此就等於 -4

因為 \( q=x+y \),而 \( \frac{𝜕f}{𝜕x} = \frac{𝜕f}{𝜕q} \frac{𝜕q}{𝜕x} = -4 * 1 = -4 \),因此就等於 -4

References

python 深度學習實作 keras 快速上手

深度學習:使用激勵函數的目的、如何選擇激勵函數 Deep Learning : the role of the activation function

生物神經元的工作原理對深度學習神經元的啟發

deep learning 用python進行深度學習的基礎理論實作

2020年1月6日

Google Voice Kit v1

根據這兩個網址的說明,安裝 Google Voice Kit V1

Google Voice Kit V1

一口氣將 Voice Kit 連上 Google Cloud Platform — 實作篇

note: 注意變壓器必須要輸出 5V 2.5A,電流不夠會讓 RPi 一直 reboot

Voice HAT (Hardware Attached on Top)

GPIO pins used by Voice HAT

傳感器常用的 I2C, UART(14,15 還特意分出來了), SPI 都沒有佔用。 其餘的 GPIO 分為兩組並配備了電源接口,可以直接用作 GPIO,也可以控制外部設備:

  1. Servo0-Servo5:5v/25mA,小電流的 Servo 適合連接類似 LED 之類的設備。
  2. Dirver0-Driver4:5v/500mA,可以連接功率更大的設備 (例如 小車的馬達),+/- 極來自在板子左下角的外接電源。可以參考這個接法:https://www.raspberrypi.org/magpi/motor-aiy-voice-pi/

使用 Speech Recognition API & gTTS 套件

  • 用 Speech Recognition API 辨識中/英文

  • 用 gTTS 套件說中文

    gTTS: a Python library and CLI tool to interface with Google Translate's text-to-speech API,這是用 python 透過 google translate 轉換為語音的套件

  • 沒有智能語義 AI,不是 Google assistent

需要產生服務帳戶金鑰

由 Google Cloud Platform GCP 產生服務帳戶金鑰,並存放到 /home/pi/cloud_speech.json

測試程式 cloudspeech_demo.py

安裝 gTTS 相關套件

sudo python3 -m pip install gTTS
sudo python3 -m pip install pydub
sudo apt install ffmpeg

修改後的 cloudspeech_demo.py

#!/usr/bin/env python3
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A demo of the Google CloudSpeech recognizer."""
import argparse
import locale
import logging

from aiy.board import Board, Led
from aiy.cloudspeech import CloudSpeechClient
from aiy.voice import audio
from gtts import gTTS
from pydub import AudioSegment


def get_hints(language_code):
    if language_code.startswith('en_'):
        return ('turn on the light',
                'turn off the light',
                'blink the light',
                'goodbye')
    return None

def locale_language():
    language, _ = locale.getdefaultlocale()
    return language

def say(text, lang=None):
    if lang == None:
        tts = gTTS(text)
    else:
        tts = gTTS(text, lang)
     # 把文字變成gtts內建的物件
    tts.save('output.mp3') # 把得到的語音存成 output.mp3
    sound = AudioSegment.from_mp3('output.mp3') # 把 output.mp3 讀出
    sound.export('output.wav', format='wav') # 轉存成 output.wav
    audio.play_wav('output.wav') # 把 wav 用 VoiceKit 播出來

def main():
    # say('test')

    logging.basicConfig(level=logging.DEBUG)

    parser = argparse.ArgumentParser(description='Assistant service example.')
    parser.add_argument('--language', default=locale_language())
    args = parser.parse_args()

    logging.info('Initializing for language %s...', args.language)
    hints = get_hints(args.language)
    client = CloudSpeechClient()
    with Board() as board:
        while True:
            if hints:
                logging.info('Say something, e.g. %s.' % ', '.join(hints))
            else:
                logging.info('Say something.')
            text = client.recognize(language_code=args.language,
                                    hint_phrases=hints)
            if text is None:
                logging.info('You said nothing.')
                continue

            logging.info('You said: "%s"' % text)
            text = text.lower()
            if 'turn on the light' in text:
                board.led.state = Led.ON
                say('light is on')
            elif 'turn off the light' in text:
                board.led.state = Led.OFF
                say('light is off')
            elif 'blink the light' in text:
                board.led.state = Led.BLINK
                say('light is blinked')
            elif '開燈' in text:
                board.led.state = Led.ON
                say('燈開好了', 'zh-TW')
            elif '關燈' in text:
                board.led.state = Led.OFF
                say('燈關了', 'zh-TW')
            elif '閃燈' in text:
                board.led.state = Led.BLINK
                say('閃燈中', 'zh-TW')
            elif 'bye' in text:
                say('bye')
                break
            elif '結束' in text:
                say('再見', 'zh-TW')
                break
            elif 'goodbye' in text:
                say('bye')
                break

if __name__ == '__main__':
    main()

調整音量的指令

alsamixer

note:

pip3 install gTTS 出現 Error

Exception:
Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.19.1-py2.py3-none-any.whl/urllib3/connectionpool.py", line 594, in urlopen
    chunked=chunked)
  File "/usr/share/python-wheels/urllib3-1.19.1-py2.py3-none-any.whl/urllib3/connectionpool.py", line 391, in _make_request
    six.raise_from(e, None)
  File "<string>", line 2, in raise_from
  File "/usr/share/python-wheels/urllib3-1.19.1-py2.py3-none-any.whl/urllib3/connectionpool.py", line 387, in _make_request
    httplib_response = conn.getresponse()
  File "/usr/lib/python3.5/http/client.py", line 1198, in getresponse
    response.begin()
  File "/usr/lib/python3.5/http/client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python3.5/http/client.py", line 266, in _read_status
    raise RemoteDisconnected("Remote end closed connection without"
http.client.RemoteDisconnected: Remote end closed connection without response

During handling of the above exception, another exception occurred:

......
TypeError: unsupported operand type(s) for -=: 'Retry' and 'int'

解決方式:更新 requests

sudo python3 -m pip install --user --upgrade requests

解決方法:改用這個指令安裝

sudo python3 -m pip install gTTS

使用 Google Assistant Service API

需要產生 OAuth 用戶端 ID

note 設定過程中,會綁定到某一個帳號:

charley@maxkit.com.tw  google assistent auth code
4/qQGwcp38dePn7QQABHiXJwgS2Hhs6Jz6hG3sVX9l2Y6WIoUXgt5bFVo

存放到 /home/pi/assistant.json

程式使用內建 pico2wave 來合成語音,故不支援中文

demo 程式

  • ~/AIY-projects-python/src/examples/voice/assistantlibrarydemo.py

    ​ 要說 Hey Google 然後再問問題,只支援英文

  • ~/AIY-projects-python/src/examples/voice/assistantlibrarywithbuttondemo.py

    ​ 要說 Hey Google 或是按下按鈕,然後再問問題,只支援英文

  • assistantgrpcdemo.py

    ~/AIY-projects-python/src/examples/voice/
    
    ./assistant_grpc_demo.py

將 assitant demo 設定為開機自動啟動

ref: GOOGLE VOICE KIT AUTOSTART

sudo vim /etc/systemd/system/assistant.service

[Unit]
Description=Google Assistant
Wants=network-online.target
After=network-online.target
Wants=systemd-timesyncd.service
After=systemd-timesyncd.service

[Service]
Environment=DISPLAY=:0
Type=simple
ExecStart=/home/pi/AIY-projects-python/src/examples/voice/assistant_library_with_button_demo.py
Restart=on-failure
User=pi
Group=pi
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=google_assistant

[Install]
WantedBy=multi-user.target
sudo chmod 755 /etc/systemd/system/assistant.service

sudo systemctl daemon-reload
sudo systemctl enable assistant.service
sudo service assistant start

查閱 log

sudo journalctl -u assistant -f

客製化 hotword

ref: 語音喚醒技術的原理是什麼?

ref: 語音喚醒

語音喚醒在學術上被稱為keyword spotting(簡稱KWS),吳老師給它做了一個定義:在連續語流中實時檢測出說話人特定片段。

這裡要注意,檢測的「實時性」是一個關鍵點,語音喚醒的目的就是將設備從休眠狀態激活至運行狀態,所以喚醒詞說出之後,能立刻被檢測出來,用戶的體驗才會更好。

那麼,該怎樣評價語音喚醒的效果呢?通行的指標有四個方面,即喚醒率、誤喚醒、響應時間和功耗水平

➤喚醒率,指用戶交互的成功率,專業術語為召回率,即recall。

➤誤喚醒,用戶未進行交互而設備被喚醒的概率,一般按天計算,如最多一天一次。

➤響應時間,指從用戶說完喚醒詞後,到設備給出反饋的時間差。

➤功耗水平,即喚醒系統的耗電情況。很多智能設備是通過電池供電,需要滿足長時續航,對功耗水平就比較在意。

喚醒可以看成是一種小資源的關鍵詞檢索任務,其中小資源是指計算資源比較小和空間存儲資源比較小,因此它的系統框架跟關鍵詞檢索的系統會有一定的區別,目前常用的系統框架主要有Keyword/Filler Hidden Markov Model System和Deep KWS System兩種。

陳果果 kitt.ai 開發 DNN based snowboy 提供不同 OS 的 library,可自訂 hotword,百度在 2017 全資收購。

custom-hotword-for-aiy-voicekit

# 安裝 libatlas-base-dev
sudo apt-get install libatlas-base-dev

cd ~/AIY-voice-kit-python

src/examples/voice/assistant_grpc_demo_snowboy.py --language en-US --model src/mod/resources/alexa/alexa_02092017.umdl
# hotword: alexa

只有 alexa 可以用,其他的自訂 hotword,都沒辦法偵測到


note: 安裝 VNC

ref: [基礎] 以 VNC 和 Raspberry Pi 連線

ref: 基礎篇 - vnc連線

sudo apt-get install tightvncserver

vncserver
# 設定密碼

在 vnc viewer 使用 192.168.1.175:5901 連線

Reference

AIY project github

Custom Hotword for AIY Voice Kit

lattepanda-使用google-assistant玩互動語音助理

2019年12月30日

MFCC 梅爾倒頻譜係數

MFCC是Mel-Frequency Cepstral Coefficients 梅爾頻率倒譜係數的縮寫,它是在1980年由 S.B. Davis和 Paul Mermelstein 提出來的,在語音辨識(Speech Recognition)和語者辨識(Speaker Recognition)方面,最常用到的語音特徵就是「梅爾倒頻譜係數」,此參數考慮到人耳對不同頻率的感受程度,因此特別適合用在語音辨識。

MFCC特徵提取包含兩個關鍵步驟:梅爾頻率分析和倒譜分析

在訊號處理(Signal Processing)中,梅爾倒頻譜(Mel-Frequency Cepstrum, MFC)係一個可用來代表短期音訊的頻譜,其原理根基於以非線性的梅爾刻度(mel scale)表示的對數頻譜(spectrum)及其線性餘弦轉換(linear cosine transform)之上。

梅爾倒頻譜係數 (Mel-Frequency Cepstral Coefficients, MFCC)是一組用來建立梅爾倒頻譜的關鍵係數。由音樂訊號當中的片段,我們可以得到一組足以代表此音樂訊號之倒頻譜,而梅爾倒頻譜係數即是從這個倒頻譜中推得的倒頻譜(也就是頻譜的頻譜)。與一般的倒頻譜不同 ,梅爾倒頻譜最大的特色在於,於梅爾倒頻譜上的頻帶是均勻分布於梅爾刻度上的,也就是說,這樣的頻帶會較一般我們所看到、線性的倒頻譜表示方法,和人類非線性的聽覺系統(audio system)更為接近。在音訊壓縮的技術中,常常使用梅爾倒頻譜來處理。

在語音識別(Speech Recognition)和話者識別(Speaker Recognition)方面,最常用到的語音特徵就是梅爾倒譜系數(Mel-scale Frequency Cepstral Coefficients,簡稱MFCC)。

人類聽覺特性

人耳對不同強度、不同頻率聲音的聽覺範圍稱為聲域。在人耳的聲域範圍內,聲音聽覺心理的主觀感受主要有響度、音高、音色等特徵和掩蔽效應、高頻定位等特性。其中響度、音高、音色可以在主觀上用來描述具有振幅、頻率和相位三個物理量的任何複雜的聲音,故又稱為聲音「三要素」;而在多種音源場合,人耳掩蔽效應等特性更重要,它是心理聲學的基礎。

  1. 響度

    又稱聲強或音量,它表示的是聲音能量的強弱程度,主要取決於聲波振幅的大小。聲音的響度一般用聲壓(達因/平方釐米)或聲強(瓦特/平方釐米)來計量,聲壓的單位為帕(Pa),它與基準聲壓比值的對數值稱為聲壓級,單位是分貝(dB)。對於響度的心理感受,一般用單位宋(Sone)來度量,並定義lkHz、40dB的純音的響度為1宋。響度的相對量稱為響度級,它表示的是某響度與基準響度比值的對數值,單位為口方(phon),即當人耳感到某聲音與1kHz單一頻率的純音同樣響時,該聲音聲壓級的分貝數即為其響度級。

    正常人聽覺的強度範圍為0dB—140dB(也有人認為是-5dB—130dB)。固然,超出人耳的可聽頻率範圍(即頻域)的聲音,即使響度再大,人耳也聽不出來(即響度為零)。在人耳的可聽頻域內,若聲音弱到或強到一定程度,人耳同樣是聽不到的。當聲音減弱到人耳剛剛可以聽見時,此時的聲音強度稱為「聽閾」。一般以1kHz純音為準進行測量,人耳剛能聽到的聲壓為0dB(通常大於0.3dB即有感受)、聲強為10-16W/cm2 時的響度級定為0口方。而當聲音增強到使人耳感到疼痛時,這個閾值稱為「痛閾」。仍以1kHz純音為準來進行測量,使 人耳感到疼痛時的聲壓級約達到140dB左右。

    人耳對3kHz—5kHz聲音最敏感,幅度很小的聲音信號都能被人耳聽到,而在低頻區(如小於800Hz)和高頻區(如大於5kHz)人耳對聲音的靈敏度要低得多。響度級較小時,高、低頻聲音靈敏度降低較明顯,而低頻段比高頻段靈敏度降低更加劇烈,一般應特別重視加強低頻音量。通常200Hz--3kHz語音聲壓級以60dB—70dB為宜,頻率範圍較寬的音樂聲壓以80dB—90dB最佳。

  2. 音高

    也稱音調,表示人耳對聲音調子高低的主觀感受。客觀上音高大小主要取決於聲波基頻的高低,頻率高則音調高,反之則低,單位用赫茲(Hz)表示。主觀感覺的音高單位是「美」,通常定義響度為40方的1kHz純音的音高為1000美。赫茲與「美」同樣是表示音高的兩個不同概念而又有聯繫的單位。

    人耳對響度的感覺有一個從聞閾到痛閾的範圍。人耳對頻率的感覺同樣有一個從最低可聽頻率20Hz到最高可聽頻率別20kHz的範圍。響度的測量是以1kHz純音為基準,同樣,音高的測量是以40dB聲強的純音為基準。

    實驗證明,音高與頻率之間的變化並非線性關係,除了頻率之外,音高還與聲音的響度及波形有關。音高的變化與兩個頻率相對變化的對數成正比。不管原來頻率多少,只要兩個40dB的純音頻率都增加1個倍頻程(即1倍),人耳感受到的音高變化則相同。在音樂聲學中,音高的連續變化稱為滑音,1個倍頻程相當於樂音提高了一個八度音階。根據人耳對音高的實際感受,人的語音頻率範圍可放寬到80Hz--12kHz,樂音較寬,效果音則更寬。

  3. 音色

    又稱音品,由聲音波形的諧波頻譜和包絡決定。聲音波形的基頻所產生的聽得最清楚的音稱為基音,各次諧波的微小振動所產生的聲音稱泛音。單一頻率的音稱為純音,具有諧波的音稱為複音。每個基音都有固有的頻率和不同響度的泛音,藉此可以區別其它具有相同響度和音調的聲音。

人耳的掩蔽效應

一個較弱的聲音(被掩蔽音)的聽覺感受被另一個較強的聲音(掩蔽音)影響的現象稱為人耳的「掩蔽效應」。被掩蔽音單獨存在時的聽閾分貝值,或者說在安靜環境中能被人耳聽到的純音的最小值稱為絕對聞閾。實驗表明,3kHz—5kHz絕對聞閾值最小,即人耳對它的微弱聲音最敏感;而在低頻和高頻區絕對聞閾值要大得多。在800Hz--1500Hz範圍內聞閾隨頻率變化最不顯著,即在這個範圍內語言可儲度最高。在掩蔽情況下,提高被掩蔽弱音的強度,使人耳能夠聽見時的聞閾稱為掩蔽聞閾(或稱掩蔽門限),被掩蔽弱音必須提高的分貝值稱為掩蔽量(或稱閾移)。

純音對純音、噪音對純音的掩蔽效應結論如下:

  • 純音間的掩蔽

    • 對處於中等強度時的純音最有效的掩蔽是出現在它的頻率附近。
    • 低頻的純音可以有效地掩蔽高頻的純音,而反過來則作用很小。
  • 噪音對純音的掩蔽噪音是由多種純音組成,具有無限寬的頻譜

若掩蔽聲為寬頻噪聲,被掩蔽聲為純音,則它產生的掩蔽門限在低頻段一般高於噪聲功率譜密度17dB,且較平坦;超過500Hz時大約每十倍頻程增大10dB。若掩蔽聲為窄帶噪聲,被掩蔽聲為純音,則情況較複雜。其中位於被掩蔽音附近的由純音份量組成的窄帶噪聲即臨界頻帶的掩蔽作用最明顯。

當我們改變窄頻帶聲音刺激(narrowband sound stimulus)時,其聲音成分若跨越某一頻率,則聽覺上會感到有差異,而在一頻率範圍內,則感覺不到差異,這個頻率範圍稱臨界頻帶(Critical Band)

  • 在人類聽覺範圍內 20Hz--16kHz範圍,可以分成24個臨界頻帶

根據人耳聽覺機理的研究發現,人耳對不同頻率的聲波有不同的聽覺敏感度。從200Hz到5000Hz的語音訊號對語音的清晰度影響對大。兩個響度不等的聲音作用於人耳時,則響度較高的頻率成分的存在會影響到對響度較低的頻率成分的感受,使其變得不易察覺,這種現象稱為掩蔽效應。當某個純音位於掩蔽聲的臨界頻帶之外時,掩蔽效應仍然存在。


掩蔽類型

  • 低頻的聲音傾向於遮蔽高頻的聲音

​ 掩蔽聲與被掩蔽聲同時作用時發生掩蔽效應,又稱同時掩蔽。這時,掩蔽聲在掩蔽效應發生期間一直起作用,是一種較強的掩蔽效應。通常,頻域中的一個強音會掩蔽與之同時發聲的附近的弱音,弱音離強音越近,一般越容易被掩蔽;反之,離強音較遠的弱音不容易被掩蔽。例如,—個1000Hz的音比另一個900Hz的音高18dB,則900Hz的音將被1000Hz的音掩蔽。而若1000Hz的音比離它較遠的另一個1800Hz的音高18dB,則這兩個音將同時被人耳聽到。若要讓1800Hz的音聽不到,則1000Hz的音要比1800Hz的音高45dB。一般來說,低頻的音容易掩蔽高頻的音;在距離強音較遠處,絕對聞閾比該強音所引起的掩蔽閾值高,這時,噪聲的掩蔽閾值應取絕對聞閾。

  • 聲音在聽覺器官中,傳遞時間延遲所造成的遮蔽現象,稱時間遮蔽

由於頻率較低的聲音在內耳蝸基底膜上行波傳遞的距離大於頻率較高的聲音,故一般來說,低音容易掩蔽高音,而高音掩蔽低音較困難。在低頻處的聲音掩蔽的臨界頻寬較高頻要小。

時域掩蔽是指掩蔽效應發生在掩蔽聲與被掩蔽聲不同時出現時,又稱異時掩蔽。異時掩蔽又分為導前掩蔽和滯後掩蔽。若掩蔽聲音出現之前的一段時間內發生掩蔽效應,則稱為導前掩蔽;否則稱為滯後掩蔽。產生時域掩蔽的主要原因是人的大腦處理信息需要花費一定的時間,異時掩蔽也隨著時間的推移很快會衰減,是一種弱掩蔽效應。一般情況下,導前掩蔽只有3ms—20ms,而滯後掩蔽卻可以持續50ms—100ms。

所以,人們從低頻到高頻這一段頻帶內按臨界頻寬的大小由密到疏安排一組帶通濾波器,對輸入訊號進行濾波。將每個帶通濾波器輸出的訊號能量作為訊號的基本特徵,對此特徵經過進一步處理後就可以作為語音的輸入特徵。

梅爾刻度是一種基於人耳對等距的音高(pitch)變化的感官判斷而定的非線性頻率刻度。當在梅爾刻度上面上是均勻分度的話,對於的赫茲之間的距離將會越來越大。梅爾刻度的濾波器組在低頻部分的解析度高,跟人耳的聽覺特性是相符的,這也是梅爾刻度的物理意義所在。

由於這種特徵不依賴於訊號的性質,對輸入訊號不做任何的假設和限制,又利用了聽覺模型的研究成果。因此,這種引數比基於聲道模型的LPCC相比具有更好的魯邦性,更符合人耳的聽覺特性,且信噪比降低時仍然具有較好的識別效能。

梅爾刻度與頻率的關係可用下式近似表示, f 為頻率,單位為 Hz。

\(Mel(f) = 2595 * log(1 + \frac{f}{700}) = 1125*ln(1+\frac{f}{700})\)

MFCC 的計算過程

  1. 預強調(Pre-emphasis):將語音訊號 s(n) 通過一個高通濾波器:\(H(z)=1-a*z^{-1}\) 其中 a 介於 0.9 和 1.0 之間。若以時域的運算式來表示,預強調後的訊號 \(s_2(n)\) 為 \(s_2(n) = s(n) - a*s(n-1)\) 。這個處理目的就是為了消除發聲過程中聲帶和嘴唇的效應,來補償語音信號受到發音系統所壓抑的高頻部分。(另一種說法則是要突顯在高頻的共振峰。)

    經過了預強調之後,聲音變的比較尖銳清脆,但是音量也變小了

  2. 音框化(Frame blocking):先將 N 個取樣點集合成一個觀測單位,稱為音框(Frame),通常 N 的值是 256 或 512,涵蓋的時間約為 20~30 ms 左右。為了避免相鄰兩音框的變化過大,所以我們會讓兩相鄰因框之間有一段重疊區域,此重疊區域包含了 M 個取樣點,通常 M 的值約是 N 的一半或 1/3。通常語音辨識所用的音訊的取樣頻率為 8 KHz或 16 KHz,以 8 KHz 來說,若音框長度為 256 個取樣點,則對應的時間長度是 256/8000*1000 = 32 ms。

  3. 漢明窗(Hamming window):將每一個音框乘上漢明窗,以增加音框左端和右端的連續性(請見下一個步驟的說明)。假設音框化的訊號為 \(S(n), n = 0,…N-1\)。那麼乘上漢明窗後為 \(S'(n) = S(n)*W(n)\),此 W(n) 形式如下:

    \(W(n, a) = (1 - a) - acos(2pn/(N-1)),0≦n≦N-1\)

    不同的 a 值會產生不同的漢明窗

    一般都取 a = 0.46

  4. 快速傅利葉轉換(Fast Fourier Transform, or FFT):由於訊號在時域(Time domain)上的變化通常很難看出訊號的特性,所以通常將它轉換成頻域(Frequency domain)上的能量分佈來觀察,不同的能量分佈,就能代表不同語音的特性。所以在乘上漢明窗後,每個音框還必需再經過 FFT 以得到在頻譜上的能量分佈。

    乘上漢明窗的主要目的,是要加強音框左端和右端的連續性,這是因為在進行 FFT 時,都是假設一個音框內的訊號是代表一個週期性訊號,如果這個週期性不存在,FFT 會為了要符合左右端不連續的變化,而產生一些不存在原訊號的能量分佈,造成分析上的誤差。當然,如果我們在取音框時,能夠使音框中的訊號就已經包含基本週期的整數倍,這時候的音框左右端就會是連續的,那就可以不需要乘上漢明窗了。但是在實作上,由於基本週期的計算會需要額外的時間,而且也容易算錯,因此我們都用漢明窗來達到類似的效果。

  5. 三角帶通濾波器(Triangular Bandpass Filters):將能量頻譜能量乘以一組 20 個三角帶通濾波器,求得每一個濾波器輸出的對數能量(Log Energy)。必須注意的是:這 20 個三角帶通濾波器在「梅爾頻率」(Mel Frequency)上是平均分佈的,而梅爾頻率和一般頻率 f 的關係式如下:

    \(Mel(f) = 2595 * log(1 + \frac{f}{700}) = 1125*ln(1+\frac{f}{700})\)

    梅爾頻率代表一般人耳對於頻率的感受度,由此也可以看出人耳對於頻率 f 的感受是呈對數變化的。

    • 在低頻部分,人耳感受是比較敏銳
    • 在高頻部分,人耳的感受就會越來越粗糙

    三角帶通濾波器有兩個主要目的:

    • 對頻譜進行平滑化,並消除諧波的作用,突顯原先語音的共振峰。(因此一段語音的音調或音高,是不會呈現在 MFCC 參數內,換句話說,以 MFCC 為特徵的語音辨識系統,並不會受到輸入語音的音調不同而有所影響。)
    • 降低資料量
  6. 離散餘弦轉換(Discrete cosine transform, or DCT):將上述的 20 個對數能量 Ek帶入離散餘弦轉換,求出 L 階的 Mel-scale Cepstrum 參數,這裡 L 通常取 12。

    離散餘弦轉換公式如下:\(C_m=\sum_{k=1}^{N}cos[m*(k-0.5)*p/N]*E_k, m=1,2, ..., L\) 其中 \(E_k\) 是由前一個步驟所算出來的三角濾波器和頻譜能量的內積值,N 是三角濾波器的個數。由於之前作了 FFT,所以採用 DCT 轉換是期望能轉回類似 Time Domain 的情況來看,又稱 Quefrency Domain,其實也就是 Cepstrum。又因為之前採用 Mel- Frequency 來轉換至梅爾頻率,所以才稱之Mel-scale Cepstrum。

  7. 對數能量(Log energy):一個音框的音量(即能量),也是語音的重要特徵,而且非常容易計算。因此我們通常再加上一個音框的對數能量(定義為一個音框內訊號的平方和,再取以 10 為底的對數值,再乘以 10),使得每一個音框基本的語音特徵就有 13 維,包含了 1 個對數能量和 12 個倒頻譜參數。(若要加入其他語音特徵以測試辨識率,也可以在此階段加入,這些常用的其他語音特徵,包含音高、過零率、共振峰等。)

  8. 差量倒頻譜參數(Delta cepstrum):雖然已經求出 13 個特徵參數,然而在實際應用於語音辨識時,我們通常會再加上差量倒頻譜參數,以顯示倒頻譜參數對時間的變化。它的意義為倒頻譜參數相對於時間的斜率,也就是代表倒頻譜參數在時間上的動態變化,公式如下:

    \(△C_m(t) = \frac{𝜕 C_m(t)}{𝜕t} = [\sum_{t=-M}^{M}C_m(t+t)t] / [\sum_{t=-M}^{M}t^2] \)

    這裡 M 的值一般是取 2 或 3。因此,如果加上差量運算,就會產生 26 維的特徵向量;如果再加上差差量運算,就會產生 39 維的特徵向量。

    一般在 PC 上進行的語音辨識,就是使用 39 維的特徵向量。

References

梅爾倒頻譜 wiki

語音特徵引數MFCC提取過程詳解

聲學特徵提取:梅爾頻率倒譜係數MFCC

Kaldi的MFCC特徵提取代碼分析

梅爾倒頻譜係數.ppt

聲音聽覺理論概述

chap11 speaker identification

Audio Signal Processing and Recognition (音訊處理與辨識) Roger Jang (張智星)

MFCC

語音處理中MFCC(Mel頻率倒譜系數)對應的物理含義是什麼?它計算出的那幾個系數能反映什麼樣特徵?

語音特徵參數MFCC提取過程詳解

聲學特徵(二) MFCC特徵原理

Day 25:自動語音識別(Automatic Speech Recognition) -- 觀念與實踐

Building a Dead Simple Speech Recognition Engine using ConvNet in Keras