admin管理员组

文章数量:1544593

近几天有好多小伙伴咨询Sovits本地部署的问题,所以呢决定写个简易教程。

首先给出官方Github链接:GitHub - svc-develop-team/so-vits-svc: SoftVC VITS Singing Voice Conversion

首先放出声明(官方写的):

本项目为开源、离线的项目,SvcDevelopTeam的所有成员与本项目的所有开发者以及维护者(以下简称贡献者)对本项目没有控制力。本项目的贡献者从未向任何组织或个人提供包括但不限于数据集提取、数据集加工、算力支持、训练支持、推理等一切形式的帮助;本项目的贡献者不知晓也无法知晓使用者使用该项目的用途。故一切基于本项目训练的AI模型和合成的音频都与本项目贡献者无关。一切由此造成的问题由使用者自行承担。

此项目完全离线运行,不能收集任何用户信息或获取用户输入数据。因此,这个项目的贡献者不知道所有的用户输入和模型,因此不负责任何用户输入。

本项目只是一个框架项目,本身并没有语音合成的功能,所有的功能都需要用户自己训练模型。同时,这个项目没有任何模型,任何二次分发的项目都与这个项目的贡献者无关。

使用规约:

  1. 本项目是基于学术交流目的建立,仅供交流与学习使用,并非为生产环境准备。
  2. 任何发布到视频平台的基于 sovits 制作的视频,都必须要在简介明确指明用于变声器转换的输入源歌声、音频,例如:使用他人发布的视频 / 音频,通过分离的人声作为输入源进行转换的,必须要给出明确的原视频、音乐链接;若使用是自己的人声,或是使用其他歌声合成引擎合成的声音作为输入源进行转换的,也必须在简介加以说明。
  3. 由输入源造成的侵权问题需自行承担全部责任和一切后果。使用其他商用歌声合成软件作为输入源时,请确保遵守该软件的使用条例,注意,许多歌声合成引擎使用条例中明确指明不可用于输入源进行转换!
  4. 禁止使用该项目从事违法行为与宗教、政治等活动,该项目维护者坚决抵制上述行为,不同意此条则禁止使用该项目。
  5. 继续使用视为已同意本仓库 README 所述相关条例,本仓库 README 已进行劝导义务,不对后续可能存在问题负责。
  6. 如果将此项目用于任何其他企划,请提前联系并告知本仓库作者,十分感谢。

两点强烈建议:

1、使用Linux系统(Windows也可以,但是略麻烦)

2、GPU的显存最好在12G以上(自己电脑显存不够的话可以使用云服务器,Colab或者Autodl等都可以)

Step1: 获取视频数据

训练Sovits的时候,需要一些原始音频数据,比如你想训练AI陈奕迅,那你就得获取陈奕迅的音频数据。B站有那种歌手歌曲合集的视频,可以一次性下载很多首歌,不用一首一首的下载,所以我的所有数据都是从B站获取的,当然别的渠道也可以,只要是WAV格式的都行。其他格式的音频数据也可以,但是需要借助代码或者工具来转换以下,略麻烦,不推荐。

首先打开B站,搜索XX歌手歌曲合集,点进去,选中红框内的链接复制下来。图片不让放。。这个很简单,有没有无所谓了~

import os
import subprocess
import shutil

# 视频链接列表
video_urls = ["https://www.bilibili/video/BV1Gt411U73U"]

# 视频保存的目录
output_directory = "videos/eason"


for url in video_urls:
    # 构建yt-dlp命令
    command = [
        "yt-dlp",
        "-o", os.path.join(output_directory, "%(title)s.%(ext)s"),  # 输出路径
        url  # 要下载的视频链接
    ]

    # 执行yt-dlp命令
    subprocess.run(command, check=True)

video_urls里面放入上面复制的链接就可以了,这里可以放多个链接,用逗号隔开就好。Video/eason是存放视频文件的地方,可以自定义。

Step2: 获取音频数据

需要训练的数据是音频数据,所以还要将上面的视频数据给分离一下,分成音频和视频。

import os
import moviepy.editor as mp
from pydub import AudioSegment
from multiprocessing import Pool

