Browse Source

enable n objectives for MOEAD

Jérôme BUISINE 3 years ago
parent
commit
6313a6a393
3 changed files with 36 additions and 14 deletions
  1. 2 1
      knapsackMultiExample.py
  2. 24 6
      macop/algorithms/multi/MOEAD.py
  3. 10 7
      macop/operators/policies/UCBPolicy.py

+ 2 - 1
knapsackMultiExample.py

@@ -78,7 +78,8 @@ def main():
     policy = RandomPolicy(operators)
 
     # pass list of evaluators
-    algo = MOEAD(20, 5, init, [evaluator1, evaluator2], operators, policy, validator, _maximise=True)
+    algo = MOEAD(20, 5, init, [evaluator1, evaluator2, evaluator2, evaluator2], operators, policy, validator, _maximise=True)
+    print(algo.weights)
     algo.addCallback(MultiCheckpoint(_every=5, _filepath=mo_checkpoint_path))
     algo.addCallback(ParetoCheckpoint(_every=5, _filepath=pf_checkpoint_path))
 

+ 24 - 6
macop/algorithms/multi/MOEAD.py

@@ -36,15 +36,16 @@ class MOEAD(Algorithm):
     Attributes:
         mu: {int} -- number of sub problems
         T: {[float]} -- number of neightbors for each sub problem
+        nObjectives: {int} -- number of objectives (based of number evaluator)
         initalizer: {function} -- basic function strategy to initialize solution
         evaluator: {[function]} -- list of basic function in order to obtained fitness (multiple objectives)
         operators: {[Operator]} -- list of operator to use when launching algorithm
         policy: {Policy} -- Policy class implementation strategy to select operators
         validator: {function} -- basic function to check if solution is valid or not under some constraints
         maximise: {bool} -- specify kind of optimization problem 
-        currentSolution: {Solution} -- current solution managed for current evaluation
         population: [{Solution}] -- population of solution, one for each sub problem
         pfPop: [{Solution}] -- pareto front population
+        weights: [[{float}]] -- random weights used for custom mu sub problems
         callbacks: {[Callback]} -- list of Callback class implementation to do some instructions every number of evaluations and `load` when initializing algorithm
     """
     def __init__(self,
@@ -69,6 +70,7 @@ class MOEAD(Algorithm):
         # by default
         self.numberOfEvaluations = 0
         self.maxEvaluations = 0
+        self.nObjectives = len(_evaluator)
 
         # other parameters
         self.parent = _parent  # parent algorithm if it's sub algorithm
@@ -93,10 +95,25 @@ class MOEAD(Algorithm):
         self.setNeighbors()
 
         weights = []
-        for i in range(self.mu):
-            angle = math.pi / 2 * i / (self.mu - 1)
-            weights.append([math.cos(angle), math.sin(angle)])
+    
+        if self.nObjectives == 2:
+                
+            for i in range(self.mu):
+                angle = math.pi / 2 * i / (self.mu - 1)
+                weights.append([math.cos(angle), math.sin(angle)])
+
+        elif self.nObjectives >= 3:
+
+            # random weights using uniform
+            for i in range(self.mu):
+                w_i = np.random.uniform(0, 1, self.nObjectives)
+                weights.append(w_i / sum(w_i))
+        else:
+            raise ValueError('Unvalid number of objectives')
 
+        
+        self.weights = weights
+        
         self.subProblems = []
 
         for i in range(self.mu):
@@ -114,10 +131,11 @@ class MOEAD(Algorithm):
         self.population = [None for n in range(self.mu)]
         self.pfPop = []
 
+        # ref point based on number of evaluators
         if self.maximise:
-            self.refPoint = [ 0 for _ in range(len(_evaluator)) ]
+            self.refPoint = [ 0 for _ in range(self.nObjectives) ]
         else:
-            self.refPoint = [ sys.float_info.max for _ in range(len(_evaluator)) ]
+            self.refPoint = [ sys.float_info.max for _ in range(self.nObjectives) ]
         
 
     def initRun(self):

+ 10 - 7
macop/operators/policies/UCBPolicy.py

@@ -18,7 +18,7 @@ class UCBPolicy(Policy):
         rewards: {[float]} -- list of summed rewards obtained for each operator
         occurences: {[int]} -- number of use (selected) of each operator
     """
-    def __init__(self, _operators, _C=1000.):
+    def __init__(self, _operators, _C=100.):
         self.operators = _operators
         self.rewards = [0. for o in self.operators]
         self.occurences = [0 for o in self.operators]
@@ -72,13 +72,16 @@ class UCBPolicy(Policy):
         # compute fitness of new solution
         newSolution.evaluate(self.algo.evaluator)
 
-        # compute reward
-        difference = newSolution.fitness() - _solution.fitness()
-        reward = difference if difference > 0 else 0.
+        # compute fitness improvment rate
+        if self.algo.maximise:
+            fir =  (newSolution.fitness() - _solution.fitness()) / _solution.fitness()
+        else:
+            fir = (_solution.fitness() - newSolution.fitness()) / _solution.fitness()
 
-        operator_index = self.operators.index(operator)
-        self.rewards[operator_index] += reward
-        self.occurences[operator_index] += 1
+        if fir > 0:
+            operator_index = self.operators.index(operator)
+            self.rewards[operator_index] += fir
+            self.occurences[operator_index] += 1
 
         logging.info("---- Obtaining %s" % (_solution))