本地训练,立等可取,30秒音频素材复刻霉霉讲中文音色基于Bert-VITS2V2.0.2
之前我們使用Bert-VITS2V2.0.2版本對現(xiàn)有的原神數(shù)據(jù)集進(jìn)行了本地訓(xùn)練,但如果克隆對象脫離了原神角色,我們就需要自己構(gòu)建數(shù)據(jù)集了,事實上,深度學(xué)習(xí)模型的性能和泛化能力都依托于所使用的數(shù)據(jù)集的質(zhì)量和多樣性,本次我們在本地利用Bert-VITS2V2.0.2對霉霉講中文的音色進(jìn)行克隆實踐。
霉霉講中文的原始音視頻地址:
https://www.bilibili.com/video/BV1bB4y1R7Nu/
這一段是基于HeyGen項目的AI音色克隆以及唇形合成技術(shù),全片1分鐘左右,中文和英文各30秒,因為我們只克隆中文音色部分,那么將英文部分截去,留下30秒的中文音頻素材。
Bert-VITS2V2.0.2構(gòu)建數(shù)據(jù)集
拿到視頻后,首先需要做音畫分離的操作,即將視頻和音頻拆開,因為數(shù)據(jù)集并不需要視頻,運行命令安裝相關(guān)庫:
pip3 install moviepy
moviepy可以幫我們把音頻部分提取出來,編寫代碼:
from moviepy.editor import AudioFileClip
my_audio_clip = AudioFileClip("e:/meimei.mp4")
my_audio_clip.write_audiofile("e:/meimei.wav")
音頻就被提取了出來。
隨后針對原始音頻素材進(jìn)行分析:
import librosa
import numpy as np
audio, freq = librosa.load("e:\meimei.wav")
time = np.arange(0, len(audio)) / freq
print(len(audio), type(audio), freq, sep="\t")
程序返回:
python3 -u "test.py"
848384 <class 'numpy.ndarray'> 22050
可以看到讀取到了采樣頻率和每個采樣點的信號強度,采樣點共 848384,頻率為 22050,音頻長度約38秒。
至此,我們就完成了原始數(shù)據(jù)集文件的準(zhǔn)備。
Bert-VITS2V2.0.2數(shù)據(jù)集切分
深度學(xué)習(xí)訓(xùn)練過程中,計算機會把訓(xùn)練數(shù)據(jù)讀入顯卡的緩存中,但如果訓(xùn)練集數(shù)據(jù)過大,會導(dǎo)致內(nèi)存溢出問題,也就是常說的“爆顯存”現(xiàn)象。
將數(shù)據(jù)集分成多個部分,每次只載入一個部分的數(shù)據(jù)進(jìn)行訓(xùn)練。這種方法可以減少內(nèi)存使用,同時也可以實現(xiàn)并行處理,提高訓(xùn)練效率。
雖然38秒的原始數(shù)據(jù)并不大,我們依然需要對其切分,這里首先克隆Bert-VITS2V2.0.2本地訓(xùn)練項目:
https://github.com/v3ucn/Bert-VITS2_V202_Train.git
安裝依賴:
pip install -r requirements.txt
隨后運行項目內(nèi)的切分腳本:
python3 audio_slicer.py
該腳本原理就是利用slicer2庫將大文件切分為小份:
import librosa # Optional. Use any library you like to read audio files.
import soundfile # Optional. Use any library you like to write audio files.
import shutil
import gradio as gr
import os
import webbrowser
import subprocess
import datetime
import json
import requests
import soundfile as sf
import numpy as np
import yaml
from config import config
import os
with open('config.yml', mode="r", encoding="utf-8") as f:
configyml=yaml.load(f,Loader=yaml.FullLoader)
model_name = configyml["dataset_path"].replace("Data\\","")
from slicer2 import Slicer
audio, sr = librosa.load(f'./Data/{model_name}/raw/{model_name}/{model_name}.wav', sr=None, mono=False) # Load an audio file with librosa.
slicer = Slicer(
sr=sr,
threshold=-40,
min_length=2000,
min_interval=300,
hop_size=10,
max_sil_kept=500
)
chunks = slicer.slice(audio)
for i, chunk in enumerate(chunks):
if len(chunk.shape) > 1:
chunk = chunk.T # Swap axes if the audio is stereo.
soundfile.write(f'./Data/{model_name}/raw/{model_name}/{model_name}_{i}.wav', chunk, sr) # Save sliced audio files with soundfile.
if os.path.exists(f'./Data/{model_name}/raw/{model_name}/{model_name}.wav'): # 如果文件存在
os.remove(f'./Data/{model_name}/raw/{model_name}/{model_name}.wav')
需要注意的是min_length參數(shù)非常重要,分片文件時長絕對不能低于2秒,這里單位是毫秒,所以數(shù)值為2000,因為梅爾頻譜本身需要有一個加窗的過程,音頻文件必須要至少達(dá)到1幀長+窗口時長才能有結(jié)果,否則就會返回空。所以在數(shù)據(jù)切分時不能有超過2秒的音頻,同時本來短時樣本的質(zhì)量就普遍偏低。
切分后效果:
E:\work\Bert-VITS2-v202_demo\Data\meimei\raw\meimei>tree /f
Folder PATH listing for volume myssd
Volume serial number is 7CE3-15AE
E:.
meimei_0.wav
meimei_1.wav
meimei_2.wav
meimei_3.wav
meimei_4.wav
meimei_5.wav
meimei_6.wav
meimei_7.wav
meimei_8.wav
可以看到38秒音頻被切成了九份。
Bert-VITS2V2.0.2數(shù)據(jù)集重采樣和標(biāo)注
切分好數(shù)據(jù)集后,需要對音頻進(jìn)行重新采樣并生成標(biāo)注文件,較高的采樣率會導(dǎo)致更大的數(shù)據(jù)量和更高的計算成本。
運行腳本:
python3 short_audio_transcribe.py --languages "CJE" --whisper_size medium
這里語言使用medium模型進(jìn)行推理,解決方案采用whisper,關(guān)于whisper,請移步:持續(xù)進(jìn)化,快速轉(zhuǎn)錄,F(xiàn)aster-Whisper對視頻進(jìn)行雙語字幕轉(zhuǎn)錄實踐(Python3.10),這里不再贅述。
程序返回:
E:\work\Bert-VITS2-v202_demo\venv\lib\site-packages\whisper\timing.py:58: NumbaDeprecationWarning: The 'nopython' keyword argument was not supplied to the 'numba.jit' decorator. The implicit default value for this argument is currently False, but it will be changed to True in Numba 0.59.0. See https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit for details.
def backtrace(trace: np.ndarray):
Data\meimei\raw
Detected language: zh
但這些歌曲沒進(jìn)入專輯因為想留著他們下一張專輯用
Processed: 1/31
Detected language: zh
然後下一張專輯完全不同所以他們被拋在了後面
Processed: 2/31
Detected language: zh
你總是會想起這些歌曲你會想
Processed: 3/31
Detected language: zh
會發(fā)生什么因為我希望人們能聽到這個但它屬于那個時刻
Processed: 4/31
Detected language: zh
所以現(xiàn)在我可以回去重新審視我的舊作品
Processed: 5/31
Detected language: zh
我從他們所在的地方挖掘出那些歌曲
Processed: 6/31
Detected language: zh
並聯(lián)繫了我喜歡的藝術(shù)家
Processed: 7/31
Detected language: zh
問他們是否願意和我一起演唱這首歌
Processed: 8/31
Detected language: zh
你知道Phoebe Bridgers是我最喜歡的藝術(shù)家之一
Processed: 9/31
可以看到文本已經(jīng)被whisper轉(zhuǎn)錄了出來。
隨后對文本進(jìn)行預(yù)處理以及生成bert模型可讀文件:
python3 preprocess_text.py
python3 bert_gen.py
執(zhí)行后會產(chǎn)生訓(xùn)練集和驗證集文件:
E:\work\Bert-VITS2-v202\Data\meimei\filelists>tree /f
Folder PATH listing for volume myssd
Volume serial number is 7CE3-15AE
E:.
cleaned.list
short_character_anno.list
train.list
val.list
檢查無誤后,數(shù)據(jù)預(yù)處理就完成了。
Bert-VITS2 V2.0.2開始訓(xùn)練
打開Data/meimei/config.json訓(xùn)練配置文件:
{
"train": {
"log_interval": 50,
"eval_interval": 50,
"seed": 42,
"epochs": 200,
"learning_rate": 0.0001,
"betas": [
0.8,
0.99
],
"eps": 1e-09,
"batch_size": 8,
"fp16_run": false,
"lr_decay": 0.99995,
"segment_size": 16384,
"init_lr_ratio": 1,
"warmup_epochs": 0,
"c_mel": 45,
"c_kl": 1.0,
"skip_optimizer": false
},
"data": {
"training_files": "Data/meimei/filelists/train.list",
"validation_files": "Data/meimei/filelists/val.list",
"max_wav_value": 32768.0,
"sampling_rate": 44100,
"filter_length": 2048,
"hop_length": 512,
"win_length": 2048,
"n_mel_channels": 128,
"mel_fmin": 0.0,
"mel_fmax": null,
"add_blank": true,
"n_speakers": 1,
"cleaned_text": true,
"spk2id": {
"keqing": 0
}
},
"model": {
"use_spk_conditioned_encoder": true,
"use_noise_scaled_mas": true,
"use_mel_posterior_encoder": false,
"use_duration_discriminator": true,
"inter_channels": 192,
"hidden_channels": 192,
"filter_channels": 768,
"n_heads": 2,
"n_layers": 6,
"kernel_size": 3,
"p_dropout": 0.1,
"resblock": "1",
"resblock_kernel_sizes": [
3,
7,
11
],
"resblock_dilation_sizes": [
[
1,
3,
5
],
[
1,
3,
5
],
[
1,
3,
5
]
],
"upsample_rates": [
8,
8,
2,
2,
2
],
"upsample_initial_channel": 512,
"upsample_kernel_sizes": [
16,
16,
8,
2,
2
],
"n_layers_q": 3,
"use_spectral_norm": false,
"gin_channels": 256
},
"version": "2.0"
}
訓(xùn)練的保存間隔調(diào)小一點,方便訓(xùn)練過程中隨時進(jìn)行推理驗證。
隨后輸入命令,開始訓(xùn)練:
python3 train_ms.py
至此,訓(xùn)練環(huán)節(jié)和之前的基于已有數(shù)據(jù)集的本地訓(xùn)練流程已經(jīng)一致,更多訓(xùn)練步驟請移步:本地訓(xùn)練,開箱可用,Bert-VITS2 V2.0.2版本本地基于現(xiàn)有數(shù)據(jù)集訓(xùn)練(原神刻晴),囿于篇幅,這里不再贅述。
Bert-VITS2 V2.0.2過擬合問題
按照刻板印象,訓(xùn)練步數(shù)應(yīng)該越多越好,但其實不然,訓(xùn)練步數(shù)(或稱為迭代次數(shù))并不是越多越好,而是需要在一定范圍內(nèi)找到一個合適的平衡點,如果模型的訓(xùn)練步數(shù)過多,模型可能會過度擬合訓(xùn)練數(shù)據(jù),導(dǎo)致在新數(shù)據(jù)上的泛化能力下降。過擬合指的是模型過度記憶了訓(xùn)練數(shù)據(jù)中的細(xì)節(jié)和噪聲,而無法很好地適應(yīng)新的、未見過的數(shù)據(jù)。
類比的話,有些類似生活中的語義飽和現(xiàn)象,又稱字形飽和、完形崩壞,是一種心理學(xué)現(xiàn)象,指的是人在重復(fù)盯著一個字或者一個單詞長時間后,會發(fā)生突然不認(rèn)識該字或者單詞的情況。此過程僅為暫時,心理學(xué)上認(rèn)為其原因是人的大腦神經(jīng)如果短時間內(nèi)接收到太多重復(fù)的刺激,就會引起神經(jīng)活動的抑制,造成對常用字突然不認(rèn)識的現(xiàn)象。
一般情況下,較大的數(shù)據(jù)集通常可以提供更多的樣本和更豐富的數(shù)據(jù)分布,有助于模型學(xué)習(xí)更準(zhǔn)確和泛化能力更好的特征。大數(shù)據(jù)集可以降低過擬合的風(fēng)險,使模型更能夠捕捉數(shù)據(jù)中的普遍模式而不是噪聲。因此,如果數(shù)據(jù)集足夠大,模型可能需要更多的訓(xùn)練步數(shù)才能充分利用數(shù)據(jù)集的信息。
但我們的數(shù)據(jù)集只有30秒,所以并不需要迭代過多次數(shù),50步足矣。
最后,運行命令對剛訓(xùn)練的模型進(jìn)行推理即可:
python3 server_fastapi.py
結(jié)語
需要注意的是,本次30秒小數(shù)據(jù)集訓(xùn)練很容易導(dǎo)致過擬合,因為模型可能會過度記憶數(shù)據(jù)中的細(xì)節(jié)和噪聲。過多的訓(xùn)練次數(shù)可能會加劇過擬合問題。另一方面,如果訓(xùn)練次數(shù)太少,模型可能無法充分學(xué)習(xí)數(shù)據(jù)中的模式和特征,導(dǎo)致欠擬合。因此,需要在過擬合和欠擬合之間找到一個平衡點。
最后奉上本地整合包,與君共觴:
https://pan.baidu.com/s/1KtNb4wb4UbsHrwVKyTlT0g?pwd=v3uc
總結(jié)
以上是生活随笔為你收集整理的本地训练,立等可取,30秒音频素材复刻霉霉讲中文音色基于Bert-VITS2V2.0.2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka 如何保证消息消费的全局顺序性
- 下一篇: 关于微信小程序中如何实现数据可视化-ec