def process_video(filename):
    if filename.endswith('.mp4'):
        # 读取视频文件
        video = mp.VideoFileClip(os.path.join(input_video_directory, filename))

        # 创建音频文件
        audio = video.audio
        audio_filename = os.path.splitext(filename)[0] + '.wav'
        audio.write_audiofile(os.path.join(output_audio_directory, audio_filename))

        # 创建无音频的视频文件
        video_without_audio = video.without_audio()
        video_filename = os.path.splitext(filename)[0] + '_no_audio.mp4'
        video_without_audio.write_videofile(os.path.join(output_video_directory, video_filename))

# 视频输入和输出目录
input_video_directory = 'video/eason'
output_video_directory = 'audio_video/video'

# 音频输出目录
output_audio_directory = 'audio_video/audio'
# 创建一个处理器池
pool = Pool()

# 使用多进程处理视频文件
pool.map(process_video, os.listdir(input_video_directory))

pool.close()
pool.join()

这个input_video_directory就是第一步从B站下载到的视频的存放文件夹,output_video_directory是分离后的视频存放文件地址,output_audio_directory是音频存放地址,后续训练我们只用到output_audio_directory。

如果运行以后出现"no module named xx",那就是xx包没有安装,直接pip install xx -i 清华源就好。

Step3: 人声和背景声分离

第二步获取到的音频数据是人声和背景声,比如钢琴、小提琴和吉他声等。为了获得纯净的人声,需要利用算法将它们分开。

import os
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'

from spleeter.separator import Separator
import soundfile as sf

def process_folder(input_folder_path, vocals_folder_path, accompaniment_folder_path):
    # 使用预训练模型 'spleeter:2stems' 进行声音分离
    separator = Separator('spleeter:2stems')

    # 获取文件夹中所有.wav文件的路径
    file_paths = [os.path.join(input_folder_path, f) for f in os.listdir(input_folder_path) if f.endswith('.wav')]

    # 逐个处理音频文件
    for file_path in file_paths:
        # 加载音频文件
        audio_data, sample_rate = sf.read(file_path)

        # 分离音频文件
        prediction = separator.separate(audio_data)

        # 获取音频文件名(不含后缀)
        file_name = os.path.splitext(os.path.basename(file_path))[0]

        # 保存人声到特定的文件夹
        sf.write(os.path.join(vocals_folder_path, file_name + '_vocals.wav'), prediction['vocals'], sample_rate)

        # 保存伴奏到特定的文件夹
        sf.write(os.path.join(accompaniment_folder_path, file_name + '_accompaniment.wav'), prediction['accompaniment'], sample_rate)

# 使用你的音频文件夹路径替换下面的路径
process_folder('audio_video/audio', 'vocals', 'accompaniment')

说明一下,process_folder函数里面第一个参数是第二步获取到的audio文件夹的地址,vocals是人声存放地址,这个就是我们的初始数据,accompaniment存放的是背景声,这个虽然训练用不到,但是后面会用到,不要删掉了。

Step4: 音频切片

一首歌通常4分钟左右,但是如果将整首歌直接送到模型,大概率会爆显存,所以现在把每一首歌切成很多个片段,每个片段长度在5-15秒左右,根据自己GPU显存来确定,我这里选择每段切成10s。

import os
import wave
import audioop

input_folder = "vocals"
output_folder = "eason"

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

for audio_file in os.listdir(input_folder):
    if audio_file.endswith('.wav'):
        audio_path = os.path.join(input_folder, audio_file)

        with wave.open(audio_path, 'rb') as audio:
            params = audio.getparams()
            frames_per_slice = params.framerate * 8  # 15 seconds of frames
            
            for i in range(0, params.nframes, frames_per_slice):
                audio.setpos(i)
                frames = audio.readframes(frames_per_slice)
                
                # If the audio is stereo, we need to half the slice size because it contains two channels
                if params.nchannels == 2:
                    frames = audioop.tomono(frames, params.sampwidth, 0.5, 0.5)
                
                slice_file_name = f"{audio_file.split('.wav')[0]}_slice_{i//frames_per_slice}.wav"
                slice_path = os.path.join(output_folder, slice_file_name)
                
                with wave.open(slice_path, 'wb') as slice:
                    slice.setnchannels(1 if params.nchannels == 2 else params.nchannels)
                    slice.setsampwidth(params.sampwidth)
                    slice.setframerate(params.framerate)
                    slice.writeframes(frames)

