예제 #1
0
class Sampling(object):
    """This class is used to determine next sample and objective
    """
    def __init__(self, o1_ind, o2_ind, o1_cost, o2_cost):
        print("[STATUS]: Initializing Sample Class")
        self.O1_IND = o1_ind
        self.O2_IND = o2_ind
        self.NUM_OBJ = 2
        self.O1_COST = o1_cost
        self.O2_COST = o2_cost
        self.utils = Utils(o1_ind, o2_ind)

    def determine_next_sample(self, pess_pareto, opt_pareto, pess_indices_map,
                              opt_indices_map, pess_pareto_volume,
                              opt_pareto_volume, REGION, E):
        """@DETERMINE_NEXT_SAMPLE
        ------------------------------------------------------------------------
        This function is used to determine next sample
        ------------------------------------------------------------------------
        """
        if pess_indices_map == opt_indices_map:
            indices_map = pess_indices_map
        pess_ind = [indices_map[i] for i in range(0, len(pess_pareto))]
        opt_ind = [indices_map[i] for i in range(0, len(opt_pareto))]

        pess_status = [[{
            "pess": True,
            "opt": True
        }] if i in opt_ind else [{
            "pess": True,
            "opt": False
        }] for i in pess_ind]
        opt_status = [[{
            "pess": True,
            "opt": True
        }] if i in pess_ind else [{
            "pess": False,
            "opt": True
        }] for i in opt_ind]

        #-----------------------------------------------------------------------
        # compute dv/c for each point in pessimistic pareto front
        #-----------------------------------------------------------------------
        dv_per_cost_pess = [{"o1": 0, "o2": 0} for i in pess_ind]
        for i in range(0, len(pess_pareto)):
            for j in range(0, self.NUM_OBJ):
                # Update pessimistic pareto front shring pess to avg
                if pess_status[i][0]["pess"] is True:
                    cur_pess = pess_pareto[:]
                    # replace pess with avg value across O1
                    cur_pess[i][j] = REGION[pess_ind[i]]["avg"][j]
                    cur_pess_pareto = self.utils.construct_pessimistic_pareto_front(
                        pess_ind, cur_pess, "UPDATE")
                    cur_pess_volume = self.utils.compute_pareto_volume(
                        cur_pess_pareto)

                # Update optimistic pareto front shring pess to avg
                if pess_status[i][0]["opt"] is True:
                    cur_opt = opt_pareto[:]
                    opt_i = opt_ind.index(pess_ind[i])
                    # replace opt with avg value across O1
                    cur_opt[opt_i][j] = REGION[opt_ind[i]]["avg"][j]
                    cur_opt_pareto = self.utils.construct_optimistic_pareto_front(
                        opt_ind, cur_opt, "UPDATE")
                    cur_opt_volume = self.utils.compute_pareto_volume(
                        cur_opt_pareto)

                # Shrinking of pessimistic pareto points do not change optimistic
                # pareto front
                if pess_status[i][0]["opt"] is False:
                    cur_opt_volume = opt_pareto_volume

                dv = (opt_pareto_volume -
                      pess_pareto_volume) - (cur_opt_volume - cur_pess_volume)
                if j == self.O1_IND:
                    dv_per_cost_pess[i]["o1"] = dv / self.O1_COST
                if j == self.O2_IND:
                    dv_per_cost_pess[i]["o2"] = dv / self.O2_COST
        #-----------------------------------------------------------------------
        # compute dv/c for each point in optimistic pareto front
        #-----------------------------------------------------------------------
        dv_per_cost_opt = [{"o1": 0, "o2": 0} for i in opt_ind]
        for i in range(0, len(opt_pareto)):
            for j in range(0, self.NUM_OBJ):
                # Update optimistic pareto front shring opt to avg. Similar points
                # both in pess and opt pareto fronts are already covered in
                # pessimistic pareto front update computation
                if (opt_status[i][0]["opt"] is True
                        and opt_status[i][0]["opt"] is False):

                    cur_opt = opt_pareto[:]
                    # replace pess with avg value across O1
                    cur_opt[i][j] = REGION[opt_ind[i]]["avg"][j]
                    cur_opt_pareto = self.utils.construct_optimistic_pareto_front(
                        opt_ind, cur_opt, "UPDATE")
                    cur_opt_volume = self.utils.compute_pareto_volume(
                        cur_opt_pareto)
                    # Shrinking of optimistic pareto points do not change pessimistic
                    # pareto front
                    cur_pess_volume = pess_pareto_volume

                # Compute dv per cost for each objective
                dv = (opt_pareto_volume -
                      pess_pareto_volume) - (cur_opt_volume - cur_pess_volume)
                if j == self.O1_IND:
                    dv_per_cost_opt[i]["o1"] = dv / self.O1_COST
                if j == self.O2_IND:
                    dv_per_cost_opt[i]["o2"] = dv / self.O2_COST
        #-----------------------------------------------------------------------
        # Compute max dv per cost to determine the next sample and objective
        #-----------------------------------------------------------------------
        max_dv_per_cost = 0
        objective = "o1"

        # Compute max dv per cost from pessimistic pareto points
        for i in range(0, len(dv_per_cost_pess)):
            if abs(dv_per_cost_pess[i]["o1"]) >= max_dv_per_cost:
                max_dv_per_cost_ind = i
                max_dv_per_cost = abs(dv_per_cost_pess[i]["o1"])
                objective = "o1"
            if abs(dv_per_cost_pess[i]["o2"]) >= max_dv_per_cost:
                max_dv_per_cost_ind = i
                max_dv_per_cost = abs(dv_per_cost_pess[i]["o2"])
                objective = "o2"
        cur_dv_per_cost_ind = indices_map[max_dv_per_cost_ind]

        # Compute max dv per cost from optimistic pareto points
        for i in range(0, len(dv_per_cost_opt)):
            if abs(dv_per_cost_opt[i]["o1"]) >= max_dv_per_cost:
                max_dv_per_cost_ind = i
                max_dv_per_cost = abs(dv_per_cost_pess[i]["o1"])
                objective = "o1"
            if abs(dv_per_cost_opt[i]["o2"]) >= max_dv_per_cost:
                max_dv_per_cost_ind = i
                max_dv_per_cost = abs(dv_per_cost_pess[i]["o2"])
                objective = "o2"

        # Compute next sample
        cur_dv_per_cost_ind = indices_map[max_dv_per_cost_ind]

        next_sample = E[cur_dv_per_cost_ind]
        return (cur_dv_per_cost_ind, next_sample, objective)
