|

如何使用Intel AI PC及OpenVINO實現虛擬主播

   
作者: Jack OmniXRI,Intel Software Innovator

2022年底 OpenAI 引爆大語言模型(Large Lauguage Model,LLM)及生成式人工智慧(Generative Artificial Intelligence,GenAI),從此有各種文字、聲音、影像及多模態的應用,其中「虛擬主播」就是很常的應用例,如像民視的「敏熙」就是很經典的案例。

說到虛擬主播,其演進歷史也有數十年,早年需由美工人員大費周章設計好3D人物模型,再請配音員配上固定對白,最後由動畫人員把肢體動作、對白和嘴形對好,才能完成影片輸出,常見於高階 3D 電玩中較精緻的非玩家角色(Non-Player Character,NPC)。

後來隨著傳統電腦視覺及3D動畫技術演進,慢慢開始有了虛擬代理人(Virtual Agent)、VTuber (Video + Youtuber)出現,只要事先準備好可愛的3D人物模型(公仔),加上高階動作補捉器(Motion Capture),再請真人表演肢體及臉部動作來驅動3D公仔,就可大幅減少美工及動畫人員的工作。早期電腦性能較差,只能採預錄加上後處理合成方式處理,像日本「初音未來」這類「虛擬偶像」及擬真 3D 電影「阿凡達」就是知名代表。

後來隨電腦性能及電腦視覺技術成熟,只需使用一般網路攝影機,就能即時偵測到表演者的動作、表情並驅動3D公仔,一般會稱呼表演者為 VTuber (Video Youtuber),像日本知名「絆愛」、台灣 Yahoo TV 的「虎妮」就屬此類。這樣的技術很適合哪些不露臉的表演者和真實世界的互動,但缺點也是沒有真人就無法操作了,且真人表演不流暢也會影響虛擬人物表現。

十多年前深度學習電腦視覺及自然語言處理(Natual Language Processing,NLP)技術興起,讓電腦有機會能完全控制3D公仔的肢體動作、語音轉文字(Speech To Text,STT)、自然語言理解(Natual Language Understanding,NLU)、對話內容產生、語音轉文字(Text To Speech,TTS),於是開始有了虛擬助理(Vitrual Assistant)和虛擬代理人(Virtual Agent)出現。而隨著大語言模型及生成式技術越來越成熟,像真人一樣互動的數位分身(中國大陸慣稱數字人--即Digital Human、Meta Human)也開始出現在各種場域中,如捷運站的虛擬客服。

圖1:虛擬分身演進,3D人物、人臉建模,動作、表情補捉、真人驅動VTuber,大語言模型及生成式AI客服、主播。(OmniXRI整理製作, 2024/12/12) 圖1:虛擬分身演進,3D人物、人臉建模,動作、表情補捉、真人驅動VTuber,大語言模型及生成式AI客服、主播。(OmniXRI整理製作, 2024/12/12)

為了使大家能更進一步理解如何實作一個簡單離線版(邊緣端)的虛擬主播,可以輸入所需文字,產生對應語音,配合閉嘴人物影片生成新的對嘴影片。接下來就分別從「推論硬體及環境建置介紹」、「MeloTTS 文字轉語音生成」、「Wav2Lip 自動對嘴影片生成」及「建置完整虛擬主播」等四大部份作更進一步說明。

完整範例程式可參考下列網址:https://github.com/OmniXRI/digital_human

(註:本文範例不適用 Google Colab 執行,僅限Intel OpenVINO Notebooks虛擬環境下使用)

1. 推論硬體及環境建置介紹

這裡選用了 Intel AI PC Asus NUC 14 Pro (Core Ultra 5 125H, 內建 Arc GPU, 10TOPS NPU, DDR5 32GB)作為邊緣推論裝置,完整規格請見參考文獻。建議使用前先到官網更新一下NPU驅動程式。(註:如果你仍是使用 Core i3/i5/i7 12/13/14代CPU,在Windows 10運作,原則上以下各範例還是可以執行,只是速度上會慢上許多。)

本文主要使用Windows 11,工作環境是根據 Intel OpenVINO Notebooks 建議的 Python 虛擬環境。如果你未曾安裝過OpenVINO及Notebooks則可參考官方Github 說明進行全新的安裝。

(註:如需中文安裝說明,可參考第2小節說明)

OpenVINO Notebooks目前最新版(latest)為2024.5版,原則大部份的範例都可執行在OpenVINO 2024.x 版。由於w2vlip 範例 只存在 2024.5版中,所以如果電腦中已安裝過較舊版本OpenVINO Notebooks,請先下載最新版openvinotoolkit/openvino_notebooks的ZIP格式檔案,解壓縮後再把 /notebooks/wav2lip 整個檔案夾複製到自己電腦上原先 /openvino_notebooks/notebooks 路徑下,才能進行後面的工作。

