iT邦幫忙

2021 iThome 鐵人賽

DAY 5
2
AI & Data

AI Voice Conversion系列 第 5

【Day5】從頻域到 wave 的轉換,淺談虛數可以拿來 Train Model 嗎?

  • 分享至 

  • xImage
  •  

在頻域裡面遭遇虛數

經過前面 4 篇的介紹我們已經知道如何萃取出聲音的特徵了,我們用來訓練的資料,都是在頻域裡面的資料,所以之後的模型勢必然預測出來的會是個頻譜。

雖然也是有人直接用 wave 來訓練,但目前我覺得比較成功的案例大概是 waveGan 系列

那我們該如何把頻譜轉回 wave 呢 ? 在那之前我們先看看我們之前做了什麼事。

不就是個傅立葉轉換嗎 ?

沒錯,我們確實是做了傅立葉轉換,但出來的結果是一個複數,所以我們取了 abs。

我就是要反其道而行,我今天就是要用這個複數來訓練 model 拉!

確實也有人在做這方面的研究,但這部分遇到的困難就是,即便你讓 weight 跟 bias 也變成了複數的型態,在遇到激活函數的時候(為了讓 Backpropagation 起作用),根據劉維定理 這些有界的激活函數在複數平面上是常數,也就是說它們是線性的。所以當他們在複數平面上的時候就會有奇異點(不可微分的點),造成函數往無窮大那頭爆炸。

那我設計一個超屌激活函數讓它不要爆炸不就好了?

是這樣子沒錯,但首先你會先設計到瘋掉,然後還是無法避免的讓它在某些點爆炸,接著你會設定一些條件讓它可以指定搜索某部分的空間就好,來防止它爆炸。

有人有做到上面的程度,但目前只在 FCN 上成功

最後,光是設計激活函數還有邊界之外,還有很多眉角要注意(就不一一列舉了,自己也不是很明白),結果就是付出的運算成本跟得到的不成比例,因此這方面的研究目前看起來還是挺絕望的 XD。

總而言之,還是有人在努力突破這個問題,可惜目前並沒有成功,回歸正題,我們再取了 abs 之後,其實也等於丟了一個很重要的相位訊息,舉一個簡單的例子,5 可以分解成 3+4i,也可以分解成 4+3i,但你不曉得哪個才是原本的訊號。

Griffin Lim 演算法

那如果我們看的信號不是只看一幀而已,而是看了連續的信號,那麼當左右的信號幅度和原本正常的幅度不同,是否就說明了這樣的相位是錯誤的,假設信號的幅度變化是有規律的,那麼相位就必定也會滿足某種規律,比方說一個三角波,從一幀來看,每個相位是都可以的,但是如果要保證相鄰的波型幅度是正確的,那麼每幀的相位就會有規律,也因為有這樣的假設,所以如果你的訊號像是在坐過山車那樣,這種算法就會失靈。

講那麼多,直接做一次比較快啦!

import librosa
import numpy as np
from IPython.display import Audio

sig,sr = librosa.load("test.wav")
sig = sig[:50000]
# 聽聽看原始聲音
Audio(sig,rate=sr)

# 定義一些參數,之後再補充說明
window='han'
hop_length = 256
n_fft = 2048
spec = librosa.feature.melspectrogram(sig,n_fft=n_fft,hop_length=hop_length,window=window)
# 我們直接 call 它的涵式來轉回 stft,注意這裡是已經取過 abs 的後的值
spec = librosa.feature.inverse.mel_to_stft(spec)

定義自己的 griffin lim ,雖然主要還是參考 librosa 的寫法

def grifflim(S,n_iter=100,hop_length=hop_length,window="hann"):
    n_fft = 2 * (S.shape[0] - 1)
    # 初始化角度
    angles = np.empty(S.shape, dtype=np.complex64)
    angles = np.exp(2j * np.pi * np.random.rand(*S.shape))
    # 紀錄重建之後的結果
    rebuilt = 0.0
    for _ in range(n_iter):
        # 紀錄前一個重建之後的結果
        tprev = rebuilt

        # 把現在的訊號直接轉回去
        inverse = librosa.istft(
            S * angles,
            hop_length=hop_length,
        )

        #  再轉回來
        rebuilt = librosa.stft(
            inverse,
            n_fft=n_fft,
            hop_length=hop_length,
        )

        # 更新角度
        angles = rebuilt -  tprev
        angles /= np.abs(angles) 

    return librosa.istft(
        S * angles,
        hop_length=hop_length,
        window=window,
    )
    

來聽一下重建之後的水平

sig_after = grifflim(spec)
Audio(sig_after,rate=sr)

講了那麼多, 其實 librosa 都幫我們做好了 XD

librosa.griffinlim(S)
# 你甚至可以省略轉成 stft
librosa.feature.inverse.mel_to_audio(M)

自己寫還是有好處的,像是在更新角度的地方就可以用別的做法 (取個 exp 之類的),你也可以更改 n_ter 的次數,像 librosa 只做了 32 次,那結果是有非常嚴重的機械音。

沒有錯,griffin lim 一個致命的缺點就是機器音

所以當 AI 大紅大紫之時,也有人透過訓練,將這部分的交給 Model 來處理,我們稱呼這種 Model 為

~~ Vocoder ~~

但明天想先補充一些其他名詞資訊,可能後天才會開始介紹這部分 XD

小結

今天我們實作 griffin lim ,它可以讓 mel 重新回到 wave 的懷抱,即使它是一種傳統的演算法但依然有效;我們也稍微討論了一下虛數在機器學習下的狀況,得到的結論是目前還是不太行,最後這幾天的 code 已更新在 Github 上了,我盡量想讓大家可以從網頁上 copy 過去 notebook 直接運行就好,希望大家喜歡,再次感謝您耐心的閱讀!

參考資料

What Would Happen if Neural Network States Were Complex Numbers?
Griffin-Lim演算法

/images/emoticon/emoticon09.gif/images/emoticon/emoticon13.gif/images/emoticon/emoticon14.gif/images/emoticon/emoticon22.gif/images/emoticon/emoticon28.gif


上一篇
【Day4】音樂分類小實驗
下一篇
【Day6】窗涵式,n_fft ,hop_length 到底什麼意思啊?
系列文
AI Voice Conversion30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言