更新并完善分布式训练功能 (#186)

* 修复多机训练问题

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* 更新并完善分布式训练功能

近期融合V2版本代码时发现之前修改的多机功能并不正确,仍会报错,只不过单机多卡情况下local_rank即相当于rank,感知不出
1. 修复train_ms.py中DDP初始化及.cuda绑定到local_rank上
2. 在default_config.yml配置文件中添加env变量 LOCAL_RANK,否则默认情况下会key error
3. 添加run_MnodesAndMgpus.sh,更新分布式相关说明

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Lvjinhong
2023-11-16 13:46:15 +08:00
committed by GitHub
parent 1fbddf4202
commit 31de84eb3b
4 changed files with 80 additions and 27 deletions

View File

@@ -66,6 +66,7 @@ train_ms:
MASTER_ADDR: "localhost" MASTER_ADDR: "localhost"
MASTER_PORT: 10086 MASTER_PORT: 10086
WORLD_SIZE: 1 WORLD_SIZE: 1
LOCAL_RANK: 0
RANK: 0 RANK: 0
# 可以填写任意名的环境变量 # 可以填写任意名的环境变量
# THE_ENV_VAR_YOU_NEED_TO_USE: "1234567" # THE_ENV_VAR_YOU_NEED_TO_USE: "1234567"

View File

@@ -1,7 +0,0 @@
torchrun \
--nnodes=1:3\
--nproc_per_node=2\
--rdzv_id=1\
--rdzv_backend=c10d\
--rdzv_endpoint="ib1:8880"\
train_ms.py

31
run_MnodesAndMgpus.sh Normal file
View File

@@ -0,0 +1,31 @@
#多机多卡训练
#--nnodes=1:3 表示 使用一到三台机器 弹性分配资源
#--nnodes=<最小节点数>:<最大节点数>
#--nproc_per_node=每台机器上可用的GPU数
#--rdzv_endpoint=主节点最先启动的ip:端口号
#其他不需要变
#注意: 此版本的分布式训练是基于数据并行的多机多卡相当于开更大的batchsize此时epoch迭代速度会增加,
#但由于 该版本的代码中 保存模型是按照global step来计算的所以会出现的效果就是 保存模型的时间不会有明显加速,
#但每次保存模型时epoch都比之前迭代了更多次,也就是 “更少的步数,实现更好的效果”
#*************************
# torchrun \
# --nnodes=1:3\
# --nproc_per_node=2\
# --rdzv_id=1\
# --rdzv_backend=c10d\
# --rdzv_endpoint="inspur1:8880"\
# train_ms.py
#****************************
#多卡训练
#nproc_per_node = 机器上可用的GPU数
#*************************
torchrun \
--nnodes=1\
--nproc_per_node=2\
train_ms.py
#*************************

View File

@@ -51,7 +51,17 @@ def run():
envs = config.train_ms_config.env envs = config.train_ms_config.env
for env_name, env_value in envs.items(): for env_name, env_value in envs.items():
if env_name not in os.environ.keys(): if env_name not in os.environ.keys():
print("加载config中的配置{}".format(str(env_value)))
os.environ[env_name] = str(env_value) os.environ[env_name] = str(env_value)
print(
"加载环境变量 \nMASTER_ADDR: {},\nMASTER_PORT: {},\nWORLD_SIZE: {},\nRANK: {},\nLOCAL_RANK: {}".format(
os.environ["MASTER_ADDR"],
os.environ["MASTER_PORT"],
os.environ["WORLD_SIZE"],
os.environ["RANK"],
os.environ["LOCAL_RANK"],
)
)
# 多卡训练设置 # 多卡训练设置
backend = "nccl" backend = "nccl"
@@ -162,7 +172,7 @@ def run():
3, 3,
0.1, 0.1,
gin_channels=hps.model.gin_channels if hps.data.n_speakers != 0 else 0, gin_channels=hps.model.gin_channels if hps.data.n_speakers != 0 else 0,
).cuda(rank) ).cuda(local_rank)
if ( if (
"use_spk_conditioned_encoder" in hps.model.keys() "use_spk_conditioned_encoder" in hps.model.keys()
and hps.model.use_spk_conditioned_encoder is True and hps.model.use_spk_conditioned_encoder is True
@@ -182,9 +192,9 @@ def run():
mas_noise_scale_initial=mas_noise_scale_initial, mas_noise_scale_initial=mas_noise_scale_initial,
noise_scale_delta=noise_scale_delta, noise_scale_delta=noise_scale_delta,
**hps.model, **hps.model,
).cuda(rank) ).cuda(local_rank)
net_d = MultiPeriodDiscriminator(hps.model.use_spectral_norm).cuda(rank) net_d = MultiPeriodDiscriminator(hps.model.use_spectral_norm).cuda(local_rank)
optim_g = torch.optim.AdamW( optim_g = torch.optim.AdamW(
filter(lambda p: p.requires_grad, net_g.parameters()), filter(lambda p: p.requires_grad, net_g.parameters()),
hps.train.learning_rate, hps.train.learning_rate,
@@ -206,11 +216,13 @@ def run():
) )
else: else:
optim_dur_disc = None optim_dur_disc = None
net_g = DDP(net_g, device_ids=[rank]) net_g = DDP(net_g, device_ids=[local_rank])
net_d = DDP(net_d, device_ids=[rank]) net_d = DDP(net_d, device_ids=[local_rank])
dur_resume_lr = None dur_resume_lr = None
if net_dur_disc is not None: if net_dur_disc is not None:
net_dur_disc = DDP(net_dur_disc, device_ids=[rank], find_unused_parameters=True) net_dur_disc = DDP(
net_dur_disc, device_ids=[local_rank], find_unused_parameters=True
)
# 下载底模 # 下载底模
if config.train_ms_config.base["use_base_model"]: if config.train_ms_config.base["use_base_model"]:
@@ -256,6 +268,9 @@ def run():
epoch_str = max(epoch_str, 1) epoch_str = max(epoch_str, 1)
global_step = (epoch_str - 1) * len(train_loader) global_step = (epoch_str - 1) * len(train_loader)
print(
f"******************检测到模型存在epoch为 {epoch_str}gloabl step为 {global_step}*********************"
)
except Exception as e: except Exception as e:
print(e) print(e)
epoch_str = 1 epoch_str = 1
@@ -281,6 +296,7 @@ def run():
if rank == 0: if rank == 0:
train_and_evaluate( train_and_evaluate(
rank, rank,
local_rank,
epoch, epoch,
hps, hps,
[net_g, net_d, net_dur_disc], [net_g, net_d, net_dur_disc],
@@ -294,6 +310,7 @@ def run():
else: else:
train_and_evaluate( train_and_evaluate(
rank, rank,
local_rank,
epoch, epoch,
hps, hps,
[net_g, net_d, net_dur_disc], [net_g, net_d, net_dur_disc],
@@ -311,7 +328,17 @@ def run():
def train_and_evaluate( def train_and_evaluate(
rank, epoch, hps, nets, optims, schedulers, scaler, loaders, logger, writers rank,
local_rank,
epoch,
hps,
nets,
optims,
schedulers,
scaler,
loaders,
logger,
writers,
): ):
net_g, net_d, net_dur_disc = nets net_g, net_d, net_dur_disc = nets
optim_g, optim_d, optim_dur_disc = optims optim_g, optim_d, optim_dur_disc = optims
@@ -327,6 +354,7 @@ def train_and_evaluate(
net_d.train() net_d.train()
if net_dur_disc is not None: if net_dur_disc is not None:
net_dur_disc.train() net_dur_disc.train()
for batch_idx, ( for batch_idx, (
x, x,
x_lengths, x_lengths,
@@ -347,21 +375,21 @@ def train_and_evaluate(
- net_g.module.noise_scale_delta * global_step - net_g.module.noise_scale_delta * global_step
) )
net_g.module.current_mas_noise_scale = max(current_mas_noise_scale, 0.0) net_g.module.current_mas_noise_scale = max(current_mas_noise_scale, 0.0)
x, x_lengths = x.cuda(rank, non_blocking=True), x_lengths.cuda( x, x_lengths = x.cuda(local_rank, non_blocking=True), x_lengths.cuda(
rank, non_blocking=True local_rank, non_blocking=True
) )
spec, spec_lengths = spec.cuda(rank, non_blocking=True), spec_lengths.cuda( spec, spec_lengths = spec.cuda(
rank, non_blocking=True local_rank, non_blocking=True
), spec_lengths.cuda(local_rank, non_blocking=True)
y, y_lengths = y.cuda(local_rank, non_blocking=True), y_lengths.cuda(
local_rank, non_blocking=True
) )
y, y_lengths = y.cuda(rank, non_blocking=True), y_lengths.cuda( speakers = speakers.cuda(local_rank, non_blocking=True)
rank, non_blocking=True tone = tone.cuda(local_rank, non_blocking=True)
) language = language.cuda(local_rank, non_blocking=True)
speakers = speakers.cuda(rank, non_blocking=True) bert = bert.cuda(local_rank, non_blocking=True)
tone = tone.cuda(rank, non_blocking=True) ja_bert = ja_bert.cuda(local_rank, non_blocking=True)
language = language.cuda(rank, non_blocking=True) en_bert = en_bert.cuda(local_rank, non_blocking=True)
bert = bert.cuda(rank, non_blocking=True)
ja_bert = ja_bert.cuda(rank, non_blocking=True)
en_bert = en_bert.cuda(rank, non_blocking=True)
with autocast(enabled=hps.train.fp16_run): with autocast(enabled=hps.train.fp16_run):
( (