chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
root_dir = Path(__file__).parent.parent.resolve()
|
||||
os.environ['PYTHONPATH'] = str(root_dir)
|
||||
sys.path.insert(0, str(root_dir))
|
||||
|
||||
from utils.hparams import set_hparams, hparams
|
||||
|
||||
set_hparams()
|
||||
|
||||
|
||||
def binarize():
|
||||
binarizer_cls = hparams["binarizer_cls"]
|
||||
pkg = ".".join(binarizer_cls.split(".")[:-1])
|
||||
cls_name = binarizer_cls.split(".")[-1]
|
||||
binarizer_cls = getattr(importlib.import_module(pkg), cls_name)
|
||||
print("| Binarizer: ", binarizer_cls)
|
||||
binarizer_cls().process()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
binarize()
|
||||
@@ -0,0 +1,72 @@
|
||||
import torch
|
||||
import argparse
|
||||
import pathlib
|
||||
import re
|
||||
|
||||
|
||||
def modify_spk_embed(spk_embed):
|
||||
num_spk, hidden_size = spk_embed.shape
|
||||
all_ids = set(range(num_spk))
|
||||
if args.drop is not None:
|
||||
drop_ids = set([int(i) for i in args.drop.split(',') if i != '']).intersection(all_ids)
|
||||
else:
|
||||
drop_ids = all_ids - set([int(i) for i in args.retain.split(',') if i != ''])
|
||||
|
||||
fill_list = None
|
||||
if args.fill == 'zeros':
|
||||
fill_list = [0. for _ in drop_ids]
|
||||
elif args.fill == 'random':
|
||||
fill_list = [torch.randn(1, hidden_size, dtype=torch.float32, device='cpu') for _ in drop_ids]
|
||||
elif args.fill == 'mean':
|
||||
mean = torch.mean(spk_embed, dim=0, keepdim=True)
|
||||
fill_list = [mean for _ in drop_ids]
|
||||
elif args.fill == 'cyclic':
|
||||
retain_ids = sorted(all_ids - drop_ids)
|
||||
num_retain = len(retain_ids)
|
||||
fill_list = [spk_embed[retain_ids[i % num_retain], :] for i, _ in enumerate(drop_ids)]
|
||||
|
||||
for spk_id, fill in zip(sorted(drop_ids), fill_list):
|
||||
spk_embed[spk_id, :] = fill
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description='Drop or edit spk_embed in a checkpoint.')
|
||||
parser.add_argument('input', type=str, help='Path to the input file')
|
||||
parser.add_argument('output', type=str, help='Path to the output file')
|
||||
drop_retain_group = parser.add_mutually_exclusive_group()
|
||||
drop_retain_group.add_argument('--drop', type=str, required=False, metavar='ID,ID,...',
|
||||
help='Drop specific speaker IDs.')
|
||||
drop_retain_group.add_argument('--retain', type=str, required=False, metavar='ID,ID,...',
|
||||
help='Retain specific speaker IDs and drop all the others.')
|
||||
parser.add_argument('--fill', type=str, required=False, default='zeros', metavar='METHOD',
|
||||
choices=['zeros', 'random', 'mean', 'cyclic'],
|
||||
help='Specify a filling method for the dropped embedding. '
|
||||
'Available methods: zeros, random, mean, cyclic')
|
||||
parser.add_argument('--overwrite', required=False, default=False,
|
||||
action='store_true', help='Overwrite if the output file exists.')
|
||||
args = parser.parse_args()
|
||||
assert args.drop is not None or args.retain is not None, 'Either --drop or --retain should be specified.'
|
||||
if args.drop and not re.fullmatch(r'(\d+)?(,\d+)*,?', args.drop):
|
||||
print(f'Invalid format for --drop: \'{args.drop}\'')
|
||||
exit(-1)
|
||||
if args.retain and not re.fullmatch(r'(\d+)?(,\d+)*,?', args.retain):
|
||||
print(f'Invalid format for --retain: \'{args.retain}\'')
|
||||
exit(-1)
|
||||
|
||||
import torch
|
||||
input_ckpt = pathlib.Path(args.input).resolve()
|
||||
output_ckpt = pathlib.Path(args.output).resolve()
|
||||
assert input_ckpt.exists(), 'The input file does not exist.'
|
||||
assert args.overwrite or not output_ckpt.exists(), \
|
||||
'The output file already exists or is the same as the input file.\n' \
|
||||
'This is not recommended because spk_embed dropping scripts may not be stable, ' \
|
||||
'and you may be at risk of losing your model.\n' \
|
||||
'If you are sure to OVERWRITE the existing file, please re-run this script with the \'--overwrite\' argument.'
|
||||
|
||||
ckpt_loaded = torch.load(input_ckpt, map_location='cpu')
|
||||
state_dict = ckpt_loaded['state_dict']
|
||||
if 'model.fs2.spk_embed.weight' in state_dict:
|
||||
modify_spk_embed(state_dict['model.fs2.spk_embed.weight'])
|
||||
if 'model.spk_embed.weight' in state_dict:
|
||||
modify_spk_embed(state_dict['model.spk_embed.weight'])
|
||||
|
||||
torch.save(ckpt_loaded, output_ckpt)
|
||||
@@ -0,0 +1,294 @@
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
import click
|
||||
import torch
|
||||
|
||||
root_dir = pathlib.Path(__file__).resolve().parent.parent
|
||||
os.environ['PYTHONPATH'] = str(root_dir)
|
||||
sys.path.insert(0, str(root_dir))
|
||||
|
||||
from utils.hparams import set_hparams, hparams
|
||||
|
||||
|
||||
def find_exp(exp):
|
||||
if not (root_dir / 'checkpoints' / exp).exists():
|
||||
for subdir in (root_dir / 'checkpoints').iterdir():
|
||||
if not subdir.is_dir():
|
||||
continue
|
||||
if subdir.name.startswith(exp):
|
||||
print(f'| match ckpt by prefix: {subdir.name}')
|
||||
exp = subdir.name
|
||||
break
|
||||
else:
|
||||
raise click.BadParameter(
|
||||
f'There are no matching exp starting with \'{exp}\' in \'checkpoints\' folder. '
|
||||
'Please specify \'--exp\' as the folder name or prefix.'
|
||||
)
|
||||
else:
|
||||
print(f'| found ckpt by name: {exp}')
|
||||
return exp
|
||||
|
||||
|
||||
def parse_spk_settings(export_spk, freeze_spk):
|
||||
if export_spk is None:
|
||||
export_spk = []
|
||||
else:
|
||||
export_spk = list(export_spk)
|
||||
from utils.infer_utils import parse_commandline_spk_mix
|
||||
spk_name_pattern = r'[0-9A-Za-z_-]+'
|
||||
export_spk_mix = []
|
||||
for spk in export_spk:
|
||||
assert '=' in spk or '|' not in spk, \
|
||||
'You must specify an alias with \'NAME=\' for each speaker mix.'
|
||||
if '=' in spk:
|
||||
alias, mix = spk.split('=', maxsplit=1)
|
||||
assert re.fullmatch(spk_name_pattern, alias) is not None, f'Invalid alias \'{alias}\' for speaker mix.'
|
||||
export_spk_mix.append((alias, parse_commandline_spk_mix(mix)))
|
||||
else:
|
||||
export_spk_mix.append((spk, {spk: 1.0}))
|
||||
freeze_spk_mix = None
|
||||
if freeze_spk is not None:
|
||||
assert '=' in freeze_spk or '|' not in freeze_spk, \
|
||||
'You must specify an alias with \'NAME=\' for each speaker mix.'
|
||||
if '=' in freeze_spk:
|
||||
alias, mix = freeze_spk.split('=', maxsplit=1)
|
||||
assert re.fullmatch(spk_name_pattern, alias) is not None, f'Invalid alias \'{alias}\' for speaker mix.'
|
||||
freeze_spk_mix = (alias, parse_commandline_spk_mix(mix))
|
||||
else:
|
||||
freeze_spk_mix = (freeze_spk, {freeze_spk: 1.0})
|
||||
return export_spk_mix, freeze_spk_mix
|
||||
|
||||
|
||||
@click.group()
|
||||
def main():
|
||||
pass
|
||||
|
||||
|
||||
@main.command(help='Export DiffSinger acoustic model to ONNX format.')
|
||||
@click.option(
|
||||
'--exp', type=click.STRING,
|
||||
required=True, metavar='EXP', callback=lambda ctx, param, value: find_exp(value),
|
||||
help='Choose an experiment to export.'
|
||||
)
|
||||
@click.option(
|
||||
'--ckpt', type=click.IntRange(min=0),
|
||||
required=False, metavar='STEPS',
|
||||
help='Checkpoint training steps.'
|
||||
)
|
||||
@click.option(
|
||||
'--out', type=click.Path(
|
||||
dir_okay=True, file_okay=False,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
required=False,
|
||||
help='Output directory for the artifacts.'
|
||||
)
|
||||
@click.option(
|
||||
'--freeze_gender', type=click.FloatRange(min=-1, max=1),
|
||||
help='(for random pitch shifting) Freeze gender value into the model.'
|
||||
)
|
||||
@click.option(
|
||||
'--freeze_velocity', is_flag=True,
|
||||
help='(for random time stretching) Freeze default velocity value into the model.'
|
||||
)
|
||||
@click.option(
|
||||
'--export_spk', type=click.STRING,
|
||||
required=False, multiple=True,
|
||||
help='(for multi-speaker models) Export one or more speaker or speaker mixture keys.'
|
||||
)
|
||||
@click.option(
|
||||
'--freeze_spk', type=click.STRING,
|
||||
required=False,
|
||||
help='(for multi-speaker models) Freeze one speaker or speaker mixture into the model.'
|
||||
)
|
||||
def acoustic(
|
||||
exp: str,
|
||||
ckpt: int = None,
|
||||
out: pathlib.Path = None,
|
||||
freeze_gender: float = 0.,
|
||||
freeze_velocity: bool = False,
|
||||
export_spk: List[str] = None,
|
||||
freeze_spk: str = None
|
||||
):
|
||||
# Validate arguments
|
||||
if export_spk and freeze_spk:
|
||||
print('--export_spk is exclusive to --freeze_spk.')
|
||||
exit(-1)
|
||||
if out is None:
|
||||
out = root_dir / 'artifacts' / exp
|
||||
export_spk_mix, freeze_spk_mix = parse_spk_settings(export_spk, freeze_spk)
|
||||
|
||||
# Load configurations
|
||||
sys.argv = [
|
||||
sys.argv[0],
|
||||
'--exp_name',
|
||||
exp,
|
||||
'--infer'
|
||||
]
|
||||
set_hparams()
|
||||
|
||||
# Export artifacts
|
||||
from deployment.exporters import DiffSingerAcousticExporter
|
||||
print(f'| Exporter: {DiffSingerAcousticExporter}')
|
||||
exporter = DiffSingerAcousticExporter(
|
||||
device=torch.device('cuda' if torch.cuda.is_available() else 'cpu'),
|
||||
cache_dir=root_dir / 'deployment' / 'cache',
|
||||
ckpt_steps=ckpt,
|
||||
freeze_gender=freeze_gender,
|
||||
freeze_velocity=freeze_velocity,
|
||||
export_spk=export_spk_mix,
|
||||
freeze_spk=freeze_spk_mix
|
||||
)
|
||||
try:
|
||||
exporter.export(out)
|
||||
except KeyboardInterrupt:
|
||||
exit(-1)
|
||||
|
||||
|
||||
@main.command(help='Export DiffSinger variance model to ONNX format.')
|
||||
@click.option(
|
||||
'--exp', type=click.STRING,
|
||||
required=True, metavar='EXP', callback=lambda ctx, param, value: find_exp(value),
|
||||
help='Choose an experiment to export.'
|
||||
)
|
||||
@click.option(
|
||||
'--ckpt', type=click.IntRange(min=0),
|
||||
required=False, metavar='STEPS',
|
||||
help='Checkpoint training steps.'
|
||||
)
|
||||
@click.option(
|
||||
'--out', type=click.Path(
|
||||
dir_okay=True, file_okay=False,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
required=False,
|
||||
help='Output directory for the artifacts.'
|
||||
)
|
||||
@click.option(
|
||||
'--freeze_glide', is_flag=True,
|
||||
help='Freeze default glide embedding into the model.'
|
||||
)
|
||||
@click.option(
|
||||
'--freeze_expr', is_flag=True,
|
||||
help='Freeze default pitch expressiveness factor into the model.'
|
||||
)
|
||||
@click.option(
|
||||
'--export_spk', type=click.STRING,
|
||||
required=False, multiple=True,
|
||||
help='(for multi-speaker models) Export one or more speaker or speaker mixture keys.'
|
||||
)
|
||||
@click.option(
|
||||
'--freeze_spk', type=click.STRING,
|
||||
required=False,
|
||||
help='(for multi-speaker models) Freeze one speaker or speaker mixture into the model.'
|
||||
)
|
||||
def variance(
|
||||
exp: str,
|
||||
ckpt: int = None,
|
||||
out: str = None,
|
||||
freeze_glide: bool = False,
|
||||
freeze_expr: bool = False,
|
||||
export_spk: List[str] = None,
|
||||
freeze_spk: str = None
|
||||
):
|
||||
# Validate arguments
|
||||
if export_spk and freeze_spk:
|
||||
print('--export_spk is exclusive to --freeze_spk.')
|
||||
exit(-1)
|
||||
if out is None:
|
||||
out = root_dir / 'artifacts' / exp
|
||||
export_spk_mix, freeze_spk_mix = parse_spk_settings(export_spk, freeze_spk)
|
||||
|
||||
# Load configurations
|
||||
sys.argv = [
|
||||
sys.argv[0],
|
||||
'--exp_name',
|
||||
exp,
|
||||
'--infer'
|
||||
]
|
||||
set_hparams()
|
||||
from deployment.exporters import DiffSingerVarianceExporter
|
||||
print(f'| Exporter: {DiffSingerVarianceExporter}')
|
||||
exporter = DiffSingerVarianceExporter(
|
||||
device=torch.device('cuda' if torch.cuda.is_available() else 'cpu'),
|
||||
cache_dir=root_dir / 'deployment' / 'cache',
|
||||
ckpt_steps=ckpt,
|
||||
freeze_glide=freeze_glide,
|
||||
freeze_expr=freeze_expr,
|
||||
export_spk=export_spk_mix,
|
||||
freeze_spk=freeze_spk_mix
|
||||
)
|
||||
try:
|
||||
exporter.export(out)
|
||||
except KeyboardInterrupt:
|
||||
exit(-1)
|
||||
|
||||
|
||||
@main.command(help='Export NSF-HiFiGAN vocoder model to ONNX format.')
|
||||
@click.option(
|
||||
'--config', type=click.Path(
|
||||
exists=True, file_okay=True, dir_okay=False, readable=True,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
required=True,
|
||||
help='Specify a configuration file for the vocoder.'
|
||||
)
|
||||
@click.option(
|
||||
'--ckpt', type=click.Path(
|
||||
exists=True, file_okay=True, dir_okay=False, readable=True,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
required=False,
|
||||
help='Specify a model path of the vocoder checkpoint.'
|
||||
)
|
||||
@click.option(
|
||||
'--out', type=click.Path(
|
||||
dir_okay=True, file_okay=False,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
required=False,
|
||||
help='Output directory for the artifacts.'
|
||||
)
|
||||
@click.option(
|
||||
'--name', type=click.STRING,
|
||||
required=False, default='nsf_hifigan', show_default=False,
|
||||
help='Specify filename (without suffix) of the target model file.'
|
||||
)
|
||||
def nsf_hifigan(
|
||||
config: pathlib.Path,
|
||||
ckpt: pathlib.Path = None,
|
||||
out: pathlib.Path = None,
|
||||
name: str = None
|
||||
):
|
||||
# Check arguments
|
||||
if out is None:
|
||||
out = root_dir / 'artifacts' / 'nsf_hifigan'
|
||||
|
||||
# Load configurations
|
||||
set_hparams(config.as_posix())
|
||||
if ckpt is None:
|
||||
model_path = pathlib.Path(hparams['vocoder_ckpt']).resolve()
|
||||
else:
|
||||
model_path = ckpt
|
||||
|
||||
# Export artifacts
|
||||
from deployment.exporters import NSFHiFiGANExporter
|
||||
print(f'| Exporter: {NSFHiFiGANExporter}')
|
||||
exporter = NSFHiFiGANExporter(
|
||||
device=torch.device('cuda' if torch.cuda.is_available() else 'cpu'),
|
||||
cache_dir=root_dir / 'deployment' / 'cache',
|
||||
model_path=model_path,
|
||||
model_name=name
|
||||
)
|
||||
try:
|
||||
exporter.export(out)
|
||||
except KeyboardInterrupt:
|
||||
exit(-1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,381 @@
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
from typing import Tuple
|
||||
|
||||
root_dir = Path(__file__).resolve().parent.parent
|
||||
os.environ['PYTHONPATH'] = str(root_dir)
|
||||
sys.path.insert(0, str(root_dir))
|
||||
|
||||
|
||||
def find_exp(exp):
|
||||
if not (root_dir / 'checkpoints' / exp).exists():
|
||||
for subdir in (root_dir / 'checkpoints').iterdir():
|
||||
if not subdir.is_dir():
|
||||
continue
|
||||
if subdir.name.startswith(exp):
|
||||
print(f'| match ckpt by prefix: {subdir.name}')
|
||||
exp = subdir.name
|
||||
break
|
||||
else:
|
||||
raise click.BadParameter(
|
||||
f'There are no matching exp starting with \'{exp}\' in \'checkpoints\' folder. '
|
||||
'Please specify \'--exp\' as the folder name or prefix.'
|
||||
)
|
||||
else:
|
||||
print(f'| found ckpt by name: {exp}')
|
||||
return exp
|
||||
|
||||
|
||||
@click.group()
|
||||
def main():
|
||||
pass
|
||||
|
||||
|
||||
@main.command(help='Run DiffSinger acoustic model inference')
|
||||
@click.argument(
|
||||
'proj', type=click.Path(
|
||||
exists=True, file_okay=True, dir_okay=False, readable=True,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
metavar='DS_FILE'
|
||||
)
|
||||
@click.option(
|
||||
'--exp', type=str,
|
||||
required=True, metavar='EXP',
|
||||
callback=lambda ctx, param, value: find_exp(value),
|
||||
help='Selection of model'
|
||||
)
|
||||
@click.option(
|
||||
'--ckpt', type=click.IntRange(min=0),
|
||||
required=False, metavar='STEPS',
|
||||
help='Selection of checkpoint training steps'
|
||||
)
|
||||
@click.option(
|
||||
'--spk', type=click.STRING,
|
||||
required=False,
|
||||
help='Speaker name or mixture of speakers'
|
||||
)
|
||||
@click.option(
|
||||
'--lang', type=click.STRING,
|
||||
required=False,
|
||||
help='Default language name'
|
||||
)
|
||||
@click.option(
|
||||
'--out', type=click.Path(
|
||||
file_okay=False, dir_okay=True, path_type=pathlib.Path
|
||||
),
|
||||
required=False,
|
||||
help='Path of the output folder'
|
||||
)
|
||||
@click.option(
|
||||
'--title', type=click.STRING,
|
||||
required=False,
|
||||
help='Title of output file'
|
||||
)
|
||||
@click.option(
|
||||
'--num', type=click.IntRange(min=1),
|
||||
required=False, default=1,
|
||||
help='Number of runs'
|
||||
)
|
||||
@click.option(
|
||||
'--key', type=click.INT,
|
||||
required=False, default=0,
|
||||
help='Key transition of pitch'
|
||||
)
|
||||
@click.option(
|
||||
'--gender', type=click.FloatRange(min=-1, max=1),
|
||||
required=False,
|
||||
help='Formant shifting (gender control)'
|
||||
)
|
||||
@click.option(
|
||||
'--seed', type=click.INT,
|
||||
required=False, default=-1,
|
||||
help='Random seed of the inference'
|
||||
)
|
||||
@click.option(
|
||||
'--depth', type=click.FloatRange(min=0, max=1),
|
||||
required=False,
|
||||
help='Shallow diffusion depth'
|
||||
)
|
||||
@click.option(
|
||||
'--steps', type=click.IntRange(min=1),
|
||||
required=False,
|
||||
help='Diffusion sampling steps'
|
||||
)
|
||||
@click.option(
|
||||
'--mel', is_flag=True,
|
||||
help='Save intermediate mel format instead of waveform'
|
||||
)
|
||||
def acoustic(
|
||||
proj: pathlib.Path,
|
||||
exp: str,
|
||||
ckpt: int,
|
||||
spk: str,
|
||||
lang: str,
|
||||
out: pathlib.Path,
|
||||
title: str,
|
||||
num: int,
|
||||
key: int,
|
||||
gender: float,
|
||||
seed: int,
|
||||
depth: float,
|
||||
steps: int,
|
||||
mel: bool
|
||||
):
|
||||
name = proj.stem if not title else title
|
||||
if out is None:
|
||||
out = proj.parent
|
||||
|
||||
with open(proj, 'r', encoding='utf-8') as f:
|
||||
params = json.load(f)
|
||||
|
||||
if not isinstance(params, list):
|
||||
params = [params]
|
||||
|
||||
if len(params) == 0:
|
||||
print('The input file is empty.')
|
||||
exit()
|
||||
|
||||
from utils.infer_utils import trans_key, parse_commandline_spk_mix
|
||||
|
||||
if key != 0:
|
||||
params = trans_key(params, key)
|
||||
key_suffix = '%+dkey' % key
|
||||
if not title:
|
||||
name += key_suffix
|
||||
print(f'| key transition: {key:+d}')
|
||||
|
||||
sys.argv = [
|
||||
sys.argv[0],
|
||||
'--exp_name',
|
||||
exp,
|
||||
'--infer'
|
||||
]
|
||||
from utils.hparams import set_hparams, hparams
|
||||
set_hparams()
|
||||
|
||||
# Check for vocoder path
|
||||
assert mel or (root_dir / hparams['vocoder_ckpt']).exists(), \
|
||||
f'Vocoder ckpt \'{hparams["vocoder_ckpt"]}\' not found. ' \
|
||||
f'Please put it to the checkpoints directory to run inference.'
|
||||
|
||||
# For compatibility:
|
||||
# migrate timesteps, K_step, K_step_infer, diff_speedup to time_scale_factor, T_start, T_start_infer, sampling_steps
|
||||
if 'diff_speedup' not in hparams and 'pndm_speedup' in hparams:
|
||||
hparams['diff_speedup'] = hparams['pndm_speedup']
|
||||
if 'T_start' not in hparams:
|
||||
hparams['T_start'] = 1 - hparams['K_step'] / hparams['timesteps']
|
||||
if 'T_start_infer' not in hparams:
|
||||
hparams['T_start_infer'] = 1 - hparams['K_step_infer'] / hparams['timesteps']
|
||||
if 'sampling_steps' not in hparams:
|
||||
if hparams['use_shallow_diffusion']:
|
||||
hparams['sampling_steps'] = hparams['K_step_infer'] // hparams['diff_speedup']
|
||||
else:
|
||||
hparams['sampling_steps'] = hparams['timesteps'] // hparams['diff_speedup']
|
||||
if 'time_scale_factor' not in hparams:
|
||||
hparams['time_scale_factor'] = hparams['timesteps']
|
||||
|
||||
if depth is not None:
|
||||
assert depth <= 1 - hparams['T_start'], (
|
||||
f"Depth should not be larger than 1 - T_start ({1 - hparams['T_start']})"
|
||||
)
|
||||
hparams['K_step_infer'] = round(hparams['timesteps'] * depth)
|
||||
hparams['T_start_infer'] = 1 - depth
|
||||
if steps is not None:
|
||||
if hparams['use_shallow_diffusion']:
|
||||
step_size = (1 - hparams['T_start_infer']) / steps
|
||||
if 'K_step_infer' in hparams:
|
||||
hparams['diff_speedup'] = round(step_size * hparams['K_step_infer'])
|
||||
else:
|
||||
if 'timesteps' in hparams:
|
||||
hparams['diff_speedup'] = round(hparams['timesteps'] / steps)
|
||||
hparams['sampling_steps'] = steps
|
||||
|
||||
spk_mix = parse_commandline_spk_mix(spk) if hparams['use_spk_id'] and spk is not None else None
|
||||
for param in params:
|
||||
if gender is not None and hparams['use_key_shift_embed']:
|
||||
param['gender'] = gender
|
||||
if spk_mix is not None:
|
||||
param['spk_mix'] = spk_mix
|
||||
if lang is not None:
|
||||
param['lang'] = lang
|
||||
|
||||
from inference.ds_acoustic import DiffSingerAcousticInfer
|
||||
infer_ins = DiffSingerAcousticInfer(load_vocoder=not mel, ckpt_steps=ckpt)
|
||||
print(f'| Model: {type(infer_ins.model)}')
|
||||
|
||||
try:
|
||||
infer_ins.run_inference(
|
||||
params, out_dir=out, title=name, num_runs=num,
|
||||
spk_mix=spk_mix, seed=seed, save_mel=mel
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
exit(-1)
|
||||
|
||||
|
||||
@main.command(help='Run DiffSinger variance model inference')
|
||||
@click.argument(
|
||||
'proj', type=click.Path(
|
||||
exists=True, file_okay=True, dir_okay=False, readable=True,
|
||||
path_type=pathlib.Path, resolve_path=True
|
||||
),
|
||||
metavar='DS_FILE'
|
||||
)
|
||||
@click.option(
|
||||
'--exp', type=str,
|
||||
required=True, metavar='EXP',
|
||||
callback=lambda ctx, param, value: find_exp(value),
|
||||
help='Selection of model'
|
||||
)
|
||||
@click.option(
|
||||
'--ckpt', type=click.IntRange(min=0),
|
||||
required=False, metavar='STEPS',
|
||||
help='Selection of checkpoint training steps'
|
||||
)
|
||||
@click.option(
|
||||
'--predict', type=click.STRING,
|
||||
multiple=True, metavar='TAGS',
|
||||
help='Parameters to predict'
|
||||
)
|
||||
@click.option(
|
||||
'--spk', type=click.STRING,
|
||||
required=False,
|
||||
help='Speaker name or mixture of speakers'
|
||||
)
|
||||
@click.option(
|
||||
'--lang', type=click.STRING,
|
||||
required=False,
|
||||
help='Default language name'
|
||||
)
|
||||
@click.option(
|
||||
'--out', type=click.Path(
|
||||
file_okay=False, dir_okay=True, path_type=pathlib.Path
|
||||
),
|
||||
required=False,
|
||||
help='Path of the output folder'
|
||||
)
|
||||
@click.option(
|
||||
'--title', type=click.STRING,
|
||||
required=False,
|
||||
help='Title of output file'
|
||||
)
|
||||
@click.option(
|
||||
'--num', type=click.IntRange(min=1),
|
||||
required=False, default=1,
|
||||
help='Number of runs'
|
||||
)
|
||||
@click.option(
|
||||
'--key', type=click.INT,
|
||||
required=False, default=0,
|
||||
help='Key transition of pitch'
|
||||
)
|
||||
@click.option(
|
||||
'--expr', type=click.FloatRange(min=0, max=1),
|
||||
required=False, help='Static expressiveness control'
|
||||
)
|
||||
@click.option(
|
||||
'--seed', type=click.INT,
|
||||
required=False, default=-1,
|
||||
help='Random seed of the inference'
|
||||
)
|
||||
@click.option(
|
||||
'--steps', type=click.IntRange(min=1),
|
||||
required=False,
|
||||
help='Diffusion sampling steps'
|
||||
)
|
||||
def variance(
|
||||
proj: pathlib.Path,
|
||||
exp: str,
|
||||
ckpt: int,
|
||||
spk: str,
|
||||
lang: str,
|
||||
predict: Tuple[str],
|
||||
out: pathlib.Path,
|
||||
title: str,
|
||||
num: int,
|
||||
key: int,
|
||||
expr: float,
|
||||
seed: int,
|
||||
steps: int
|
||||
):
|
||||
name = proj.stem if not title else title
|
||||
if out is None:
|
||||
out = proj.parent
|
||||
if (not out or out.resolve() == proj.parent.resolve()) and not title:
|
||||
name += '_variance'
|
||||
|
||||
with open(proj, 'r', encoding='utf-8') as f:
|
||||
params = json.load(f)
|
||||
|
||||
if not isinstance(params, list):
|
||||
params = [params]
|
||||
params = [OrderedDict(p) for p in params]
|
||||
|
||||
if len(params) == 0:
|
||||
print('The input file is empty.')
|
||||
exit()
|
||||
|
||||
from utils.infer_utils import trans_key, parse_commandline_spk_mix
|
||||
|
||||
if key != 0:
|
||||
params = trans_key(params, key)
|
||||
key_suffix = '%+dkey' % key
|
||||
if not title:
|
||||
name += key_suffix
|
||||
print(f'| key transition: {key:+d}')
|
||||
|
||||
sys.argv = [
|
||||
sys.argv[0],
|
||||
'--exp_name',
|
||||
exp,
|
||||
'--infer'
|
||||
]
|
||||
from utils.hparams import set_hparams, hparams
|
||||
set_hparams()
|
||||
|
||||
# For compatibility:
|
||||
# migrate timesteps, K_step, K_step_infer, diff_speedup to time_scale_factor, T_start, T_start_infer, sampling_steps
|
||||
if 'diff_speedup' not in hparams and 'pndm_speedup' in hparams:
|
||||
hparams['diff_speedup'] = hparams['pndm_speedup']
|
||||
if 'sampling_steps' not in hparams:
|
||||
hparams['sampling_steps'] = hparams['timesteps'] // hparams['diff_speedup']
|
||||
if 'time_scale_factor' not in hparams:
|
||||
hparams['time_scale_factor'] = hparams['timesteps']
|
||||
|
||||
if steps is not None:
|
||||
if 'timesteps' in hparams:
|
||||
hparams['diff_speedup'] = round(hparams['timesteps'] / steps)
|
||||
hparams['sampling_steps'] = steps
|
||||
|
||||
spk_mix = parse_commandline_spk_mix(spk) if hparams['use_spk_id'] and spk is not None else None
|
||||
for param in params:
|
||||
if expr is not None:
|
||||
param['expr'] = expr
|
||||
if spk_mix is not None:
|
||||
param['ph_spk_mix_backup'] = param.get('ph_spk_mix')
|
||||
param['spk_mix_backup'] = param.get('spk_mix')
|
||||
param['ph_spk_mix'] = param['spk_mix'] = spk_mix
|
||||
if lang is not None:
|
||||
param['lang'] = lang
|
||||
|
||||
from inference.ds_variance import DiffSingerVarianceInfer
|
||||
infer_ins = DiffSingerVarianceInfer(ckpt_steps=ckpt, predictions=set(predict))
|
||||
print(f'| Model: {type(infer_ins.model)}')
|
||||
|
||||
try:
|
||||
infer_ins.run_inference(
|
||||
params, out_dir=out, title=name,
|
||||
num_runs=num, seed=seed
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
exit(-1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,31 @@
|
||||
import importlib
|
||||
import os
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
root_dir = Path(__file__).parent.parent.resolve()
|
||||
os.environ['PYTHONPATH'] = str(root_dir)
|
||||
sys.path.insert(0, str(root_dir))
|
||||
|
||||
os.environ['TORCH_CUDNN_V8_API_ENABLED'] = '1' # Prevent unacceptable slowdowns when using 16 precision
|
||||
|
||||
from utils.hparams import set_hparams, hparams
|
||||
|
||||
set_hparams()
|
||||
if not hparams['nccl_p2p']:
|
||||
print("Disabling NCCL P2P")
|
||||
os.environ['NCCL_P2P_DISABLE'] = '1'
|
||||
|
||||
|
||||
def run_task():
|
||||
assert hparams['task_cls'] != ''
|
||||
pkg = ".".join(hparams["task_cls"].split(".")[:-1])
|
||||
cls_name = hparams["task_cls"].split(".")[-1]
|
||||
task_cls = getattr(importlib.import_module(pkg), cls_name)
|
||||
|
||||
task_cls.start()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_task()
|
||||
@@ -0,0 +1,90 @@
|
||||
# coding=utf8
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
root_dir = pathlib.Path(__file__).parent.parent.resolve()
|
||||
os.environ['PYTHONPATH'] = str(root_dir)
|
||||
sys.path.insert(0, str(root_dir))
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
import tqdm
|
||||
|
||||
from inference.ds_acoustic import DiffSingerAcousticInfer
|
||||
from utils.infer_utils import cross_fade, save_wav
|
||||
from utils.hparams import set_hparams, hparams
|
||||
|
||||
parser = argparse.ArgumentParser(description='Run DiffSinger vocoder')
|
||||
parser.add_argument('mel', type=str, help='Path to the input file')
|
||||
parser.add_argument('--exp', type=str, required=False, help='Read vocoder class and path from chosen experiment')
|
||||
parser.add_argument('--config', type=str, required=False, help='Read vocoder class and path from config file')
|
||||
parser.add_argument('--class', type=str, required=False, help='Specify vocoder class')
|
||||
parser.add_argument('--ckpt', type=str, required=False, help='Specify vocoder checkpoint path')
|
||||
parser.add_argument('--out', type=str, required=False, help='Path of the output folder')
|
||||
parser.add_argument('--title', type=str, required=False, help='Title of output file')
|
||||
args = parser.parse_args()
|
||||
|
||||
mel = pathlib.Path(args.mel)
|
||||
name = mel.stem if not args.title else args.title
|
||||
config = None
|
||||
if args.exp:
|
||||
config = root_dir / 'checkpoints' / args.exp / 'config.yaml'
|
||||
elif args.config:
|
||||
config = pathlib.Path(args.config)
|
||||
else:
|
||||
assert False, 'Either argument \'--exp\' or \'--config\' should be specified.'
|
||||
|
||||
sys.argv = [
|
||||
sys.argv[0],
|
||||
'--config',
|
||||
str(config)
|
||||
]
|
||||
set_hparams(print_hparams=False)
|
||||
|
||||
cls = getattr(args, 'class')
|
||||
if cls:
|
||||
hparams['vocoder'] = cls
|
||||
if args.ckpt:
|
||||
hparams['vocoder_ckpt'] = args.ckpt
|
||||
|
||||
|
||||
out = args.out
|
||||
if args.out:
|
||||
out = pathlib.Path(args.out)
|
||||
else:
|
||||
out = mel.parent
|
||||
|
||||
mel_seq = torch.load(mel)
|
||||
assert isinstance(mel_seq, list), 'Not a valid mel sequence.'
|
||||
assert len(mel_seq) > 0, 'Mel sequence is empty.'
|
||||
|
||||
sample_rate = hparams['audio_sample_rate']
|
||||
infer_ins = DiffSingerAcousticInfer(load_model=False)
|
||||
|
||||
|
||||
def run_vocoder(path: pathlib.Path):
|
||||
result = np.zeros(0)
|
||||
current_length = 0
|
||||
|
||||
for seg_mel in tqdm.tqdm(mel_seq, desc='mel segment', total=len(mel_seq)):
|
||||
seg_audio = infer_ins.run_vocoder(seg_mel['mel'].to(infer_ins.device), f0=seg_mel['f0'].to(infer_ins.device))
|
||||
seg_audio = seg_audio.squeeze(0).cpu().numpy()
|
||||
silent_length = round(seg_mel['offset'] * sample_rate) - current_length
|
||||
if silent_length >= 0:
|
||||
result = np.append(result, np.zeros(silent_length))
|
||||
result = np.append(result, seg_audio)
|
||||
else:
|
||||
result = cross_fade(result, seg_audio, current_length + silent_length)
|
||||
current_length = current_length + silent_length + seg_audio.shape[0]
|
||||
|
||||
print(f'| save audio: {path}')
|
||||
save_wav(result, path, sample_rate)
|
||||
|
||||
|
||||
os.makedirs(out, exist_ok=True)
|
||||
try:
|
||||
run_vocoder(out / (name + '.wav'))
|
||||
except KeyboardInterrupt:
|
||||
exit(-1)
|
||||
Reference in New Issue
Block a user