不管全新或部份安裝,為避免影響到原先的範例程式,所以請先將 /notebooks/wav2lip 檔案夾複製一份,並更名為 /notebooks/digital_humnan,以便後續將MeloTTS和Wav2Lip整合在一起。接著將 https://github.com/OmniXRI/digital_human 中三個 ipynb 範例下載到 \digitl_human 路徑下,以利後續測試。

另外由於程式會使用到影音相關處理函式,但這些未包括在 OpenVINO & Notebooks 範例中,所以需手動安裝 ffmpeg 函式庫。請確認已進入 OpenVINO Notebooks Python 虛擬環境中後再安裝,如以下指令所示:

pip install ffmpeg

2. MeloTTS 文字轉語音生成

目前 OpenVINO 在文字轉語音(TTS)方面雖有提供 OuteTTS 和 Parler-TTS 範例,但本文使用另一個更輕量的模型 MeloTTS 。它提供了多國語言,如英文、法文、日文、韓文、西班牙文等,其中當然也有包含中文(可中英文混合)。使用上非常簡單,只需提供待發音之文字內容、語速即可。

由於 MeloTTS 尚未正式加入 OpenVINO Notebooks 中,所以這裡我們需要手動安裝相關套件。安裝前,首先啟動 OpenVINO Notebooks Python 虛擬環境,但先不要啟動 Jupyter Notebooks 環境,進到 /openvino_notebooks/notebooks/ 路徑中準備安裝。

接著到 https://github.com/zhaohb/MeloTTS-OV/tree/speech-enhancement-and-npu ,按下綠色「<> Code」,選擇「Download ZIP」,解壓縮後把 \MeloTTS-OV-speech-enhancement-and-npu 檔案夾內所有內容複製到 \openvino_notebooks\notebooks\digital_human 下。

(註:請不要直接複製網頁上git clone命令,這樣會誤下載到標準版本,導致 OpenVINO 無法正確執行。)

再來進到指定路徑,開始安裝必要套件。

cd digital_human

pip install -r requirements.txt

pip install openvino nncf

python setup.py develop # or pip install -e .

python -m unidic download

python -m nltk.downloader averaged_perceptron_tagger_eng

pip install deepfilternet # optional for enhancing speech

pip install ffmpeg # 一定要裝,不然影音內容無法顯示

完成後執行下列命令進行文字轉語音測試。這裡 language 設為 ZH (中英混合)即可, tts_device 可設為CPU、GPU,而bert_device則可設為 CPU、GPU、NPU。

python test_tts.py --language ZH --tts_device CPU --bert_device CPU

第一次執行會花比較多的時間下載模型及轉換成OpenVINO用的IR格式(bin+xml),完成的模型會存放在 \tts_ov_ZH 路徑下。執行完成後會得到 ov_en_int8_ZH.wav ,語音內容為「我們探討如何在Intel平台上轉換和優化atificial intelligence 模型」,可開啟聲音播放軟體進行檢查。

完成上述步驟後才能運作下列簡易版帶介面程式 MeloTTS_run.ipynb 。這個範例有提供 Gradio 介面,方便大家以網頁方式重覆輸入測試字串及檢查生成聲音檔案內容。

下次想要測試時,由於已有轉換好的模型,所以直接開啟並執行這個範例即可執行文字轉語音工作。

# MeloTTS for OpenVINO 單獨執行含Gradio介面範例

#

# by Jack OmniXRI, 2024/12/12

from melo.api import TTS

from pathlib import Path

import time

# MeloTTS 文字轉語音基本參數設定

speed = 1.0 # 調整語速

use_ov = True # True 使用 OpenVINO, False 使用 PyTorch

use_int8 = True # True 啟用 INT8 格式

speech_enhance = True # True 啟用語音增強模式

tts_device = "CPU" # 指定 TTS 推論裝置 , "CPU" 或 "GPU"(這裡指 Intel GPU)

bert_device = "CPU" # 指定 Bert 推論裝置, "CPU" 或 "GPU" 或 "NPU"

lang = "ZH" # 設定語系, EN 英文, ZH 中文(含混合英文、簡繁中文皆可)

# 指定測試文字轉語音字串

if lang == "ZH":

text = "我們討如何在 Intel 平台上轉換和優化 artificial intelligence 模型"

elif lang == "EN":

text = "For Intel platforms, we explore the methods for converting and optimizing models."

# 若指定語音增強模式則新增 process_audio() 函式

if speech_enhance:

from df.enhance import enhance, init_df, load_audio, save_audio

import torchaudio

# 將輸入聲音檔案處理後轉存到新檔案中

def process_audio(input_file: str, output_file: str, new_sample_rate: int = 48000):

