Files
2026-07-13 12:40:42 +08:00

144 lines
4.2 KiB
Python

# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
def all_params(mp, pp, sharding, h, l, V):
# TODO: TBD - add some fixed structure models.
return 1
def full_recompute_acts(mp, pp, s, b, h, l):
# TODO: TBD - add some fixed structure models.
return 1
def all_acts(mp, pp, s, b, h, l, a):
# TODO: TBD - add some fixed structure models.
return 1
def to_gb(p):
return p / (2**30)
def get_mem(total_cards, parallel_cfg, l, h, a, V, s, gbs):
"""Estimate the memory of model unset parallel strategy."""
sharding = parallel_cfg["sharding_degree"]
mp = parallel_cfg["mp_degree"]
b = parallel_cfg["micro_batch_size"]
pp = parallel_cfg["pp_degree"]
vpp = parallel_cfg["vpp_degree"]
use_recompute = parallel_cfg["use_recompute"]
sep = 1
lbs = int(gbs / sharding / s)
lbs = int(lbs / pp) * pp
assert s % sep == 0
s_sep = s // sep
assert a % (sep * mp) == 0, f'{a} vs {sep * mp}'
vpp_ratio = 1
if vpp > 1:
assert l % (pp * vpp) == 0
vpp_ratio = 1 + (pp - 1) / (pp * vpp)
params = to_gb(all_params(mp, pp, sharding, h, l, V))
acts = 0
assert l % pp == 0
if use_recompute:
acts = to_gb(full_recompute_acts(mp, pp, s_sep, b, h, l)) * vpp_ratio
else:
acts = to_gb(all_acts(mp, pp, s, b, h, l, a)) * vpp_ratio
assert acts > 0
peak_mem = params + acts
return peak_mem
def divisor(num, reverse=False):
"""Get the divisor of a given number."""
results = set()
i = 1
mid = num // 2 + 1
while i < mid:
if num % i == 0:
results.add(i)
results.add(num // i)
i += 1
results = list(results)
return sorted(results, reverse=reverse)
def get_not_oom_cfgs(cfgs, tuner_cfg):
"""Get not OOM parallel strategies."""
total_cards, l, h, a, V, s, gbs, per_card_memory = (
tuner_cfg["search_algo"]["estimated_num_gpus"],
tuner_cfg["model_cfg"]["num_layers"],
tuner_cfg["model_cfg"]["hidden_size"],
tuner_cfg["model_cfg"]["num_attention_heads"],
tuner_cfg["model_cfg"]["vocab_size"],
tuner_cfg["model_cfg"]["seq_length"],
tuner_cfg["model_cfg"]["global_batch_size"],
tuner_cfg.get("per_card_memory", 80),
)
pruned_cfgs = []
for cfg in cfgs:
mp = cfg["mp_degree"]
sharding = cfg["sharding_degree"]
mbs = cfg["micro_batch_size"]
pp = cfg["pp_degree"]
vpp = cfg["vpp_degree"]
dp = cfg["dp_degree"]
use_recompute = cfg["use_recompute"]
if mp * sharding * pp * dp != total_cards:
continue
if gbs % sharding != 0:
continue
if gbs // sharding % dp != 0:
continue
if gbs // sharding // dp % mbs != 0:
continue
if l % pp != 0:
continue
if l // pp % vpp != 0:
continue
if vpp != 1 and pp <= 2:
continue
if a % mp != 0 or V % mp != 0 or h % mp != 0:
continue
pruned_cfgs.append(cfg)
valid_cfgs = []
for cfg in pruned_cfgs:
mem = get_mem(total_cards, cfg, l, h, a, V, s, gbs)
# TODO: Uncomment when it is actually implemented.
# if (
# mem < per_card_memory
# and mem
# > tuner_cfg.get(
# "search_algo", {"name": "dp_estimation", "threshold": 0.7}
# ).get("threshold", 0.7)
# * per_card_memory
# ):
# cfg["memory_cost"] = mem
# valid_cfgs.append(cfg)
cfg["memory_cost"] = mem
valid_cfgs.append(cfg)
assert valid_cfgs
return valid_cfgs