blob: 8b32fab3df4112fb95b85ea8b60c0c16cdfcb4ac [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
from copy import copy
from src.search_space.core.space import SpaceWrapper
from src.common.constant import Config
from src.eva_engine.phase2.evaluator import P2Evaluator
# UniformAllocation
class UniformAllocation:
def __init__(self,
search_space_ins: SpaceWrapper, dataset_name: str,
eta, time_per_epoch, args=None):
self.is_simulate = True
self._evaluator = P2Evaluator(search_space_ins,
dataset_name,
is_simulate=True,
train_loader=None,
val_loader=None,
args=None)
self.eta = eta
self.max_unit_per_model = args.epoch
self.time_per_epoch = time_per_epoch
self.name = "UNIFORM"
def schedule_budget_per_model_based_on_T(self, space_name, fixed_time_budget, K_):
# for benchmarking only phase 2
# try different K and U combinations
# only consider 15625 arches in this paper
# min_budget_required: when K = 1, N = min_budget_required * 1
if space_name == Config.NB101:
U_options = [4, 12, 16, 108]
else:
U_options = list(range(1, 200))
history = []
for U in U_options:
expected_time_used = self.pre_calculate_epoch_required(K_, U) * self.time_per_epoch
if expected_time_used > fixed_time_budget:
break
else:
history.append(U)
return history[-1]
def pre_calculate_epoch_required(self, K, U, eta: int=3, max_unit_per_model: int=200):
"""
:param B: total budget for phase 2
:param U: mini unit computation for each modle
:param candidates_m:
:return:
"""
return K * U
def run_phase2(self, U: int, candidates_m: list):
"""
:param U: mini unit computation for each modle
:param candidates_m:
:return:
"""
# print(f" *********** begin uniformly_allocate with U={U}, K={len(candidates_m)} ***********")
candidates = copy(candidates_m)
min_budget_required = 0
# todo: this is to run the full training, when compute full traiing
# U = self.max_unit_per_model
if U >= self.max_unit_per_model:
U = self.max_unit_per_model
# print(f"[uniformly_allocate]: uniformly allocate {U} epoch to each model")
total_time = 0
total_score = []
for cand in candidates:
score, time_usage = self._evaluator.p2_evaluate(cand, U)
total_time += time_usage
total_score.append((cand, score))
min_budget_required += U
# sort from min to max
scored_cand = sorted(total_score, key=lambda x: x[1])
candidate = scored_cand[-1][0]
best_perform, _ = self._evaluator.p2_evaluate(candidate, self.max_unit_per_model)
return candidate, best_perform, min_budget_required, total_time