Exemplo n.º 1
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):
        print("Initializing FlexiBO class")
        self.utils = Utils()
        self.sample = Sample()
        self.df = data
        cfg = ConfigReal()
        (self.E, self.O, self.measurement) = cfg.set_design_space()

        self.NUM_ITER = 200
        self.NUM_OBJ = 2
        self.O1_IND = 0
        self.O2_IND = 1
        self.m1 = "inference_time"
        self.m2 = "power_consumption"
        self.SM = SurrogateModel()
        (self.X, self.Y1, self.Y2) = self.prepare_training_data()
        self.fit_rf()
        self.perform_bo_loop()

    def fit_rf(self):
        """This function is used to predict 
        """
        self.rf1 = RandomForestRegressor(n_estimators=16)
        self.rf2 = RandomForestRegressor(n_estimators=16)
        self.rf1.fit(self.X, self.Y1)
        self.rf2.fit(self.X, self.Y2)

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

        X = self.df[['number_of_cores', 'core_freq', 'gpu_freq',
                     'emc_freq']].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), 10)
        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[:]
        rbf = ConstantKernel(1.0) * RBF(length_scale=1.0)
        gpr = GaussianProcessRegressor(kernel=rbf, n_restarts_optimizer=9)
        # bo loop
        for iteration in range(0, self.NUM_ITER):
            print("---------------------------------------Iteration: ",
                  iteration)
            REGION = [{} for _ in U]

            # Fit a GP for each objective
            #model_o1=self.SM.fit_gp(init_X1,init_Y1)
            #model_o2=self.SM.fit_gp(init_X2,init_Y2)
            model_o1 = gpr.fit(init_X1, init_Y1)
            model_o2 = gpr.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:
                    #(mu_o1,sigma_o1)=self.SM.get_gp_model_params(model_o1,cur)
                    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:
                    #(mu_o2,sigma_o2)=self.SM.get_gp_model_params(model_o2,cur)
                    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
                ]
            print(REGION)
            """
            REGION=[
                   {'opt': [2, 11], 'avg': [1, 10], 'pes': [0.5,9]},
                   {'opt': [3, 9], 'avg': [2.5, 8], 'pes': [1.5,7]},
                   {'opt': [1.5, 7], 'avg': [1, 6], 'pes': [0.5,5]},
                   {'opt': [5, 6], 'avg': [4.5, 5], 'pes': [4,4]},
                   {'opt': [7.5, 4], 'avg': [6.5, 3], 'pes': [6,2.5]},
                   {'opt': [3.5, 3.5], 'avg': [3, 3], 'pes': [2.5,2.5]},
                   {'opt': [5.5, 3], 'avg': [5, 2], 'pes': [4.5,1.5]}
                   ] 
            """
            # 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.sample.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":
                cur_X1 = np.array(next_sample)
                cur_Y1 = np.array(self.rf1.predict([cur_X1]))
                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)
                cur_Y2 = np.array(self.rf2.predict([cur_X2]))
                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))
Exemplo n.º 2
0
class Sample(object):
    """This class is used to determine next sample and objective
    """
    def __init__(self):
        print("Initializing Sample Class")
        self.O1_IND = 1
        self.O2_IND = 0
        self.NUM_OBJ = 2
        self.O1_COST = 1
        self.O2_COST = 17.6 * self.O1_COST
        self.utils = Utils()

    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_pess[i]["o1"] = dv / self.O1_COST
                if j == self.O2_IND:
                    dv_per_cost_pess[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)