예제 #2
0
class FlexiBO(object):
    """This class is used to implement an active learning approach to optimize
    multiple objectives of different cost
    E: design space
    O: evaluated objectives
    n: number of objectives
    m1: objective 1
    m2: objective 2
    """
    def __init__(self, data, surrogate):
        print("Initializing FlexiBO class")

        self.df = data
        with open("config.yaml", "r") as fp:
            config = yaml.load(fp)
        cfg = ConfigSpaceReal("hardware", "os",
                              config["config"]["network"]["net"])
        (self.E, self.O, self.measurement) = cfg.set_design_space()
        self.network = config["config"]["network"]["net"]
        self.NUM_ITER = 200
        self.NUM_OBJ = 2
        self.O1_IND = config["config"]["index"]["O1"]
        self.O2_IND = config["config"]["index"]["O2"]
        self.m1 = config["config"]["objective"]["O1"]
        self.m2 = config["config"]["objective"]["O2"]
        self.O1_COST = config["config"]["evaluation_cost"]["O1"]
        self.O2_COST = config["config"]["evaluation_cost"]["O2"]
        self.sampling = Sampling(self.O1_IND, self.O2_IND, self.O1_COST,
                                 self.O2_COST)
        self.utils = Utils(self.O1_IND, self.O2_IND)
        self.surrogate = surrogate
        if self.surrogate == "GP":
            from src.surrogate_model import GPSurrogateModel
            self.SM = GPSurrogateModel()
        else:
            print("[ERROR]: Surrogate model not supported")
        (self.X, self.Y1, self.Y2) = self.prepare_training_data()

        self.perform_bo_loop()

    def prepare_training_data(self):
        """This function is used to prepare training data
        """

        X = self.df[[
            "num_cores", "core_freq", "gpu_freq", "emc_freq", "cache_pressure",
            "swappiness", "dirty_bg", "dirty_ratio", "entry_num_filters",
            "entry_filter_size", "middle_num_filters", "middle_filter_size",
            "exit_filter_size"
        ]].values

        Y1 = self.df[self.m1].values
        Y2 = self.df[self.m2].values
        Y1 = [[i] for i in Y1]
        Y2 = [[i] for i in Y2]

        return (X, Y1, Y2)

    def initialize(self):
        """This function is used to initialize data
        """
        import random
        index = random.sample(range(0, len(self.X) - 1), 20)
        X = [self.X[i] for i in index]
        Y1 = [self.Y1[i] for i in index]
        Y2 = [self.Y2[i] for i in index]
        return (X, Y1, Y2, index)

    def perform_bo_loop(self):
        """This function is used to perform bayesian optimization loop
        U: Design Space
        REGION: Uncertainty Region for each configuration in design space
        """
        # Initialization
        BETA = 1.0
        (init_X, init_Y1, init_Y2, init_measured_indices) = self.initialize()

        for i in range(0, len(init_measured_indices)):
            self.O[i]["o1"] = True
            self.measurement[init_measured_indices[i]]["o1"] = init_Y1[i][0]
            self.O[i]["o2"] = True
            self.measurement[init_measured_indices[i]]["o2"] = init_Y2[i][0]
        (init_X, init_Y1, init_Y2) = (np.array(init_X), np.array(init_Y1),
                                      np.array(init_Y2))

        U = np.array(self.E[:])
        init_X1 = init_X[:]
        init_X2 = init_X[:]

        # bo loop
        for iteration in range(0, self.NUM_ITER):
            print("---------------------------------------Iteration: ",
                  iteration)
            REGION = [{} for _ in U]
            if self.surrogate == "GP":
                # Fit a GP for each objective
                gpr1, gpr2 = self.SM.fit_gp()
                model_o1 = gpr1.fit(init_X1, init_Y1)
                model_o2 = gpr2.fit(init_X2, init_Y2)

            for config in range(0, len(U)):
                # Compute mu and sigma of each points for each objective
                cur = np.array([U[config]])
                cur_eval = self.O[config]
                # Objective 1
                if cur_eval["o1"] is False:
                    if self.surrogate == "GP":
                        mu_o1, sigma_o1 = model_o1.predict(cur,
                                                           return_std=True)

                else:
                    (mu_o1, sigma_o1) = (self.measurement[config]["o1"], 0)

                # Objective 2
                if cur_eval["o2"] is False:
                    if self.surrogate == "GP":
                        mu_o2, sigma_o2 = model_o2.predict(cur,
                                                           return_std=True)
                else:
                    (mu_o2, sigma_o2) = (self.measurement[config]["o2"], 0)

                # Compute uncertainty region for each point using mu and sigma
                REGION[config]["pes"] = [
                    0 if (mu_o1 - math.sqrt(BETA) * sigma_o1) < 0 else mu_o1 -
                    math.sqrt(BETA) * sigma_o1, 0 if
                    (mu_o2 - math.sqrt(BETA) * sigma_o2) < 0 else mu_o2 -
                    math.sqrt(BETA) * sigma_o2
                ]
                REGION[config]["avg"] = [mu_o1, mu_o2]
                REGION[config]["opt"] = [
                    mu_o1 + math.sqrt(BETA) * sigma_o1,
                    mu_o2 + math.sqrt(BETA) * sigma_o2
                ]

            # Determine undominated points
            (undominated_points_ind, undominated_points
             ) = self.utils.identify_undominated_points(REGION)
            # Determine pessimistic pareto front
            (pess_pareto,
             pess_indices_map) = self.utils.construct_pessimistic_pareto_front(
                 undominated_points_ind, undominated_points, "CONSTRUCT")
            # Determine optimistic pareto front
            (opt_pareto,
             opt_indices_map) = self.utils.construct_optimistic_pareto_front(
                 undominated_points_ind, undominated_points, "CONSTRUCT")
            # Determine pessimistic pareto volume
            pess_pareto_volume = self.utils.compute_pareto_volume(pess_pareto)
            # Determine optimistic pareto volume
            opt_pareto_volume = self.utils.compute_pareto_volume(opt_pareto)
            # Determine volume of the pareto front
            volume_of_pareto_front = opt_pareto_volume - pess_pareto_volume
            # Determine next configuration and objective
            (next_sample_index, next_sample,
             objective) = self.sampling.determine_next_sample(
                 pess_pareto, opt_pareto, pess_indices_map, opt_indices_map,
                 pess_pareto_volume, opt_pareto_volume, REGION, self.E)

            # Perform measurement on next sample on the objective returned
            # Update init_X and init_Y

            if objective == "o1":
                # Evaluate Objective O1
                ConfigHardware(next_sample)
                ComputePerformance(fname_model)
                cur_X1 = np.array(next_sample)
                self.O[next_sample_index]["o1"] = True
                self.measurement[next_sample_index]["o1"] = cur_Y1[0]
                np.vstack((init_X1, cur_X1))
                np.vstack((init_Y1, cur_Y1))
            if objective == "o2":
                cur_X2 = np.array(next_sample)
                ConfigNetwork(self.network, next_sample)
                ComputePerformance(fname_model)
                self.O[next_sample_index]["o2"] = True
                self.measurement[next_sample_index]["o2"] = cur_Y2[0]
                np.vstack((init_X2, np.array(next_sample)))
                np.vstack((init_Y2, cur_Y2))