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

156 lines
5.3 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.
import csv
import os
from .utils import default_candidates, gbs_default_candidates
class AutoTuner:
"""
The AutoTuner can automatically provide running task based on user-defined settings
and the task will be launched for execution.
Args:
tuner_cfg (dict): The configuration of auto tuner user defined.
"""
def __init__(self, tuner_cfg):
self.cur_task_id = 1
self.task_limit = tuner_cfg.get("task_limit", 100)
search_algo = tuner_cfg.get("search_algo", {"name": "grid"})["name"]
if search_algo == "grid":
from .search import GridSearch
tuner_cfg["candidates"] = default_candidates(tuner_cfg)
self.algo = GridSearch(tuner_cfg)
elif search_algo == "dp_estimation":
from .search import DpEstimationSearch
tuner_cfg["candidates"] = default_candidates(tuner_cfg)
self.algo = DpEstimationSearch(tuner_cfg)
elif search_algo == "gbs":
from .search import GBSSearch
tuner_cfg["candidates"] = gbs_default_candidates(tuner_cfg)
self.algo = GBSSearch(tuner_cfg)
elif search_algo == "customize":
from .search import CustomizeSearch
self.algo = CustomizeSearch(tuner_cfg)
else:
raise NotImplementedError
self.history_cfgs = []
self.resume_cfgs = []
self.tuner_cfg = tuner_cfg
def search_once(self):
"""Return a new task config."""
if self.cur_task_id > self.task_limit:
return None
new_cfg = self.algo.search_once(self.history_cfgs)
self.cur_task_id += 1
return new_cfg
def add_cfg(self, cfg):
"""Add cfg into history cfgs"""
self.history_cfgs.append(cfg)
def resume_form_history(self, history_csv_path="./history.csv"):
"""Resume form history csv file"""
# The breakpoint resume function does not start when the resume csv file does not exist.
if not os.path.exists(history_csv_path):
return
resume_csv_path = os.path.join(
os.path.dirname(history_csv_path),
f'{os.path.basename(history_csv_path).split(".")[0]}_copy.csv',
)
with open(history_csv_path, "r") as fread:
reader = csv.reader(fread)
data_list = list(reader)
with open(resume_csv_path, "w") as fwrite:
writer = csv.writer(fwrite)
for row in data_list:
writer.writerow(row)
# chang str type to real type
for row in data_list:
for i, value in enumerate(row):
try:
row[i] = int(value)
except ValueError:
try:
row[i] = float(value)
except ValueError:
pass
data_dict = []
keys = data_list[0]
values = data_list[1:]
for val in values:
val = [x if x != '' else None for x in val]
val = [True if x == 'True' else x for x in val]
val = [False if x == 'False' else x for x in val]
dictionary = dict(zip(keys, val))
time_val = -1
target_key = self.tuner_cfg["metric_cfg"]["name"]
if dictionary[target_key]:
time_val = dictionary[target_key]
dictionary["time"] = time_val
data_dict.append(dictionary)
self.resume_cfgs = data_dict
def get_cfg_from_resume(self, cur_cfg):
"""Get cfg from resume cfgs"""
keys_to_compare = [
'mp_degree',
'sharding_degree',
'pp_degree',
'dp_degree',
'sharding_stage',
'micro_batch_size',
'vpp_degree',
'use_recompute',
'recompute_granularity',
'num_gpus',
'nodes',
'global_batch_size',
'sharding_overlap',
'acc_steps',
]
if self.tuner_cfg.get("refined_recompute", None):
for rr in self.tuner_cfg["refined_recompute"]:
keys_to_compare.append(rr)
if self.tuner_cfg.get("custom_search_dim", None):
for key in self.tuner_cfg["custom_search_dim"]:
keys_to_compare.append(key)
for cfg in self.resume_cfgs:
ret_is_same = True
for key in keys_to_compare:
if not cfg.get(key) and not cur_cfg.get(key):
continue
else:
is_same = str(cfg.get(key)) == str(cur_cfg.get(key))
ret_is_same = ret_is_same and is_same
if ret_is_same:
return cfg
return None