本地训练,立等可取,30秒音频素材复刻霉霉讲中文音色基于Bert-VITS2V2.0.2
之前我們使用Bert-VITS2V2.0.2版本對現有的原神數據集進行了本地訓練,但如果克隆對象脫離了原神角色,我們就需要自己構建數據集了,事實上,深度學習模型的性能和泛化能力都依托于所使用的數據集的質量和多樣性,本次我們在本地利用Bert-VITS2V2.0.2對霉霉講中文的音色進行克隆實踐。
霉霉講中文的原始音視頻地址:
https://www.bilibili.com/video/BV1bB4y1R7Nu/
這一段是基于HeyGen項目的AI音色克隆以及唇形合成技術,全片1分鐘左右,中文和英文各30秒,因為我們只克隆中文音色部分,那么將英文部分截去,留下30秒的中文音頻素材。
Bert-VITS2V2.0.2構建數據集
拿到視頻后,首先需要做音畫分離的操作,即將視頻和音頻拆開,因為數據集并不需要視頻,運行命令安裝相關庫:
pip3 install moviepy
moviepy可以幫我們把音頻部分提取出來,編寫代碼:
from moviepy.editor import AudioFileClip
my_audio_clip = AudioFileClip("e:/meimei.mp4")
my_audio_clip.write_audiofile("e:/meimei.wav")
音頻就被提取了出來。
隨后針對原始音頻素材進行分析:
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秒。
至此,我們就完成了原始數據集文件的準備。
Bert-VITS2V2.0.2數據集切分
深度學習訓練過程中,計算機會把訓練數據讀入顯卡的緩存中,但如果訓練集數據過大,會導致內存溢出問題,也就是常說的“爆顯存”現象。
將數據集分成多個部分,每次只載入一個部分的數據進行訓練。這種方法可以減少內存使用,同時也可以實現并行處理,提高訓練效率。
雖然38秒的原始數據并不大,我們依然需要對其切分,這里首先克隆Bert-VITS2V2.0.2本地訓練項目:
https://github.com/v3ucn/Bert-VITS2_V202_Train.git
安裝依賴:
pip install -r requirements.txt
隨后運行項目內的切分腳本:
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參數非常重要,分片文件時長絕對不能低于2秒,這里單位是毫秒,所以數值為2000,因為梅爾頻譜本身需要有一個加窗的過程,音頻文件必須要至少達到1幀長+窗口時長才能有結果,否則就會返回空。所以在數據切分時不能有超過2秒的音頻,同時本來短時樣本的質量就普遍偏低。
切分后效果:
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數據集重采樣和標注
切分好數據集后,需要對音頻進行重新采樣并生成標注文件,較高的采樣率會導致更大的數據量和更高的計算成本。
運行腳本:
python3 short_audio_transcribe.py --languages "CJE" --whisper_size medium
這里語言使用medium模型進行推理,解決方案采用whisper,關于whisper,請移步:持續進化,快速轉錄,Faster-Whisper對視頻進行雙語字幕轉錄實踐(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
但這些歌曲沒進入專輯因為想留著他們下一張專輯用
Processed: 1/31
Detected language: zh
然後下一張專輯完全不同所以他們被拋在了後面
Processed: 2/31
Detected language: zh
你總是會想起這些歌曲你會想
Processed: 3/31
Detected language: zh
會發生什么因為我希望人們能聽到這個但它屬于那個時刻
Processed: 4/31
Detected language: zh
所以現在我可以回去重新審視我的舊作品
Processed: 5/31
Detected language: zh
我從他們所在的地方挖掘出那些歌曲
Processed: 6/31
Detected language: zh
並聯繫了我喜歡的藝術家
Processed: 7/31
Detected language: zh
問他們是否願意和我一起演唱這首歌
Processed: 8/31
Detected language: zh
你知道Phoebe Bridgers是我最喜歡的藝術家之一
Processed: 9/31
可以看到文本已經被whisper轉錄了出來。
隨后對文本進行預處理以及生成bert模型可讀文件:
python3 preprocess_text.py
python3 bert_gen.py
執行后會產生訓練集和驗證集文件:
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
檢查無誤后,數據預處理就完成了。
Bert-VITS2 V2.0.2開始訓練
打開Data/meimei/config.json訓練配置文件:
{
"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"
}
訓練的保存間隔調小一點,方便訓練過程中隨時進行推理驗證。
隨后輸入命令,開始訓練:
python3 train_ms.py
至此,訓練環節和之前的基于已有數據集的本地訓練流程已經一致,更多訓練步驟請移步:本地訓練,開箱可用,Bert-VITS2 V2.0.2版本本地基于現有數據集訓練(原神刻晴),囿于篇幅,這里不再贅述。
Bert-VITS2 V2.0.2過擬合問題
按照刻板印象,訓練步數應該越多越好,但其實不然,訓練步數(或稱為迭代次數)并不是越多越好,而是需要在一定范圍內找到一個合適的平衡點,如果模型的訓練步數過多,模型可能會過度擬合訓練數據,導致在新數據上的泛化能力下降。過擬合指的是模型過度記憶了訓練數據中的細節和噪聲,而無法很好地適應新的、未見過的數據。
類比的話,有些類似生活中的語義飽和現象,又稱字形飽和、完形崩壞,是一種心理學現象,指的是人在重復盯著一個字或者一個單詞長時間后,會發生突然不認識該字或者單詞的情況。此過程僅為暫時,心理學上認為其原因是人的大腦神經如果短時間內接收到太多重復的刺激,就會引起神經活動的抑制,造成對常用字突然不認識的現象。
一般情況下,較大的數據集通常可以提供更多的樣本和更豐富的數據分布,有助于模型學習更準確和泛化能力更好的特征。大數據集可以降低過擬合的風險,使模型更能夠捕捉數據中的普遍模式而不是噪聲。因此,如果數據集足夠大,模型可能需要更多的訓練步數才能充分利用數據集的信息。
但我們的數據集只有30秒,所以并不需要迭代過多次數,50步足矣。
最后,運行命令對剛訓練的模型進行推理即可:
python3 server_fastapi.py
結語
需要注意的是,本次30秒小數據集訓練很容易導致過擬合,因為模型可能會過度記憶數據中的細節和噪聲。過多的訓練次數可能會加劇過擬合問題。另一方面,如果訓練次數太少,模型可能無法充分學習數據中的模式和特征,導致欠擬合。因此,需要在過擬合和欠擬合之間找到一個平衡點。
最后奉上本地整合包,與君共觴:
https://pan.baidu.com/s/1KtNb4wb4UbsHrwVKyTlT0g?pwd=v3uc
總結
以上是生活随笔為你收集整理的本地训练,立等可取,30秒音频素材复刻霉霉讲中文音色基于Bert-VITS2V2.0.2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka 如何保证消息消费的全局顺序性
- 下一篇: 强化学习(八) - 深度Q学习(Deep