"""

Load an audio file, enhance it using a DeepFilterNet, and save the result.

Parameters:

input_file (str): Path to the input audio file.

output_file (str): Path to save the enhanced audio file.

new_sample_rate (int): Desired sample rate for the output audio file (default is 48000 Hz).

"""

model, df_state, _ = init_df()

audio, sr = torchaudio.load(input_file)

# Resample the WAV file to meet the requirements of DeepFilterNet

resampler = torchaudio.transforms.Resample(orig_freq=sr, new_freq=new_sample_rate)

resampled_audio = resampler(audio)

enhanced = enhance(model, df_state, resampled_audio)

# Save the enhanced audio

save_audio(output_file, enhanced, df_state.sr())

# 初始化 TTS

model = TTS(language=lang, tts_device=tts_device, bert_device=bert_device, use_int8=use_int8)

# 取得語者資訊

speaker_ids = model.hps.data.spk2id

speakers = list(speaker_ids.keys())

# 若指定使用 OpenVINO, 檢查該語系是否已處理過,若無則進行轉換,結果會存在 \tts_ov_語系 路徑下

if use_ov:

ov_path = f"tts_ov_{lang}"

if not Path(ov_path).exists():

# 將原始模型轉換成 OpenVINO IR (bin+xml) 格式

model.tts_convert_to_ov(ov_path, language= lang)

# 進行模型初始化

model.ov_model_init(ov_path, language = lang)

if not use_ov: # 若未使用 OpenVINO

for speaker in speakers:

output_path = 'en_pth_{}.wav'.format(str(speaker))

start = time.perf_counter()

model.tts_to_file(text, speaker_ids, output_path, speed=speed*0.75, use_ov = use_ov)

end = time.perf_counter()

else: # 若使用 OpenVINO

for speaker in speakers:

output_path = 'ov_en_int8_{}.wav'.format(speaker) if use_int8 else 'en_ov_{}.wav'.format(speaker)

start = time.perf_counter()

model.tts_to_file(text, speaker_ids, output_path, speed=speed, use_ov=use_ov)

if speech_enhance:

print("Use speech enhance")

process_audio(output_path,output_path)

end = time.perf_counter()

dur_time = (end - start) * 1000

print(f"MeloTTS 文字轉語音共花費: {dur_time:.2f} ms")

# 使用 Gradio 產生互動介面

import gradio as gr

# 定義文字轉語音處理函式 tts()

# 輸入: content(字串)、 use_ov(布林值)、 speed(數值)

# 輸出: "MeloTTS 文字轉語音共花費: xx.xx ms"(字串)、 語音檔案名稱(字串)

def tts(content, use_ov, speed):

start = time.perf_counter()

model.tts_to_file(content, speaker_ids, output_path, speed=speed/100, use_ov=use_ov)

if speech_enhance:

print("Use speech enhance")

process_audio(output_path,output_path)

end = time.perf_counter()

dur_time = (end - start) * 1000

audio = "ov_en_int8_ZH.wav"

result = f"MeloTTS 文字轉語音共花費: {dur_time:.2f} ms"

return result, audio

# 建立輸人及輸出簡單應用介面

# fn: 介面函數名稱

# inputs: 輸人格式, 文字(標籤:名字, 值: “請輸入文字內容")、使用 OpenVINO(複選盒)、滑動桿(標籤:語速(%),最小值50,最大值200,預設值100)

# outputs: 輸出格式,結果字串(標籤:輸出)、輸出音檔(標籤:輸出結果, 檔格式式: filetype)

demo = gr.Interface(

fn=tts,

inputs=[gr.Textbox(label="文字", value = "請輸入文字內容"),

gr.Checkbox(value=True, label="Use_OpenCV"),

gr.Slider(50, 200, value=100, label="語速(%)") ],

outputs=[gr.Textbox(label="轉換時間"),

gr.Audio(label="輸出結果", type="filepath")],

)

# 執行顯示介面

demo.launch()

本文為會員限定文章

立即加入會員! 全站文章無限看~

                               

已經是會員? 按此登入

只需不到短短一分鐘...

輸入您的信箱與ID註冊即可享有一切福利!

會員福利
1

免費電子報

2

會員搶先看

3

主題訂閱

4

好文收藏

許 哲豪

Author: 許 哲豪

工作經驗超過二十年,主要專長機電整合、電腦視覺、人機互動、人工智慧、專利分析及新創輔導。曾任機電整合工程師、機器視覺研發副理、技轉中心商業發展經理。目前擔任多家公司兼任技術顧問並積極推廣實境互動相關技術。 主持歐尼克斯實境互動工作室(OmniXRI):http://omnixri.blogspot.com Edge AI Taiwan邊緣智能交流區:https://www.facebook.com/groups/edgeaitw/

Share This Post On

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *