批次生成,本地推理,人工智慧聲音克隆框架PaddleSpeech本地批次克隆實踐(Python3.10)

2023-06-15 15:01:03

雲端煉丹固然是極好的,但不能否認的是,成本要比本地高得多,同時考慮到深度學習的訓練相對於推理來說成本也更高,這主要是因為它需要大量的資料、計算資源和時間等資源,並且對超引數的調整也要求較高,更適合在雲端進行。

在推理階段,模型的權重和引數不再調整。相反,模型根據輸入資料的特徵進行計算,並輸出預測結果。推理階段通常需要較少的計算資源和時間,所以訓練我們可以放在雲端,而批次推理環節完全可以挪到本地,這樣更適合批次的聲音克隆場景。

本地設定PaddleSpeech

首先需要在本地安裝PaddlePaddle框架,關於PaddlePaddle的本地設定,請移步:聲音好聽,顏值能打,基於PaddleGAN給人工智慧AI語音模型配上動態畫面(Python3.10),這裡不再贅述。

安裝好PaddlePaddle之後,執行命令本地安裝PaddleSpeech:

pip3 install paddlespeech

由於paddlespeech的依賴庫中包括webrtcvad,如果本地環境沒有安裝過Microsoft Visual C++ 14.0,大概率會報這個錯誤:

building 'Crypto.Random.OSRNG.winrandom' extension  
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual  
C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools

此時需要安裝一下Microsoft Visual C++ 14.0的開發者工具,最好不要使用微軟的線上安裝包,推薦使用離線安裝包,下載地址:

連結:https://pan.baidu.com/s/1VSRHAMuDkhzQo7nM4JihEA?pwd=or7x   
提取碼:or7x

安裝完C++ 14.0即可完成PaddleSpeech的安裝:

D:\work\speech\master_voice>python  
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32  
Type "help", "copyright", "credits" or "license" for more information.  
>>> import paddlespeech  
>>>

下載音色模型和聲碼器

音色模型就是之前我們在:聲音克隆,精緻細膩,人工智慧AI打造國師「一鏡到底」鬼畜視訊,基於PaddleSpeech(Python3.10)中訓練的國師的音色模型,下載地址:

連結:https://pan.baidu.com/s/1nKOPlI7P_u_a5UGdHX76fA?pwd=ygqp   
提取碼:ygqp

隨後下載聲碼器,這裡推薦下載【PWGan】和【WaveRnn】兩款聲碼器,不推薦【HifiGan】,因為【HifiGan】的效果實在太糟糕,PWGan的效果差強人意,WaveRnn質量最高,但推理時間也最慢。

下載地址:

連結:https://pan.baidu.com/s/1KHIZS5CrydtANXm6CszdYQ?pwd=6lsk   
提取碼:6lsk

下載之後,分別解壓到同一個目錄即可。

本地推理

接下來我們就可以編寫推理指令碼了。

首先匯入需要的模組:

from pathlib import Path  
import soundfile as sf  
import os  
from paddlespeech.t2s.exps.syn_utils import get_am_output  
from paddlespeech.t2s.exps.syn_utils import get_frontend  
from paddlespeech.t2s.exps.syn_utils import get_predictor  
from paddlespeech.t2s.exps.syn_utils import get_voc_output  
  
# 音色模型的路徑  
am_inference_dir = "./master"  
  
# 聲碼器的路徑  
voc_inference_dir_pwgan = "./pwgan"   
  
# 聲碼器的路徑  
voc_inference_dir_wavernn = "./wavernn"   
  
  
  
# 克隆音訊生成的路徑  
wav_output_dir = "./output"  
  
# 選擇裝置[gpu / cpu],預設選擇gpu,   
device = "gpu"

這裡定義好模型和聲碼器的路徑,同時定義輸出路徑,預設採用gpu進行推理,速度更快。

隨後定義後要語音生成的文字:

text_dict = {  
    "1": "我原來想拿中石油的offer",  
    "2": "是不是很大膽",  
    "3": "中石油",  
    "4": "國企天花板",  
    "5": "就是中石油",  
    "6": "出差可以逛太古裡",  
    "7": "太爽了",  
    "8": "我最早準備面試的時候",  
    "9": "跟所有同學說的只面中石油",  
    "10": "所有的同學,包括親戚,朋友,他們所有人很興奮",  
    "11": "我女朋友也很興奮",  
    "12": "中石油",  
    "13": "一直說的是去中石油",  
    "14": "我一直在做去中石油的準備",  
    "15": "當時我面試的時候",  
    "16": "我說試用期只要20天",  
    "17": "或者只要25天",  
    "18": "兩週到三週",  
    "19": "hr說為什麼?",  
    "20": "我說很簡單",  
    "21": "我每天飛四川",  
    "22": "單程兩個小時",  
    "23": "早上去一次",  
    "24": "晚上去一次",  
    "25": "每天去兩次",  
    "26": "我堅持10天",  
    "27": "20次",  
    "28": "就是20次",  
    "29": "成都太古裡",  
    "30": "哇簡直太爽了",  
    "31": "逛街",  
    "32": "去10天就夠了",  
    "33": "然後前面的十天在北京",  
    "34": "上班",  
    "35": "嚴格地上班",  
    "36": "我說試用期只要二十天",  
    "37": "咱試用期就結束了",  
    "38": "哇hr說真的太厲害",  
    "39": "就挑戰性太大了",  
    "40": "一天都不能請假啊",  
    "41": "但是後來我還是放棄了,哈哈哈",  
  
  
    "42": "你知道為什麼",  
    "43": "我研究了大量的員工去成都的案例",  
    "44": "嗯,也有一些基層員工",  
    "45": "還有尤其是最近一段時間一些比較大膽的行為",  
    "46": "就是牽手那個我也看了",  
    "47": "我專門看",  
    "48": "研究",  
    "49": "就一直,我就一直下不了決心",  
    "50": "其實我真的非常想去啊,內心深處非常想",  
    "51": "你知道最大問題是什麼,當然這是一個專業問題,簡單地說最大問題就是街拍",  
    "52": "就是街拍",  
    "53": "因為你去了他就拍你啊",  
    "54": "就沒有辦法",  
    "55": "對一個員工",  
    "56": "對一個嚮往太古裡的員工",  
    "57": "一個經常逛太古裡的員工來說",  
    "58": "他給你來一個街拍",  
    "59": "全給你拍下來",  
    "60": "上傳抖音",  
    "61": "因為你不能蹭蹭蹭蹭",  
    "62": "逛的太快啊",  
    "63": "不能啊",  
    "64": "你從南邊到北邊",  
    "65": "你中間得逛啊",  
    "66": "就拍了",  
    "67": "就拍了",  
    "68": "第一是街拍避免不了",  
    "69": "無論怎麼樣",  
    "70": "我想來想去",  
    "71": "因為我算個內行嘛",  
    "72": "我不去了,我就知道街拍跑不了",  
    "73": "街拍,避免不了",  
  
    "74": "第二個",  
    "75": "你的工資會全都損失了",  
    "76": "不是損失一半的工資,一半無所謂",  
    "77": "是全部的工資,獎金,績效,年終獎全都沒有了",  
    "78": "然後你還得停職",  
    "79": "就很尷尬啊",  
    "80": "這樣子就不好混了",  
    "81": "真的不好混了",  
    "82": "最後我差不多一個多月的思想鬥爭",  
    "83": "那是個重大決定",  
    "84": "因為我都是按照去中石油準備的",  
    "85": "背面試題呢",  
    "86": "後來說放棄",  
    "87": "我自己決定放棄",  
    "88": "一個人做的決定,一個人的思考",  
    "89": "一個多月以後我放棄了,我第一個電話打給人力,我說我放棄去中石油。他,啊這,就不能接受",  
    "90": "他已經完全沉浸到去太古裡當中去了,你知道吧",  
    "91": "就想著太好了,就喜歡的不得了",  
    "92": "怎麼可能就過來說服我",  
    "93": "我說你不用跟我說",  
    "94": "你都不太清楚",  
    "95": "反正去中石油",  
    "96": "說怎麼可能,你能做到,就開始給我忽悠",  
    "97": "我放棄了",  
    "98": "然後我跟女朋友說放棄",  
    "99": "哎呀,她說她把包包裙子都買了,這那的",  
    "100": "所有人,大家都覺得太遺憾了。",  
    "101": "然後跟老闆說",  
    "102": "最有意思是跟老闆說",  
    "103": "說真的不去中石油了",  
    "104": "哎呀,哎呀",  
    "105": "就覺著好像就沒勁了,哈哈哈",  
    "106": "說你不是開玩笑吧",  
    "107": "哎呀就覺得,好像不想要我了似的",  
    "108": "開玩笑啊,開玩笑",  
    "109": "就所有人都沮喪而失落",  
    "110": "就我看到大家的反應",  
    "111": "我也很難過,很難過",  
    "112": "我我,我後來還是放棄了",  
    "113": "放棄了,嗯",  
    "114": "所以中石油offer是一個學習",  
    "115": "它對於一個追求太古裡的一個員工來說",  
    "116": "它是破壞性的",  
    "117": "你去了中石油又能怎麼樣呢?",  
    "118": "你丟掉了信仰",  
    "119": "丟掉了人格啊",  
    "120": "孰重孰輕啊",  
    "121": "所以我在學習",  
    "122": "我在學習做一個合格員工的思考",  
    "123": "這就是我的,遺憾",  
    "124": "但也許是我的一個清醒",  
    "125": "或者學習的心得",  
}

這裡字典的key是檔名,value是音訊的內容。

隨後載入聲碼器地址中的組態檔:

# frontend  
frontend = get_frontend(  
    lang="mix",  
    phones_dict=os.path.join(am_inference_dir, "phone_id_map.txt"),  
    tones_dict=None  
)  
  
# am_predictor  
am_predictor = get_predictor(  
    model_dir=am_inference_dir,  
    model_file="fastspeech2_mix" + ".pdmodel",  
    params_file="fastspeech2_mix" + ".pdiparams",  
    device=device)  
  
# voc_predictor  
voc_predictor_pwgan = get_predictor(  
    model_dir=voc_inference_dir_pwgan,  
    model_file="pwgan_aishell3" + ".pdmodel",      
    params_file="pwgan_aishell3" + ".pdiparams",  
    device=device)  
  
  
voc_predictor_wavernn = get_predictor(  
    model_dir=voc_inference_dir_wavernn,  
    model_file="wavernn_csmsc" + ".pdmodel",      
    params_file="wavernn_csmsc" + ".pdiparams",  
    device=device)  
  
output_dir = Path(wav_output_dir)  
output_dir.mkdir(parents=True, exist_ok=True)  
  
sentences = list(text_dict.items())

這裡我們準備兩個聲碼器物件。

最後執行克隆函數:

def clone(voc_predictor):  
  
    merge_sentences = True  
    fs = 24000  
    for utt_id, sentence in sentences:  
        am_output_data = get_am_output(  
            input=sentence,  
            am_predictor=am_predictor,  
            am="fastspeech2_mix",  
            frontend=frontend,  
            lang="mix",  
            merge_sentences=merge_sentences,  
            speaker_dict=os.path.join(am_inference_dir, "phone_id_map.txt"),  
            spk_id=0, )  
        wav = get_voc_output(  
                voc_predictor=voc_predictor, input=am_output_data)  
        # 儲存檔案  
        sf.write(output_dir / (utt_id + ".wav"), wav, samplerate=fs)  
  
  
if __name__ == '__main__':  
      
    clone(voc_predictor_pwgan)

這裡預設的取樣率是24000,am模型使用fastspeech2_mix,因為它可以相容英文的閱讀。

聲碼器選擇voc_predictor_pwgan,當然也可以將引數修改為voc_predictor_wavernn。

生成後的效果:

結語

基於聲學模型 FastSpeech2的PaddleSpeech的產品力已經相當驚人,就算是放在全球人工智慧領域的尺度上,擺在微軟這種業界巨頭的最佳產品Azure-tts旁邊,也是毫不遜色的,感謝百度,讓普通人也能玩惡搞配音專案,最後奉上國師的鬼畜視訊一鍵生成專案,與眾鄉親同饗:

https://github.com/zcxey2911/zhangyimou_voice_clone_text