这里面,input_folder是第三步人声的文件夹地址,output_folder是切片以后的声音片段文件夹的地址,建议将output_folder命名为歌手英文名。

上面的是我自己写的一些小工具,下面接着官方教程。

Step5: 下载一些Pretrain文件

hubert_base.pt是声音编码器文件,把它下载下来将文件名改为checkpoint_best_legacy_500.pt后,放在pretrain目录下。

clean_G_320000.pth和clean_G_320000.pth是预训练底膜文件,分别改名成G_0.pth和D_0.pth文件放在logs/44k下面,PS这俩玩意找了半天才从huffingface找到,之前用的其他人的底膜,训练出来的电音小王子把我给整麻了。

model_0.pt是扩散模型预训练文件,放在logs/44k/diffusion下面,同样在huffingface找到了,huffingfaceNB!!!!!!!

链接:https://pan.baidu/s/1zhoqdZtY7ELmQLd0ZEzd0g?pwd=vda8 
提取码:vda8 
--来自百度网盘超级会员V4的分享

Step6: 将切片后的音频片段重采样至44100HZ单声道

命令行切到so-vits-svc-4.1-Stable文件夹,然后运行resample.py

cd so-vits-svc-4.1-Stable

python resample.py

Step7: 自动划分训练集、验证集和生成配置文件

python preprocess_flist_config.py --speech_encoder vec768l12

运行完成后会生成config.json和diffusion.yaml文件夹,需要进行一些修改,搬运下官方解释:

diffusion.yaml
  • cache_all_data:加载所有数据集到内存中,某些平台的硬盘IO过于低下、同时内存容量 远大于 数据集体积时可以启用

  • duration:训练时音频切片时长,可根据显存大小调整,注意,该值必须小于训练集内音频的最短时间!

  • batch_size:单次训练加载到GPU的数据量,调整到低于显存容量的大小即可

  • timesteps : 扩散模型总步数,默认为1000.

  • k_step_max : 训练时可仅训练k_step_max步扩散以节约训练时间,注意,该值必须小于timesteps,0为训练整个扩散模型,注意,如果不训练整个扩散模型将无法使用仅扩散模型推理!

json文件夹可以用记事本打开

  • keep_ckpts:训练时保留最后几个模型,0为保留所有,默认只保留最后3

  • all_in_mem:加载所有数据集到内存中,某些平台的硬盘IO过于低下、同时内存容量 远大于 数据集体积时可以启用

  • batch_size:单次训练加载到GPU的数据量,调整到低于显存容量的大小即可

  • vocoder_name : 选择一种声码器,默认为nsf-hifigan.

Step8: 生成hubert和f0

python preprocess_hubert_f0.py --f0_predictor dio

这个过程比较缓慢,需要耐心等待。此外,最好保持硬盘内存剩余容量在10G以上。

Step9: 主模型训练

python train.py -c configs/config.json -m 44k

这里其实还有个扩散模型训练,为了省事就只训练主模型。

模型训练结束后,模型文件保存在logs/44k目录下,扩散模型在logs/44k/diffusion

Step10: 推理

python inference_main.py -m "logs/44k/G_30400.pth" -c "configs/config.json" -n "君の知らない物語-src.wav" -t 0 -s "nen"
logs/44k/G_30400.pth是训练出来的权重,根据自己训练结果调整
君の知らない物語-src.wav  是需要换声的音频

最后一个参数nen是你需要换声的对象的名字,与之前的纯净人声的文件夹名字一致,比如这里就是eason,需要注意的是我这里只同时训练了一个歌手,多个歌手需要将不同歌手切片后的声音片段放在不用文件夹里面,并且需要用不用的文件名区分,比如周杰伦可以用Jay来命名。

注意!!!!如果使用whisper-ppg 声音编码器进行推理,需要将--clip设置为25,-lg设置为1。否则将无法正常推理。

推理结果会放在results文件夹里面,一首歌的结果可能会分成两片或更多,自己合成一下,然后跟之前accompaniment文件夹里面对应的背景声合成一下就完事了。

本文标签: Sovits